Rebex

Skip to content, Skip to navigation




IMAP Tutorial

Back to tutorial list...

Table of content


# Namespaces and assemblies

There are two assemblies which have to be reference in your project to be able to use all features of Mail for .NET described here. Rebex.Net.Imap.dll is needed for any IMAP operations and contains the Imap class and others in Rebex.Net namespace. Rebex.Mail.dll contains classes that make it possible to read, create and write e-mail messages in MIME format and contains the MailMessage class in Rebex.Mail namespace and a number of classes that represent mail message headers in Rebex.Mime.Headers namespace.

To gain access to all described functionality, reference the two assemblies from your project and import the following namespaces in your source files:

C#

using Rebex.Net;
using Rebex.Mail;
using Rebex.Mime.Headers;

VB.NET

Imports Rebex.Net
Imports Rebex.Mail
Imports Rebex.Mime.Headers

 

back to top...


# IMAP basics - connecting, logging in and disconnecting

Typical IMAP session goes like this:

  • Connect to the IMAP server
  • Login - authenticate with user name and password
  • Work with folders and messages
  • Disconnect

Unlike much simpler POP3 protocol, IMAP is a multi-session protocol that supports multiple folders, also somewhat confusingly called mailboxes. While you are connected and authenticated, you will be informed about new incoming messages, and also about messages deleted or marked by other concurrent sessions using the same account. Luckily, you usually only have to care about most of this if you want to.

And now let's look at some sample code.

C#

using Rebex.Net;
...

Imap client = new Imap();
// connect to server 
client.Connect("imap.example.org");

// authenticate  
client.Login("username", "password");

// work with folders and messages 
... 

// disconnect 
client.Disconnect();

VB.NET

Imports Rebex.Net
...

Dim client As New Imap
'connect to server 
client.Connect("imap.example.org")

'authenticate  
client.Login("username", "password")

'work with folders and messages 
... 

'disconnect 
client.Disconnect()

 

back to top...


# Authenticating to an IMAP server

The IMAP protocol supports several authentication methods. Normally, you just have to supply your credentials to the Login method. The component will automatically choose the best (most secure) authentication method available and log you in.

Additionally, you can retrieve the list of supported authentication methods using the Imap object's GetSupportedAuthenticationMethods method, and specify which one is to be used for login. (Or specify ImapAuthentication.Auto that will do this automatically.)

C#

// create client and connect 
Imap client = new Imap();
client.Connect("imap.example.org");

// let the component choose the best method 
client.Login("username", "password");

// or choose one yourself 
// client.Login("username", "password", ImapAuthentication.Plain); 

VB.NET

'create client and connect 
Dim client As New Imap
client.Connect("imap.example.org")

'let the component choose the best method 
client.Login("username", "password")

'or choose one yourself 
'client.Login("username", "password", ImapAuthentication.Plain) 

 

back to top...


# Authentication using NTLM

By default, the Login method won't try NTLM authentication, because it might not work correctly in some situations. However, if NTLM does work with your server, nothing stops you from using it. Just read the information on Microsoft Exchange in the FAQ first if you use that server.

C#

// create client and connect 
Imap client = new Imap();
client.Connect("imap.example.org");

// authenticate using NTLM 
client.Login("domain\\username", "password", ImapAuthentication.Ntlm);

...

VB.NET

'create client and connect 
Dim client As New Imap
client.Connect("imap.example.org")

'authenticate using NTLM 
client.Login("domain\username", "password", SmtpAuthentication.Ntlm)

...

NTLM also makes it possible to authenticate as the user under whose context your application is running. This makes it possible for the user to log in without the need to specify his or her password.

C#

// create client and connect 
Imap client = new Imap();
client.Connect("imap.example.org");

// authenticate using NTLM 
client.Login(ImapAuthentication.Ntlm);

...

VB.NET

'create client and connect 
Dim client As New Imap
client.Connect("imap.example.org")

' authenticate using NTLM's single-sign-on feature 
client.Login(SmtpAuthentication.Ntlm)

...

 

back to top...


# Working with folders

IMAP supports multiple folders per account. In fact, a complete folder hierarchy might be available. However, to keep things simple, there is one special folder that is available in most IMAP implementations - it is called Inbox and it is the primary mailbox for a user on the IMAP server.

The folder hierarchy resembles a common file system in many ways, but there are several differences. 1) The topmost (root) folder may not contain any messages, but there can be other folders at the topmost level of hierarchy in addition to Inbox. 2) Different hierarchy delimiters may be used for different folders or on different levels of the folder tree. However, in practise, the slash ('/') is used almost everywhere. Other popular delimiters are '\' and '.' (the latter is used by IMAP servers that provide access the USENET newsgroups). 3) There is a concept of currently selected folder, but (unlike a common file system) it is possible to unselect a folder so that no folder is currently selected. In fact, this is the default state of the IMAP session.

C#

// create client, connect and log in 
Imap client = new Imap();
client.Connect("imap.example.org");
client.Login("username", "password");

// retrieve the list of topmost folders 
ImapFolderCollection folders = client.GetFolderList();

// and display it 
foreach (ImapFolder folder in folders)
{
    Console.Write(folder.Name);
    Console.Write(" (delimiter is {0})", folder.Delimiter);
    Console.WriteLine();
}

// retrieve the list of folders under Inbox 
// ImapFolderCollection folders = client.GetFolderList("Inbox"); 

// create a new folder called "Test" at the topmost level 
client.CreateFolder("Test");

// and create a new folder called "Second" under the "Test" folder 
client.CreateFolder("Test/Second");

// rename the "Second" folder 
client.RenameFolder("Test/Second", "Test/Third");

// and delete both folders 
client.DeleteFolder("Test/Third");
client.DeleteFolder("Test");

VB.NET

'create client, connect and log in 
Dim client As New Imap
client.Connect("imap.example.org")
client.Login("username", "password")

'retrieve the list of topmost folders 
Dim folders As ImapFolderCollection = client.GetFolderList()

'and display it 
Dim folder As ImapFolder
For Each folder In folders
    Console.Write(folder.Name)
    Console.Write(" (delimiter is {0})", folder.Delimiter)
    Console.WriteLine()
End If 

'retrieve the list of folders under Inbox 
'Dim folders As ImapFolderCollection = client.GetFolderList("Inbox") 

'create a new folder called "Test" at the topmost level 
client.CreateFolder("Test")

'and create a new folder called "Second" under the "Test" folder 
client.CreateFolder("Test/Second")

'rename the "Second" folder 
client.RenameFolder("Test/Second", "Test/Third")

'and delete both folders 
client.DeleteFolder("Test/Third")
client.DeleteFolder("Test")

 

back to top...


# Current folder

Many IMAP commands operate on messages in the currently selected folder. If no folder is selected, many methods will just refuse to work and throw an exception. These include GetMessageList, GetMessage, Copy, DeleteMessages and in fact all other methods that work with messages with the exception of StoreMessage method that uploads a message into a specified folder and therefore doesn't need a folder to be selected.

To start using these methods, a folder has to be selected using the SelectFolder method. In addition to selecting a folder, this will also assign the CurrentFolder property of the Imap object to an instance of ImapFolder. This can be used to determine various useful information about the folder, such as message count, number of unseen messages and supported flags. And when you are done with the selected folder, just unselect it using the UnselectFolder method or select another one. A read-only select is also possible, meaning that no write operations will be permitted while the folder is selected.

C#

// create client, connect and log in 
Imap client = new Imap();
client.Connect("server");
client.Login("username", "password");

// select folder 
client.SelectFolder("Inbox");

// show number of messages in the current folder 
Console.WriteLine
(
    "There are {0} messages in the {1} folder.",
    client.CurrentFolder.TotalMessageCount,
    client.CurrentFolder.Name
);

// and also the number of unseen messages 
Console.WriteLine
(
    "And {0} of them were not seen yet.",
    client.CurrentFolder.NotSeenMessageCount
);

...

client.UnselectFolder();

VB.NET

'create client, connect and log in 
Dim client As New Imap
client.Connect("server")
client.Login("username", "password")
'select folder  
client.SelectFolder("Inbox")

'show number of messages in the current folder  
Console.WriteLine( _
 "There are {0} messages in the {1} folder.", _
 client.CurrentFolder.TotalMessageCount, _
 client.CurrentFolder.Name)

'and also the number of unseen messages  
Console.WriteLine( _
 "And {0} of them were not seen yet.", _
 client.CurrentFolder.NotSeenMessageCount)

...

client.UnselectFolder()

Another useful method related to SelectFolder is GetFolderInfo. It returns an instance of ImapFolder that contains pretty much all the information SelectFolder would return, but, unlike SelectFolder, it does not unselect the current folder and select the new one. In fact, its purpose is to allow determining the status of a folder without unselecting the currently selected folder.

 

back to top...


# Sequence numbers and unique IDs

The IMAP protocol uses two different IDs to identify messages.

ID typeDescription
int sequenceNumber

A number between 1..[number of messages in the IMAP folder]. In IMAP, unlike POP3, this number can change even during IMAP session when a message is permanently removed from a folder, either by the current session or another one. Then, the sequence number of each successive message in the mailbox is decremented by 1, and this must be reflected in sequence numbers used in subsequent methods. However, it is guaranteed that a sequence number will not change during or in between calls to methods that deal with messages and identify them using a sequence number, such as GetMessageList, GetMessage, SetMessageFlags, DeleteMessage or Search, so synchronization loss of message numbers between the client and the server is no concern if your code is structured correctly.

In practice, sequence numbers will change after a call to Purge or CheckForUpdates methods, and also after calls that deal with messages and identify them using a unique ID. You might also want to detect this using Imap.Notification event.

string uniqueId

Unlike sequence number, the message unique ID is permanent and does not change between sessions. A message will retain its unique ID until it is deleted.

A minority of IMAP servers is not capable of unique IDs that persist accross sessions, and other servers might reassign its IDs when some special situation occurs, but even in these rare situations it is guaranteed that a unique ID that once identified a message in a folder will never identify a different message in the same folder.

However, it is important to notice that unique IDs are only unique inside a specific folder, and not accross different folders. Also, as a consequence of this, a message will be assigned a new unique ID if copied to another folder.

Most IMAP methods that deal with messages have two variants - one that accepts sequence number and one that accepts a unique ID as parameter. Obviously, the unique ID variants should be preferred, as they are permanent and thus safer to deal with and much more error-prone.

It's also possible to map a given unique ID to a corresponding sequence number and vice-versa using the GetMessageInfo method.

C#

// some valid unique ID we already retrieved in past 
string uniqueId = "abcd13954986";

// create client, connect and log in 
Imap client = new Imap();
client.Connect("imap.example.org");
client.Login("username", "password");

// get message info with the sequence number 
ImapMessageInfo info = client.GetMessageInfo
(
    uniqueId,
    ImapListFields.SequenceNumber
);
if (info == null)
{
    Console.WriteLine("Message not found, probably deleted?");
}
else 
{
    // read the sequence number from it 
    int sequenceNumber = info.SequenceNumber;
	
    // and use it to download the message 
    client.GetMessage(sequenceNumber, localPath);
	
    // please note that this sample is rather pointless, 
    // because we could have done this in the first place: 
    // client.GetMessage(uniqueId, localPath); 
}

VB.NET

'some valid unique ID we already retrieved in past 
Dim uniqueId As String = "abcd13954986"

'create client, connect and log in  
Dim client As New Imap
client.Connect("imap.example.org")
client.Login("username", "password")

'get message info with the sequence number  
Dim info As ImapMessageInfo = client.GetMessageInfo( _
 uniqueId, _
 ImapListFields.SequenceNumber)

If info Is Nothing Then 
	Console.WriteLine("Message not found, probably deleted?")
Else 
	'read the sequence number from it  
	Dim sequenceNumber As Integer = info.SequenceNumber

	'and use it to download the message  
	client.GetMessage(sequenceNumber, localPath)

	'please note that this sample is rather pointless,  
	'because we could have done this in the first place:  
	'client.GetMessage(uniqueId, localPath)  
End If 

 

back to top...


# Retrieving the message list

To get a list of messages in the mailbox, call the GetMessageList method. It accepts an optional parameter that specifies what information to retrieve from the server:

Parameter valueDescription
ImapListFields.SequenceNumberMessage sequence number for current session.
ImapListFields.UniqueIDMessage unique ID that is permanent and does not change between sessions.
ImapListFields.LengthMessage data size in bytes.
ImapListFields.FlagsMessage sequence number for current session.
ImapListFields.ReceivedDateMessage unique ID that is permanent and does not change between sessions.
ImapListFields.FastCombination of SequenceNumber, UniqueId, Length, Flags and ReceivedDate.
ImapListFields.EnvelopeSame as Fast, but also downloads the message envelope info - a selection of most important header fields of the message such as Date, From, To, Subject or Message ID fields. This is the default for GetMessageList method if no fieldsargument is specified.
ImapListFields.FullHeadersSame as Fast, but also downloads complete message headers of each message. This variant is the most verbose, but also the slowest, and in fact seldom needed, because nearly all interesting information about the message is already returned by ImapListFields.Envelope. See the next section for more discussion about this.

These fields are bit flags, which means that combinations such as UniqueId|Flags or UniqueId|SequenceNumber|Length are also possible - use bitwise or operator for this.

The following code shows how to download a message list and show a unique ID and From/Subject headers of each message:

C#

// create client, connect and log in 
Imap client = new Imap();
client.Connect("imap.example.org");
client.Login("username", "password");

// select folder 
client.SelectFolder("Inbox");

// get message list - envelope headers 
ImapMessageCollection messages =
    client.GetMessageList(ImapListFields.Envelope);

// display info about each message 
Console.WriteLine("UID | From | To | Subject");
foreach (ImapMessageInfo message in messages)
{
    Console.WriteLine(
        "{0} | {1} | {2} | {3}",
        message.UniqueId,
        message.From,
        message.To,
        message.Subject);
}

VB.NET

'create client, connect and log in 
Dim client As New Imap
client.Connect("imap.example.org")
client.Login("username", "password")

'select folder  
client.SelectFolder("Inbox")

'get message list - envelope headers  
Dim messages As ImapMessageCollection = _
client.GetMessageList(ImapListFields.Envelope)

'display info about each message  
Console.WriteLine("UID | From | To | Subject")
Dim message As ImapMessageInfo
For Each message In messages
	Console.WriteLine( _
		"{0} | {1} | {2} | {3}", _
		message.UniqueId, _
		message.From, _
		message.To, _
		message.Subject)
Next 

 

back to top...


# Downloading message headers

The simplest method for downloading all message headers is to call GetMessageList with parameter ImapListFields.FullHeaders, as described in the Retrieving the message list tutorial. It retrieves headers for all messages in the mailbox.

However, as mentioned earlier, this might take a very long time if there are too many messages in the mailbox or the connection bandwidth is limited. If this is the case, it is advisable either to download envelopes (ImapListFields.Envelope) only, which is a bit faster, or to only ask for a simple message list with the IDs, length, etc. (ImapListFields.Fast) and retrieve message headers of each message separately using the GetMessageInfo method - and this can even be done later or only when needed.

C#

// create client, connect and log in 
Imap client = new Imap();
client.Connect("imap.example.org");
client.Login("username", "password");

int sequenceNumber = 1; // the first message 

ImapMessageInfo info = client.GetMessageInfo
(
    sequenceNumber,
    ImapListFields.Envelope
);
// or FullHeaders if needed 

Console.Write("Date: " + info.Date);
Console.Write("From: " + info.From);
Console.Write("Subject: " + info.Subject);

VB.NET

'create client, connect and log in 
Dim client As New Imap
client.Connect("imap.example.org")
client.Login("username", "password")

Dim sequenceNumber As Integer = 1 'the first message  

Dim info As ImapMessageInfo = client.GetMessageInfo( _
 sequenceNumber, _
 ImapListFields.Envelope)
' or FullHeaders if needed  

Console.Write("Date: " & info.Date.ToString())
Console.Write("From: " & info.From.ToString())
Console.Write("Subject: " & info.Subject)

 

back to top...


# Searching

IMAP supports a search command that is quite powerful. You can search for messages matching given criteria using the Search method. It accepts a variable number of search parameters, so comlex queries are possible. See the table following the sample code for a list of possibilities.

Please note that this method only operates on a currently selected folder.

C#

// create client, connect and log in  
Imap client = new Imap();
client.Connect("server");
client.Login("username", "password");

// select the folder for search operation  
client.SelectFolder("Inbox");

// find messages from "joe@example.org"  
ImapMessageCollection fromJoe = client.Search
(
		ImapSearchParameter.From("joe@example.org")
);  
 
// find messages from the last year  
// and larger than 100KB  
ImapMessageCollection largeAndOld = client.Search
(
		ImapSearchParameter.Arrived(DateTime.Now.AddYears(-1), DateTime.Now),
		ImapSearchParameter.Size(1024 * 100, Int32.MaxValue)
);

// find messages that contain "test"  
// and "mail" in their subject and  
// "Regards" in their body  
ImapMessageCollection complexFilterResult = client.Search
(
		ImapSearchParameter.Subject("test"),
		ImapSearchParameter.Subject("mail"),
		ImapSearchParameter.Body("Regards")
);

VB.NET

'create client, connect and log in  
Dim client As New Imap
client.Connect("server")
client.Login("username", "password")

'select the folder for search operation  
client.SelectFolder("Inbox")

'find messages from "joe@example.org"  
Dim fromJoe As New ImapMessageCollection
fromJoe = client.Search( _
ImapSearchParameter.From("joe@example.org"))

'find messages from the last year  
'and larger than 100KB  
Dim largeAndOld As New ImapMessageCollection
largeAndOld = client.Search( _
ImapSearchParameter.Arrived(DateTime.Now.AddYears(-1), DateTime.Now), _
ImapSearchParameter.Size(1024 * 100, Integer.MaxValue))

'find messages that contain "test" and "mail" in their subject and  
'"Regards" in their body  
Dim complexFilterResult As New ImapMessageCollection
complexFilterResult = client.Search( _
ImapSearchParameter.Subject("test"), _
ImapSearchParameter.Subject("mail"), _
ImapSearchParameter.Body("Regards"))

The following table shows all the available search parameters:

Search parameterDescription
From(address)Messages that contain the specified string in their From field.
NotFromMessages that do not contain the specified string in their From field.
To(address)Messages that contain the specified string in their To field.
NotToMessages that do not contain the specified string in their To field.
CC(address)Messages that contain the specified string in their CC field.
NotCCMessages that do not contain the specified string in their CC field.
Bcc(address)Messages that contain the specified string in their BCC field.
NotBccMessages that do not contain the specified string in their BCC field.
Subject(queryTerm)Messages that contain the specified string in their subject field.
Body(queryTerm)Messages that contain the specified string in their body.
FullText(queryTerm)Messages that contain the specified string in their headers or body.
Arrived(on)Messages that arrived on the specified date (disregarding time).
Arrived(since, before)Messages that arrived in the specified date interval (disregarding time).
Sent(on)Messages that were sent on the specified date (disregarding time).
Sent(since, before)Messages that were sent in the specified date interval (disregarding time).
HasFlagsAllOf(flags)Messages with all the specified flags set.
HasFlagsNoneOf(flags)Messages with none of the specified flags set.
DeletedMessages whose Deleted flag is set.
NewMessages whose Recent flag is set and Seen flag not set.
RecentMessages whose Recent flag is set.
NotRecentMessages whose Recent flag is not set.
Header(headerName, queryTerm)Messages that contain the specified string in the specified header.
Size(min, max)Messages whose size within the specified interval.
AllSearch for all messages. Same as GetMessageList method.

 

back to top...


# Message flags

Message flags such as "Deleted", "Recent" or "Answered" indicate message states. Most of them can be changed, only the "Recent" flag is read-only. Message flags are returned as a part of GetMessageList/GetMessageInfo/Search response as the Flags property of the ImapMessageInfo class, and you can also search for messages with specified flags set. The following sample demonstrates setting message flags.

C#

// create client, connect and log in 
Imap client = new Imap();
client.Connect("imap.example.org");
client.Login("username", "password");

// select folder 
client.SelectFolder("Inbox");

// set the "flagged for special attention" flag on  
// the first message in the Inbox 
client.SetMessageFlags
    (1, ImapFlagAction.Add, ImapMessageFlags.Flagged);

// clear the "flagged for special attention" fl