Sample code for 30+ languages & platforms
Pascal (Lazarus/Delphi)

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 Pascal (Lazarus/Delphi) Downloads

Pascal (Lazarus/Delphi)
program ChilkatDemo;

// Demonstrates using the Chilkat Pascal wrapper via the C bridge DLL.
// Builds as a console application under Lazarus (FPC) or Delphi.

{$IFDEF FPC}
  {$MODE DELPHI}
{$ENDIF}
{$APPTYPE CONSOLE}

uses
  {$IFDEF UNIX}
  cthreads,
  {$ENDIF}
  SysUtils,
  CkDllLoader,
  Chilkat.Mime,
  Chilkat.HtmlToText,
  Chilkat.Email,
  Chilkat.JsonObject;

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

procedure RunDemo;
var
  success: Boolean;
  email: TEmail;
  h2t: THtmlToText;
  jsonDsnInfo: TJsonObject;
  headersText: string;
  mime: TMime;
  origEmail: TEmail;

begin
  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 := TEmail.Create;
  success := email.LoadEml('qa_data/eml/deliveryStatus.eml');
  //  success = email.LoadEml("qa_data/eml/sample_multipart_report.eml");
  if (success = False) then
    begin
      WriteLn(email.LastErrorText);
      Exit;
    end;

  //  Verify this is a multipart/report email..
  if (email.IsMultipartReport() = False) then
    begin
      WriteLn('Not a multipart/report email.');
      Exit;
    end;

  //  Get the body that is to be displayed to a human in an email program (such as Outlook).
  if (email.HasPlainTextBody() = True) then
    begin
      WriteLn('Plain text body:');
      //  println email.GetPlainTextBody();
    end
  else
    begin
      if (email.HasHtmlBody() = True) then
        begin
          //  Convert HTML to plain-text..
          h2t := THtmlToText.Create;
          WriteLn('HTML body converted to plain-text:');
          WriteLn(h2t.ToText(email.GetHtmlBody()));
        end
      else
        begin
          WriteLn('Has no plain-text or HTML body...');
        end;
    end;
  WriteLn('---------------------------------');

  //  Now get information from the message/delivery-status part (or the message/disposition-notification part)
  WriteLn('--- Delivery Status Information:');
  WriteLn('Status: ' + email.GetDeliveryStatusInfo('Status'));
  WriteLn('Action: ' + email.GetDeliveryStatusInfo('Action'));
  WriteLn('Reporting-MTA: ' + email.GetDeliveryStatusInfo('Reporting-MTA'));

  jsonDsnInfo := TJsonObject.Create;
  email.GetDsnInfo(jsonDsnInfo);
  jsonDsnInfo.EmitCompact := False;
  WriteLn(jsonDsnInfo.Emit());

  WriteLn('---------------------------------');

  //  If the multipart/report contains a text/rfc822-headers, it can be retrieved like this:
  headersText := email.GetNthTextPartOfType(0,'text/rfc822-headers',False,False);
  if (email.LastMethodSuccess = True) then
    begin
      WriteLn('The text/rfc822-headers part exists..');
      WriteLn('');
      WriteLn(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 := TMime.Create;
      mime.LoadMime(headersText);

      //  Do whatever you want.. 
      //  For example, look at the "To" header.
      WriteLn('MIME To header:');
      WriteLn(mime.GetHeaderField('To'));
    end;

  WriteLn('---------------------------------');

  //  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 > 0) then
    begin
      //  Get the 1st attachment message (assume we don't have more than one attached message)
      origEmail := TEmail.Create;
      success := email.GetAttachedEmail(0,origEmail);
      if (success = True) then
        begin
          WriteLn('Attached message subject: ' + origEmail.Subject);
          //  Do whatever else you want..
        end;
    end;


  email.Free;
          h2t.Free;
  jsonDsnInfo.Free;
      mime.Free;
      origEmail.Free;

end;

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

begin

  try
    RunDemo;
  except
    on E: Exception do
      WriteLn('Unhandled exception: ', E.ClassName, ': ', E.Message);
  end;

  WriteLn;
  {$IFDEF MSWINDOWS}
  WriteLn('Press Enter to exit...');
  ReadLn;
  {$ENDIF}
end.