How can I handle Delivery Status Notifications (DSNs)?

0 votes
asked Mar 14, 2011 by Rebex KB (8,210 points)
edited Dec 30, 2013

How can I request DSN and how can I parse it?

Applies to: Rebex Secure Mail

2 Answers

0 votes
answered Mar 14, 2011 by Rebex KB (8,210 points)
edited Jul 4, 2012
 
Best answer

A. Requesting notifications

There are several ways to request a receipt or Delivery Status Notification (DSN) to be send back to you:

  1. When an e-mail message can't be delivered, most SMTP servers send a Non-Delivery Report (NDR) to the sender. This contains the message ID to make it possible to pair the report with the original outgoing e-mail, so make sure to set MailMessage.MessageId property.

  2. It is possible to use the Disposition-Notification-To header to request a read-receipt to be sent by the recipient's mail application (check out mail tutorials for more information). To be able to pair the receipt with the original outgoing e-mail, use MailMessage.MessageId property.

  3. You can also request a DSN to be sent back to you by setting the DeliveryStatusNotificationConditions property of the Smtp object to DeliveryStatusNotificationConditions.All, then use the Smtp object to mail a MailMessage for you. If the message is received by a compliant SMTP server, you will get a DSN when the message is delivered to the recipient's mailbox. To be able to pair the notification message with the original outgoing e-mail, use MailMessage.EnvelopeId property.

These methods can be used together for the same message. However, none of the messages is guaranteed, because either the server or the client (or both) may choose to not fulfil your request.

Please note there are two message IDs:

  • One is accessible through MailMessage.MessageId property and is used to track ordinary replies and also automated responses to emails with Disposition-Notification-To header.

  • The other ID is accessible through MailMessage.EnvelopeId property and is used to track replies to (non-)delivery notifications requested using Smtp object's DeliveryStatusNotificationConditions property. You have to set EnvelopeId before sending the message for this to take effect (setting it to the same value as MessageId might be a good idea).


B. Detecting and processing notifications

Parsing DSNs is not integrated in Rebex Secure Mail itself yet, but we have written a simple class that makes this task rather easy, although it only works with fully-downloaded messages. The class parses both the Delivery Status Notifications (DSNs) and Message Disposition Notifications (MDNs) that are functionally similar.

/// <summary>
/// Simple delivery status parser.
/// See RFC1894.
/// </summary>
public class DeliveryStatus
{
    private Dictionary&lt;string, string&gt; _values;

    public string FinalRecipient
    {
        get { return GetValue("final-recipient"); }
    }

    public string Disposition
    {
        get { return GetValue("disposition"); }
    }

    public string Action
    {
        get { return GetValue("actions"); }
    }

    public string Status
    {
        get { return GetValue("status"); }
    }

    public string OriginalMessageId
    {
        get { return GetValue("original-message-id"); }
    }

    public string OriginalEnvelopeId
    {
        get { return GetValue("original-envelope-id"); }
    }

    public string ReportingMailTransferAgent
    {
        get { return GetValue("reporting-mta"); }
    }

    private string GetValue(string name)
    {
        string value;
        if (!_values.TryGetValue(name, out value))
            return null;
        return value;
    }

    public static DeliveryStatus ParseMessage(MailMessage message)
    {
        if (message == null)
            throw new ArgumentNullException("message");

        foreach (Attachment att in message.Attachments)
        {
            switch (att.MediaType)
            {
                case "message/delivery-status":
                case "message/disposition-notification":
                    using (StreamReader reader = new StreamReader(att.GetContentStream()))
                    {
                        return new DeliveryStatus(reader.ReadToEnd());
                    }
            }
        }

        return null;
    }

    public DeliveryStatus(string message)
    {
        if (message == null)
            throw new ArgumentNullException("message");

        _values = new Dictionary&lt;string, string&gt;();

        message = message.Replace("\r", "");

        string[] lines = message.Split('\n');

        for (int i = 0; i &lt; lines.Length; i++)
        {
            string line = lines[i];
            int p = line.IndexOf(':');
            if (p &lt; 0)
                continue;

            string name = line.Substring(0, p).ToLowerInvariant();
            string value = line.Substring(p + 1).Trim();

            _values[name] = value;
        }
    }
}

Using it in custom applications is simple - for example:

MailMessage mail = imap.GetMailMessage(id);
DeliveryStatus dsn = DeliveryStatus.ParseMessage(mail);
if (dsn != null)
{
    // ... the message is an DSN, do something with it
}
else
{
    // ... the message is an ordinary e-mail, do something else with it
}
0 votes
answered Dec 30, 2013 by Rakesh Rai (160 points)
edited Dec 30, 2013

Please let me know how to create a MDN message. i had tried with creating a new email and adding followinf headers to it:-

mess.Headers.Add("Content-Type", "message/disposition-notification");
mess.Headers.Add("Content-Disposition", "inline");
mess.Headers.Add("Content-Transfer-Encoding", "7bit");
mess.Headers.Add("Original-Message-ID", "<--MESSAGEID-->");
mess.Headers.Add("Disposition", "automatic-action/MDN-sent-automatically;processed");
mess.Headers.Add("Final-Recipient", "rfc822;some@domain.com");

Please provide help in this case.

Regards, Rakesh Rai

commented Dec 30, 2013 by Lukas Pokorny (99,010 points)
edited Dec 30, 2013
...