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