Sample code for 30+ languages & platforms
Unicode 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 Unicode C Downloads

Unicode C
#include <C_CkEmailW.h>
#include <C_CkHtmlToTextW.h>
#include <C_CkJsonObjectW.h>
#include <C_CkMimeW.h>

void ChilkatSample(void)
    {
    BOOL success;
    HCkEmailW email;
    HCkHtmlToTextW h2t;
    HCkJsonObjectW jsonDsnInfo;
    const wchar_t *headersText;
    HCkMimeW mime;
    HCkEmailW origEmail;

    success = FALSE;

    // 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.

    email = CkEmailW_Create();
    success = CkEmailW_LoadEml(email,L"qa_data/eml/deliveryStatus.eml");
    // success = email.LoadEml("qa_data/eml/sample_multipart_report.eml");
    if (success == FALSE) {
        wprintf(L"%s\n",CkEmailW_lastErrorText(email));
        CkEmailW_Dispose(email);
        return;
    }

    // Verify this is a multipart/report email..
    if (CkEmailW_IsMultipartReport(email) == FALSE) {
        wprintf(L"Not a multipart/report email.\n");
        CkEmailW_Dispose(email);
        return;
    }

    // Get the body that is to be displayed to a human in an email program (such as Outlook).
    if (CkEmailW_HasPlainTextBody(email) == TRUE) {
        wprintf(L"Plain text body:\n");
        // println email.GetPlainTextBody();
    }
    else {
        if (CkEmailW_HasHtmlBody(email) == TRUE) {
            // Convert HTML to plain-text..
            h2t = CkHtmlToTextW_Create();
            wprintf(L"HTML body converted to plain-text:\n");
            wprintf(L"%s\n",CkHtmlToTextW_toText(h2t,CkEmailW_getHtmlBody(email)));
        }
        else {
            wprintf(L"Has no plain-text or HTML body...\n");
        }

    }

    wprintf(L"---------------------------------\n");

    // Now get information from the message/delivery-status part (or the message/disposition-notification part)
    wprintf(L"--- Delivery Status Information:\n");
    wprintf(L"Status: %s\n",CkEmailW_getDeliveryStatusInfo(email,L"Status"));
    wprintf(L"Action: %s\n",CkEmailW_getDeliveryStatusInfo(email,L"Action"));
    wprintf(L"Reporting-MTA: %s\n",CkEmailW_getDeliveryStatusInfo(email,L"Reporting-MTA"));

    jsonDsnInfo = CkJsonObjectW_Create();
    CkEmailW_GetDsnInfo(email,jsonDsnInfo);
    CkJsonObjectW_putEmitCompact(jsonDsnInfo,FALSE);
    wprintf(L"%s\n",CkJsonObjectW_emit(jsonDsnInfo));

    wprintf(L"---------------------------------\n");

    // If the multipart/report contains a text/rfc822-headers, it can be retrieved like this:
    headersText = CkEmailW_getNthTextPartOfType(email,0,L"text/rfc822-headers",FALSE,FALSE);
    if (CkEmailW_getLastMethodSuccess(email) == TRUE) {
        wprintf(L"The text/rfc822-headers part exists..\n");
        wprintf(L"\n");
        wprintf(L"%s\n",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.
        mime = CkMimeW_Create();
        CkMimeW_LoadMime(mime,headersText);

        // Do whatever you want.. 
        // For example, look at the "To" header.
        wprintf(L"MIME To header:\n");
        wprintf(L"%s\n",CkMimeW_getHeaderField(mime,L"To"));
    }

    wprintf(L"---------------------------------\n");

    // 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 (CkEmailW_getNumAttachedMessages(email) > 0) {
        // Get the 1st attachment message (assume we don't have more than one attached message)
        origEmail = CkEmailW_Create();
        success = CkEmailW_GetAttachedEmail(email,0,origEmail);
        if (success == TRUE) {
            wprintf(L"Attached message subject: %s\n",CkEmailW_subject(origEmail));
            // Do whatever else you want..
        }

    }



    CkEmailW_Dispose(email);
    CkHtmlToTextW_Dispose(h2t);
    CkJsonObjectW_Dispose(jsonDsnInfo);
    CkMimeW_Dispose(mime);
    CkEmailW_Dispose(origEmail);

    }