Requesting read receipt (MDN)

You can also read how to:

Message headers are commonly used to store various e-mail metadata such as spam filtering score, mail agent name or other flags.

Several headers can be used to request a delivery receipt for the message. This will make the recipient’s mail client (such as Outlook) notify the sender if the user have read the message.

Please note that the reply is not mandatory – not all e-mail clients support it and those who do usually ask the user for a permission before sending the receipt. Even though, it is still a useful feature.

As usual different mail clients honor different headers: ‘Disposition-Notification-To’, ‘Return-Receipt-To’ and ‘X-Confirm-Reading-To’.

Mail.dll .NET email client provides you a single method for that: RequestReadReceipt() that copies all addresses from “From” collection or “Reply-To” collection to all those headers.

Read receipt requests may not always be honored. There are several reasons for that:

  • A mail client may not recognize the special Disposition-Notification-To header.
  • A mail client may not implement that functionality.
  • The end user may have that functionality turned off.
  • The end user may optionally not choose to send one for your particular email.

The following code sends email, that requests read receipt:

// C# version:

MailBuilder builder = new MailBuilder();
builder.From.Add(new MailBox("from@example.com", "Alice"));
builder.To.Add(new MailBox("to@example.com", "Bob"));
builder.Subject = "Please let me know if you like it";
builder.Html = "<html>....</html>";

builder.RequestReadReceipt();

IMail email = builder.Create();


using(Smtp smtp = new Smtp())
{
    smtp.Connect("smtp.server.com");  // or ConnectSSL for SSL
    smtp.UseBestLogin("user", "password");
 
    smtp.SendMessage(email);                     
 
    smtp.Close();   
}  

' VB.NET version:

Dim builder As New MailBuilder()
builder.From.Add(New MailBox("from@example.com", "Alice"))
builder.[To].Add(New MailBox("to@example.com", "Bob"))
builder.Subject = "Please let me know if you like it"
builder.Html= "<html>....</html>"

builder.RequestReadReceipt()

Using smtp As New Smtp()
    smtp.Connect("smtp.server.com")	' or ConnectSSL for SSL
    smtp.UseBestLogin("user", "password")

    smtp.SendMessage(email)

    smtp.Close()
End Using

Fluent interface equivalents:

// C# version:

using Fluent = Limilabs.Mail.Fluent;

IMail email = Fluent.Mail.Html("<html>....</html>")
    .Subject("Please let me know if you like it")
    .From("from@example.com")
    .To("to@example.com")
    .RequestReadReceipt()
    .Create();

using(Smtp smtp = new Smtp())
{
    smtp.Connect("smtp.server.com");  // or ConnectSSL for SSL
    smtp.UseBestLogin("user", "password");
 
    smtp.SendMessage(email);                     
 
    smtp.Close();   
}  

and as usual VB.NET code:

' VB.NET version:

Imports Fluent = Limilabs.Mail.Fluent;

Dim email As IMail = Fluent.Mail.Html("<html>....</html>") _
    .Subject("Please let me know if you like it") _
    .From("from@example.com") _
    .[To]("to@example.com") _
    .RequestReadReceipt() _
    .Create()

Using smtp As New Smtp()
    smtp.Connect("smtp.server.com")	' or ConnectSSL for SSL
    smtp.UseBestLogin("user", "password")

    smtp.SendMessage(email)

    smtp.Close()
End Using

High priority emails

There are several different email headers that make email high priority.

Most correct is Priority header, but also Importance is used.
Outlook uses X-Priority header.

Mail.dll email library offers simple solution of this problem: PriorityHigh() method.

The following code sends high priority email, that has all mentioned above headers set accordingly:

// C# version:
MailBuilder builder = new MailBuilder();
builder.Subject = "This is important";
builder.Html = "<html>....</html>";
builder.From.Add(new MailBox("alice@mail.com", "Alice"));
builder.To.Add(new MailBox("bob@mail.com", "Bob"));

builder.PriorityHigh();

IMail email = builder.Create();

using (Smtp client = new Smtp())
{
    client.ConnectSSL("smtp.example.org");
    client.UseBestLogin("alice@example.org", "password");
    client.SendMessage(email);
    client.Close();
}

and as usual VB.NET code:

' VB.NET version:

Dim builder As MailBuilder = New MailBuilder()
builder.Subject = "This is important"
builder.Html = "<html>....</html>"
builder.From.Add(New MailBox("alice@mail.com", "Alice"))
builder.[To].Add(New MailBox("bob@mail.com", "Bob"))

builder.PriorityHigh()

Dim email As IMail = builder.Create()

Using client As Smtp = New Smtp()
    client.ConnectSSL("smtp.example.org")
    client.UseBestLogin("alice@example.org", "password")
    client.SendMessage(email)
    client.Close()
End Using

Using fluent interface:

// C# version:

using Fluent = Limilabs.Mail.Fluent;

Fluent.Mail.Html("<html>....</html>")
    .Subject("This is important")
    .To("to@example.com")
    .From("from@example.com")
    .PriorityHigh()
    .UsingNewSmtp()
    .Server("smtp.example.com")
    .WithCredentials("user", "password")
    .WithSSL()
    .Send();
' VB.NET version:

Imports Fluent = Limilabs.Mail.Fluent;

Fluent.Mail.Html("<html>....</html>") _
    .Subject("This is important") _
    .To("to@example.com") _
    .From("from@example.com") _
    .PriorityHigh() _
    .UsingNewSmtp() _
    .Server("smtp.example.com") _
    .WithCredentials("user", "password") _
    .WithSSL() _
    .Send()

PriorityLow() method is also available.

It’s also really easy to check the email’s priority with GetGenericPriority.
GetGenericPriority checks Priority, Importance and X-Priority headers.

// C# version:

IMail email = new MailBuilder()
    .CreateFromEml(imap.GetMessageByUID(uid))

GenericPriority priority = email.GetGenericPriority();
if (priority == GenericPriority.High)
{
    // Your code goes here
}

' VB.NET version:

Dim email As IMail = New MailBuilder() _
    .CreateFromEml(imap.GetMessageByUID(uid))

Dim priority As GenericPriority = email.GetGenericPriority()

If priority = GenericPriority.High Then
    ' Your code goes here
End If

Get email information from IMAP (fast)

Email messages include attachments (encoded as text using Base64 or Quoted-Printable encoding). This causes emails to became quite big and download process slow. In many cases you don’t require to download entire message (including attachments) to process it. Think about displaying only a list of messages that are in the INBOX folder or only deciding if you should process a message.

When using IMAP protocol, Mail.dll IMAP client offers extremely fast way of downloading such email information. This include message envelope information (Subject, Date, From and To recipients) and message structure (Attachment count, attachment names and sizes).

In the following sample, we’ll download those data for all unseen messages that are in the INBOX folder:

//  C#

using (Imap imap = new Imap())
{
    imap.Connect("imap.example.com");   // or ConnectSSL
    imap.UseBestLogin("user", "password");

    imap.SelectInbox();
    List<long> uids = imap.Search(Flag.Unseen);
    List<MessageInfo> infos = imap.GetMessageInfoByUID(uids);

    foreach (MessageInfo info in infos)
    {
        Console.WriteLine("Subject: " + info.Envelope.Subject);
        Console.WriteLine("From: " + info.Envelope.From);
        Console.WriteLine("To: " + info.Envelope.To);
        foreach (MimeStructure attachment in info.BodyStructure.Attachments)
        {
            Console.WriteLine("  Attachment: '{0}' ({1} bytes)",
                attachment.SafeFileName,
                attachment.Size);
        }
        Console.WriteLine();
    }
    imap.Close();
}
' VB.NET

Using imap As New Imap()
	imap.Connect("imap.example.com")    ' or ConnectSSL
	imap.UseBestLogin("user", "password")

	imap.SelectInbox()
	Dim uids As List(Of Long) = imap.Search(Flag.Unseen)
	Dim infos As List(Of MessageInfo) = imap.GetMessageInfoByUID(uids)

	For Each info As MessageInfo In infos
		Console.WriteLine("Subject: " + info.Envelope.Subject)
		Console.WriteLine("From: " + info.Envelope.From)
		Console.WriteLine("To: " + info.Envelope.[To])
		For Each attachment As MimeStructure In info.BodyStructure.Attachments
			Console.WriteLine("  Attachment: '{0}' ({1} bytes)", _
				attachment.SafeFileName,  _
				attachment.Size)
		Next
		Console.WriteLine()
	Next
	imap.Close()
End Using

The result of the code above is list of all unread emails with attachments:


Subject: Contract
From: Alice <alice@company.com>
To: Bob <bob@company.com>
Attachment: 'document1.doc' (42738 bytes)
Attachment: '.NET.pdf' (1243 bytes)

Envelope object contains following information:

  • Subject
  • Date
  • From
  • Sender
  • To
  • Cc
  • InReplyTo
  • Message id
  • Message size
  • Gmail thread id (if available)
  • Gmail message id (if available)

BodyStructure contains information about:

  • All attachments including their size, name, content type
  • HTML message part
  • Pain text message part

It’s really fast. Downloading 1000 email information takes approximately 13 seconds.

You can read more about downloading email parts (single attachment) here

You can download Mail.dll .NET IMAP library here.

Default ports for email protocols

Here’s the list of three most common email protocols and their default ports:

ProtocolPlain textSSL/TLS
IMAP *143993
POP3 *110995
SMTP587 or 25 **465

* Check the differences between POP3 and IMAP

** SMTP (and port 25) was originally designed for email transfer, not submission. So yet another port (587) was defined for message submission.

Establishing connection using default port is easy:

// C#

client.Connect("mail.example.com");

' VB.NET

client.Connect("mail.example.com")

If you need to specify different port, just use overloaded version of the Connect method:

// C#

client.Connect("mail.example.com", 999);

' VB.NET

client.Connect("mail.example.com", 999)

Implicit SSL/TLS mode

Establishing connection encrypted with SSL/TLS using default port is easy:

// C#

client.ConnectSSL("mail.example.com");

' VB.NET

client.ConnectSSL("mail.example.com")

If you need to specify different port, just use overloaded version of ConnectSSL method:

// C#

client.ConnectSSL("mail.example.com", 999);

' VB.NET

client.ConnectSSL("mail.example.com", 999)

Explicit SSL/TLS mode (aka TLS)

Sometimes your server might require that you first connect on non SSL/TLS (plain text) port using regular Connect method, and then start SSL/TLS negotiation using STARTTLS (or STLS in case of POP3) command. This is called explicit SSL/TLS mode and sometimes is referred to as TLS:

// C#

client.Connect("mail.example.com");
client.StartTLS();

' VB.NET

client.Connect("mail.example.com")
client.StartTLS()

Here you can find more details on SSL vs TLS vs STARTTLS and STLS.

Self-signed certificates

Remember that you can ignore SSL/TLS certificate errors (for example when your server uses self-signed certificates) using ServerCertificateValidate event:

// C#

client.ServerCertificateValidate +=
    (sender, e) => { e.IsValid = true; };

' VB.NET

AddHandler client.ServerCertificateValidate, AddressOf Validate

Private Sub Validate(ByVal sender As Object, ByVal e As ServerCertificateValidateEventArgs)
    e.IsValid = True
End Sub

Get shared folders from IMAP

This article describes how to get shared folder list from your IMAP server using Mail.dll IMAP component for .NET.

Shared folder names usually start with ‘#’ character. This is not a rule, but it’s very common.

IMAP server when asked for all folder list should return also shared folders.

Here’s the unit test code that shows this:

List<folderInfo> allFolders = client.GetFolders();
CollectionAssert.Contains(allFolders.Select(x => x.Name), "#Public.PublicFolder1");
CollectionAssert.Contains(allFolders.Select(x => x.Name), "#Public");

If you want to list only shared folders you’ll need to use IMAP’s NAMESPACE command. Imap.GetNamespaces() method returns Namespaces class which contains information about personal, shared and other users namespaces:

// C# version

using (Imap client = new Imap())
{
    client.Connect("server");
    client.Login("user", "password");

    Namespaces namespaces = client.GetNamespaces();

    // List shared folders in all shared namespaces
    foreach (NamespaceInfo space in namespaces.Shared)
    {
        List<folderInfo> sharedFolders = client.GetFolders(space.Name);
        sharedFolders.ForEach(x => Console.WriteLine(x.Name));
    }

    client.Close();
}
' VB.NET version

Using client As New Imap()
	client.Connect("server")
	client.Login("user", "password")

	Dim namespaces As Namespaces = client.GetNamespaces()

	' List shared folders in all shared namespaces
	For Each space As NamespaceInfo In namespaces.[Shared]
		Dim sharedFolders As List(Of FolderInfo) = client.GetFolders(space.Name)
		sharedFolders.ForEach(Function(x) Console.WriteLine(x.Name))
	Next

	client.Close()
End Using

The above code lists all public folders available for the currently logged-in user:

#Public.PublicFolder1
#Public.PublicFolder2
#Public

Please note that server will not let you select some folders. In the example above the user can not select ‘#Public’ folder. You can use FolderInfo.CanSelect property to check if the user is allowed to select the folder.

You can download Mail.dll IMAP library for .NET here