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 type | Description |
|---|
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 value | Description |
|---|
ImapListFields.SequenceNumber | Message sequence number for current session. |
ImapListFields.UniqueID | Message unique ID that is permanent and does not change between sessions. |
ImapListFields.Length | Message data size in bytes. |
ImapListFields.Flags | Message sequence number for current session. |
ImapListFields.ReceivedDate | Message unique ID that is permanent and does not change between sessions. |
ImapListFields.Fast | Combination of SequenceNumber, UniqueId, Length,
Flags and ReceivedDate. |
ImapListFields.Envelope | Same 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.FullHeaders | Same 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 parameter | Description |
|---|
| From(address) | Messages that contain the specified string in their From field. |
| NotFrom | Messages that do not contain the specified string in their From field. |
| To(address) | Messages that contain the specified string in their To field. |
| NotTo | Messages that do not contain the specified string in their To field. |
| CC(address) | Messages that contain the specified string in their CC field. |
| NotCC | Messages that do not contain the specified string in their CC field. |
| Bcc(address) | Messages that contain the specified string in their BCC field. |
| NotBcc | Messages 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. |
| Deleted | Messages whose Deleted flag is set. |
| New | Messages whose Recent flag is set and Seen flag not set. |
| Recent | Messages whose Recent flag is set. |
| NotRecent | Messages 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. |
| All | Search 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("