Sample code for 30+ languages & platforms
Objective-C

Processing a multipart/report Delivery Status Notification (Bounce Notification)

See more Email Object Examples

This example discusses the format of Delivery Status Notification emails and how to process them.

Chilkat Objective-C Downloads

Objective-C
#import <CkoEmail.h>
#import <CkoHtmlToText.h>
#import <CkoJsonObject.h>
#import <NSString.h>
#import <CkoMime.h>

BOOL success = NO;

// Here are the MIME structures, showing the content-type and nesting of the MIME parts of three sample
// multipart/report DSN (Delivery Status Notification) emails.

// This 1st sample includes a "text/rfc822-headers" MIME subpart. 

// multipart/report
//     text/plain
//     message/delivery-status
//     text/rfc822-headers
//     message/rfc822

// This 2nd sample lacks the text/rfc-headers part, but the "report type" information
// is offered in both plain-text and HTML formats.

// multipart/report
//     multipart/alternative
//         text/plain
//         text/html
//     message/delivery-status
//     message/rfc822

// ----------------------------------------------------------------------------------------------------

// A multipart/report MIME delivery status notification follows a specific format defined by the Internet Engineering Task Force (IETF) in RFC 3464, 
// which outlines the "An Extensible Message Format for Delivery Status Notifications" standard. The format consists of multiple parts within a 
// multipart/report structure. Here's an overview of the main parts involved:
// 
// The 1st sub-part under multipart/report is the body of the DSN to be displayed by the email client (such as Outlook).
// It can be a simple text/plain body, or it can be multipart/alternative and offer a few alternative format, typically plain-text and HTML.
// HTML is best for viewing a program such as Outlook. 
// This part of the multipart/report is not structured for programmatic processing.  It's meant to be viewed by a human.

// --------------------
// The "message/delivery-status" part within a multipart/report MIME structure follows a specific format to provide details about the delivery status
// of an email message.  Here's an overview of the format and the key components within the "message/delivery-status" part:
// 
// (1) Content-Type and Reporting-UA:
// The "message/delivery-status" part begins with the Content-Type header specifying "message/delivery-status". 
// It may also include a Reporting-UA (Reporting User Agent) field that identifies the software or system generating the delivery status notification.
// 
// For example:
// 
// Content-Type: message/delivery-status
// Reporting-UA: Example Mail System 1.0
// 
// (2) Fields:
// The "message/delivery-status" part contains a series of fields, each providing specific information about the delivery status. 
// These fields are structured as key-value pairs.
// 
// Common fields include:
// 
//     Final-Recipient: Specifies the recipient for whom the delivery status is being reported.
//     Action: Describes the action performed by the reporting system (e.g., failed, delivered, delayed, etc.).
//     Status: Indicates the status code or reason for the delivery attempt result.
//     Remote-MTA: Specifies the host or system that attempted the delivery.
//     Diagnostic-Code: Provides additional diagnostic information, such as error codes or explanations.
// 
// For example:
// 
// Final-Recipient: rfc822; john.doe@example.com
// Action: failed
// Status: 5.1.1
// Remote-MTA: smtp.example.com
// Diagnostic-Code: smtp; 550 Requested action not taken: mailbox unavailable
// 
// (3) Additional Fields:
// Additional fields may be included in the "message/delivery-status" part to provide further information about the delivery attempt. 
// These fields can vary depending on the implementation or specific needs of the system generating the delivery status notification.
// For example:
// 
// X-Spam-Flag: YES
// X-Spam-Score: 7.2
// 
// Note: The specific fields and their values within the "message/delivery-status" part can vary depending on the implementation
// or the email server/application generating the delivery status notification. The structure described above represents the standard format
// as defined in RFC 3464, but variations may exist in practice.

// --------------------

// The "text/rfc822-headers" MIME part, if included, contains the headers of the original email message
// for which the delivery status notification is being generated. It provides a subset of the headers from the original message,
// typically excluding the message body and attachments.
// 
// The purpose of including the "text/rfc822-headers" part is to provide contextual information about the original message.
// It allows the recipient to review the original headers, such as the subject, sender, recipients, date, and other relevant information,
// in order to understand the context and details of the email message for which the delivery status notification is being generated.
// 
// Note that the specific headers included in the "text/rfc822-headers" part can vary based on the implementation or requirements
// of the system generating the delivery status notification.

// --------------------

// If the message/rfc822 part is present, it contains the full MIME of the email that was not delivered.
// In Chilkat terminology, this is an attached message.

// OK, let's write code to process a multipart/report email.

CkoEmail *email = [[CkoEmail alloc] init];
success = [email LoadEml: @"qa_data/eml/deliveryStatus.eml"];
// success = email.LoadEml("qa_data/eml/sample_multipart_report.eml");
if (success == NO) {
    NSLog(@"%@",email.LastErrorText);
    return;
}

// Verify this is a multipart/report email..
if ([email IsMultipartReport] == NO) {
    NSLog(@"%@",@"Not a multipart/report email.");
    return;
}

// Get the body that is to be displayed to a human in an email program (such as Outlook).
if ([email HasPlainTextBody] == YES) {
    NSLog(@"%@",@"Plain text body:");
    // println email.GetPlainTextBody();
}
else {
    if ([email HasHtmlBody] == YES) {
        // Convert HTML to plain-text..
        CkoHtmlToText *h2t = [[CkoHtmlToText alloc] init];
        NSLog(@"%@",@"HTML body converted to plain-text:");
        NSLog(@"%@",[h2t ToText: [email GetHtmlBody]]);
    }
    else {
        NSLog(@"%@",@"Has no plain-text or HTML body...");
    }

}

NSLog(@"%@",@"---------------------------------");

// Now get information from the message/delivery-status part (or the message/disposition-notification part)
NSLog(@"%@",@"--- Delivery Status Information:");
NSLog(@"%@%@",@"Status: ",[email GetDeliveryStatusInfo: @"Status"]);
NSLog(@"%@%@",@"Action: ",[email GetDeliveryStatusInfo: @"Action"]);
NSLog(@"%@%@",@"Reporting-MTA: ",[email GetDeliveryStatusInfo: @"Reporting-MTA"]);

CkoJsonObject *jsonDsnInfo = [[CkoJsonObject alloc] init];
[email GetDsnInfo: jsonDsnInfo];
jsonDsnInfo.EmitCompact = NO;
NSLog(@"%@",[jsonDsnInfo Emit]);

NSLog(@"%@",@"---------------------------------");

// If the multipart/report contains a text/rfc822-headers, it can be retrieved like this:
NSString *headersText = [email GetNthTextPartOfType: [NSNumber numberWithInt: 0] contentType: @"text/rfc822-headers" inlineOnly: NO excludeAttachments: NO];
if (email.LastMethodSuccess == YES) {
    NSLog(@"%@",@"The text/rfc822-headers part exists..");
    NSLog(@"%@",@"");
    NSLog(@"%@",headersText);

    // If you wish to process the headers, you can load them into a MIME object and use the Chilkat MIME functionality to examine the headers.
    CkoMime *mime = [[CkoMime alloc] init];
    [mime LoadMime: headersText];

    // Do whatever you want.. 
    // For example, look at the "To" header.
    NSLog(@"%@",@"MIME To header:");
    NSLog(@"%@",[mime GetHeaderField: @"To"]);
}

NSLog(@"%@",@"---------------------------------");

// Finally, if the original email was attached, you can load it into another Chilkat Email object instance and
// do what you want with it..

if ([email.NumAttachedMessages intValue] > 0) {
    // Get the 1st attachment message (assume we don't have more than one attached message)
    CkoEmail *origEmail = [[CkoEmail alloc] init];
    success = [email GetAttachedEmail: [NSNumber numberWithInt: 0] email: origEmail];
    if (success == YES) {
        NSLog(@"%@%@",@"Attached message subject: ",origEmail.Subject);
        // Do whatever else you want..
    }

}