Processing a read receipt (MDN)

You can also read how to:

In this article we’ll show how to process a read receipt.

Read receipts also known as MDNs or Message Delivery Notifications are used to notify the message sender that some action has happened with their message (it was displayed, processed, deleted)

All MDNs for a received message are available through IMail.ReadReceipts property.

// C#

var eml = imap.GetMessageByUID(uid);
IMail email = new MailBuilder().CreateFromEml(eml);
MimeMessageDispositionNotification mdn = email.ReadReceipts[0];

string finalRecipient = mdn.FinalRecipient; 
      // recipient@example.com

DispositonActionMode actionmode = mdn.ActionMode; 
      // e.g. DispositonActionMode.ManualAction

DispositonSendingMode sendingMode = mdn.SendingMode; 
      // e.g. DispositonSendingMode.SentManually

string originalMessageID= mdn.OriginalMessageID; 
      // e.g. "message-id@original.com"

DispositonType dispositionType = mdn.Type; 
      // e.g. DispositonType.Displayed, DispositonType.Deleted
' VB.NET

Dim eml = imap.GetMessageByUID(uid)
Dim email As IMail = New MailBuilder().CreateFromEml(eml)
Dim mdn As MimeMessageDispositionNotification = email.ReadReceipts(0)

Dim finalRecipient As String = mdn.FinalRecipient 
     ' recipient@example.com

Dim actionmode As DispositonActionMode = mdn.ActionMode 
      ' e.g. DispositonActionMode.ManualAction

Dim sendingMode As DispositonSendingMode = mdn.SendingMode 
      ' e.g. DispositonSendingMode.SentManually

Dim originalMessageID As String = mdn.OriginalMessageID 
      ' e.g. "message-id@original.com"

Dim dispositionType As DispositonType = mdn.Type 
      ' e.g. DispositonType.Displayed, DispositonType.Deleted

Gmail’s SPECIAL-USE capability is broken

Recently it came to my attention that Gmail’s XLIST command is deprecated.

XLIST is a custom Gmail command that retrieves information about the folder purpose, without the need of knowing the folders name. It works by returning additional flags, such as \Spam, for folders of a known purpose (e.g. “[Gmail]/Spam”)

More standardized feature, deigned for the same purpose, is SPECIAL-USE extension.

Both XLIST and SPECIAL-USE are supported by Mail.dll. You can use CommonFolders class to get folder by its function.

On this site Gmail claims that:

Gmail supports the IMAP LIST Extension for Special-Use Mailboxes [RFC 6154], which provides new attributes for special folders.

And in the next paragraph:

The Gmail-specific XLIST command is deprecated in favor of the IMAP Special-Use List Standard [RFC 6154].

The problem is that their Special-Use support is seriously broken.

Broken CAPABILITY response

RFC 6154 clearly states:

Supporting implementations MUST include the “SPECIAL-USE” capability string in response to an IMAP CAPABILITY command.

Here’s the Gmail’s response to CAPABILITY command:

Initial:

S: * OK Gimap ready for requests from 89.67.10.122 z2if15323304eeo.17
C: f3a21e43c6c648e8 CAPABILITY
S: * CAPABILITY IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA ID XLIST CHILDREN X-GM-EXT-1 XYZZY SASL-IR AUTH=XOAUTH AUTH=XOAUTH2

After logging in:

 C: 77776ad235694614 CAPABILITY
 S: * CAPABILITY IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA ID XLIST CHILDREN X-GM-EXT-1 UIDPLUS COMPRESS=DEFLATE ENABLE MOVE
 S: 77776ad235694614 OK Success

There is no “SPECIAL-USE” capability returned. What is funny deprecated XLIST is still there.

Broken LIST response

RFC 6154 clearly states:

If the client specifies the “SPECIAL-USE” return option, the LIST command MUST return the new special-use attributes on those mailboxes that have them set.

Gmail server fails to parse such command:

C: 7ab9a06868fa4717 LIST "" * RETURN (SPECIAL-USE)
S: 7ab9a06868fa4717 BAD Could not parse command

Correct LIST response?

It seems however that regular LIST response contains flags defined in RFC 6154 (\All, \Flagged, \Junk and so on):

* LIST (\HasNoChildren) "/" "INBOX"
S: * LIST (\Noselect \HasChildren) "/" "[Gmail]"
S: * LIST (\HasChildren \HasNoChildren \All) "/" "[Gmail]/All Mail"
S: * LIST (\HasNoChildren \Drafts) "/" "[Gmail]/Drafts"
S: * LIST (\HasChildren \HasNoChildren \Important) "/" "[Gmail]/Important"
S: * LIST (\HasChildren \HasNoChildren \Sent) "/" "[Gmail]/Sent Mail"
S: * LIST (\HasChildren \HasNoChildren \Junk) "/" "[Gmail]/Spam"
S: * LIST (\HasChildren \HasNoChildren \Flagged) "/" "[Gmail]/Starred"
S: * LIST (\HasChildren \HasNoChildren \Trash) "/" "[Gmail]/Trash"

The response follows the Special-Use standard with an additional \Important attribute added for Gmail’s Priority Inbox

Why not X-Important?

HTML formatted content in the description field of an iCalendar

By default, the iCalendar specification allows only plain text to be used in the description of an Event object.

X-ALT-DESC header

However Outlook can recognize HTML formatted content. This is supported using an additional field in the Event object called “X-ALT-DESC”, rather than the existing field:

DESCRIPTION:Reminder
X-ALT-DESC;FMTTYPE=text/html:<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 3.2//E
 N""><HTML><BODY>\nhtml goes here\n</BODY></HTML>

Using Mail.dll you can set this field with no extra hassle:

// C#

Appointment appointment = new Appointment();
Event e = appointment.AddEvent();
e.XAltDescription = @"<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 3.2//EN""><HTML><BODY>
html goes here
</BODY></HTML>";
' VB.NET

Dim appointment As New Appointment()
Dim e As [Event] = appointment.AddEvent()
e.XAltDescription = "<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 3.2//EN""><HTML><BODY>" _ 
 & vbCr & vbLf & "html goes here"  _ 
 & vbCr & vbLf & "</BODY></HTML>"

Adding custom headers

This is also good sample to show how to add a custom header to any PDI object:

// C#

Appointment appointment = new Appointment();
Event e = appointment.AddEvent();

const string html = @"<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 3.2//EN""><HTML><BODY>
html goes here
</BODY></HTML>";

PdiHeader header = new PdiHeader("X-ALT-DESC", html);
header.KeyParameters.Add(new KeyValues("FMTTYPE", "text/html"));
e.AddCustomHeader(header);
' VB.NET

Dim appointment As New Appointment()
Dim e As [Event] = appointment.AddEvent()

Const  html As String = "<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 3.2//EN""><HTML><BODY>" _
 & vbCr & vbLf & "html goes here" _
 & vbCr & vbLf & "</BODY></HTML>"

Dim header As New PdiHeader("X-ALT-DESC", html)
header.KeyParameters.Add(New KeyValues("FMTTYPE", "text/html"))
e.AddCustomHeader(header)

ALTREP parameter

It is worth mentioning that RFC defines a way of specifying HTML content. The problem is that, it requires additional source (like email attachment or http address). Address of this resource, for example using “cid:” is set using ALTREP DESCRIPTION header:

DESCRIPTION;ALTREP="CID:part3.msg.970415T083000@example.com":
 Project XYZ Review Meeting will include the following agenda
   items: (a) Market Overview\, (b) Finances\, (c) Project Man
 agement

Mail.dll supports this feature also.

First we’ll define MIME object containing html data. Note that we are setting ContentId property.

// C#

MimeText html = new MimeFactory().CreateMimeText();
html.ContentType = ContentType.TextHtml;
html.Text = "<html><body>Html</body></html>";
html.ContentId = "part3.msg.970415T083000@example.com";
' VB.NET

Dim html As MimeText = New MimeFactory().CreateMimeText()
html.ContentType = ContentType.TextHtml
html.Text = "<html><body>Html</body></html>"
html.ContentId = "part3.msg.970415T083000@example.com"

Now we’ll create event:

// C#

Appointment appointment = new Appointment();
Event e = appointment.AddEvent();

e.Description = "Project XYZ Review Meeting will include the following agenda items: (a) Market Overview, (b) Finances, (c) Project Management";
e.DescriptionAltRep = "CID:" + html.ContentId;
' VB.NET

Dim appointment As New Appointment()
Dim e As [Event] = appointment.AddEvent()

e.Description = "Project XYZ Review Meeting will include the following agenda items: (a) Market Overview, (b) Finances, (c) Project Management"
e.DescriptionAltRep = "CID:" + html.ContentId

Finally we need to create an email with the event and html data:

// C#

MailBuilder builder = new MailBuilder();
builder.AddAttachment(html);
builder.AddAppointment(appointment);
IMail email = builder.Create();
' VB.NET

Dim builder As New MailBuilder()
builder.AddAttachment(html)
builder.AddAppointment(appointment)
Dim email As IMail = builder.Create()

How to shorten Connect timeout

Connect and BeginConnect methods take quite a long time to timeout, when you use incorrect server address. It usually takes almost 20 seconds for those methods to decide that connection is impossible. Setting SendTimeout/ReceiveTimeout doesn’t influence this in any way.

Not only Imap, Pop3, and Smtp classes suffer from this problem, it’s the same for regular Socket class.

There is a solution however, using BeginConnect and simply waiting for specified amount of time (AsyncWaitHandle.WaitOne) without calling EndConnect (which blocks):

// C#

using(Imap imap =new Imap())
{
    IAsyncResult result = imap.BeginConnectSSL("imap.example.com");

    // 5 seconds timeout
    bool success = result.AsyncWaitHandle.WaitOne(5000, true);

    if (success == false)
    {
        throw new Exception("Failed to connect server.");
    }
    imap.EndConnect(result);

    //...

    imap.Close();
}
' VB.NET

Using imap As New Imap()
	Dim result As IAsyncResult = imap.BeginConnectSSL("imap.example.com")

	' 5 seconds timeout
	Dim success As Boolean = result.AsyncWaitHandle.WaitOne(5000, True)

	If success = False Then
		Throw New Exception("Failed to connect server.")
	End If
	imap.EndConnect(result)

	'...

	imap.Close()
End Using

System.Net.Mail vs Mail.dll

In this article we’ll try to describe advantages of Mail.dll over standard .NET System.Net.Mail namespace.

The fundamental difference is that with System.Net.Mail you can’t receive emails. System.Net.Mail does not have support for POP3 and IMAP protocols – two fundamental protocols for email retrieval, also .NET does not have any classes that would parse received email.

System.Net.Mail is great for sending simple emails, but Mail.dll gives you much more, even in terms of sending. You get appointments (iCal) and vCard support, you can send S/MIME signed and encrypted emails (if you plan to use EDI). It gives you easy to use template engine and VERP support out-of-the-box.

Here’s the comparison chart:

System.Net.Mail Mail.dll component
Send emails yes yes
SMTP protocol support (over SSL/TLS) yes yes
Send emails using VERP no yes
Send S/MIME encrypted emails no yes
Send S/MIME signed emails no yes
Send S/MIME signed emails (detached) no yes
Send DKIM (Domain Key Identified Mail) no yes
Templates support no yes
Receive emails no yes
IMAP protocol support (over SSL/TLS) no yes
POP3 protocol support (over SSL/TLS) no yes
Retrieve and parse emails no yes
Extract HTML, plain text, images no yes
Attachment retrieval no yes
Send and retrieve iCalendar appointments no yes
Send and retrieve vCards no yes
OAuth 1.1a/2.0 support no yes
Spam filter no yes
Bounce handling no yes
Convert HTML only emails to plain text no yes

If you need help or more information about any of these features visit Mail.dll samples.