More .NET components

IMAP - message operations

The sample code on this page assumes you have already connected and authenticated to an IMAP servers and selected a folder.

Getting list of messages #

To get a list of messages, use GetMessageList method. By default, the Envelope information is retrieved, which is sufficient to display basic info such as From, To, Date and Subject headers.

Tip: You can choose which fields to retrieve to improve the performance of your application.

CSharp

// create IMAP client instance, connect, log in, select folder
var imap = new Rebex.Net.Imap();
imap.Connect(hostname, SslMode.Implicit);
imap.Login(username, password);
imap.SelectFolder("Inbox");

// get list of all messages
ImapMessageCollection list = imap.GetMessageList();

// print some info
Console.WriteLine("Found {0} message(s).", list.Count);
foreach (ImapMessageInfo info in list)
{
    Console.WriteLine("[{0}] {1}: {2}", info.ReceivedDate, info.From, info.Subject);
}

VisualBasic

' create IMAP client instance, connect, log in, select folder
Dim imap As New Rebex.Net.Imap()
imap.Connect(hostname, SslMode.Implicit)
imap.Login(username, password)
imap.SelectFolder("Inbox")

' get list of all messages
Dim list As ImapMessageCollection = imap.GetMessageList()

' print some info
Console.WriteLine("Found {0} message(s).", list.Count)
For Each info As ImapMessageInfo In list
    Console.WriteLine("[{0}] {1}: {2}", info.ReceivedDate, info.From, info.Subject)
Next

Sequence numbers and unique IDs #

IMAP servers identify a single mail message by sequence number or unique ID.

Sequence number identifies the current position of the message within its folder, and it changes if one (or more) of the messages with a lower sequence number is removed.

On the other hand, unique IDs are supposed to stay the same for a long time, possibly indefinitely, as long as the message stays within its original folder in its original form. Otherwise, they can only changed when the validity ID of their folder has been changed, which should only happen rarely.

The following code converts a unique ID to sequence number:

CSharp

// create IMAP client instance, connect, log in, select folder
// ...

// get message info according to Unique ID
ImapMessageInfo info = imap.GetMessageInfo(uniqueId, ImapListFields.SequenceNumber);

// get the Sequence number from message info
int sequenceNumber = info.SequenceNumber;

VisualBasic

' create IMAP client instance, connect, log in, select folder
' ...

' get message info according to Unique ID
Dim info As ImapMessageInfo = imap.GetMessageInfo(uniqueId, ImapListFields.SequenceNumber)

' get the Sequence number from message info
Dim sequenceNumber As Integer = info.SequenceNumber

The following code converts a sequence number to unique ID:

CSharp

// get message info according to Sequence number
ImapMessageInfo info = imap.GetMessageInfo(sequenceNumber, ImapListFields.UniqueId);

// get the Unique ID from message info
string uniqueId = info.UniqueId;

VisualBasic

' get message info according to Sequence number
Dim info As ImapMessageInfo = imap.GetMessageInfo(sequenceNumber, ImapListFields.UniqueId)

' get the Unique ID from message info
Dim uniqueId As String = info.UniqueId

Almost all Imap methods have a unique ID overload and a sequence number overload.

Message fields #

Some of Imap methods make it possible to specify which information to retrieve about IMAP messages. These methods include GetMessageInfo, GetMessageList and Search. It's a good idea to only request the information you need - it can save lot of time, bandwidth and processing power. Use the ImapListFields argument to specify which information to retrieve:

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 flags (see the ImapMessageFlags enum for the list of message flags).
ImapListFields.ReceivedDate Date and time at which the message was received by the mail server.
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 methods with optional fields argument.
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.
ImapListFields.Body Text and HTML bodies of the message.
ImapListFields.MessageStructure Information about the message structure - list of message parts (bodies, resources and attachments) with detailed info (file names, lengths, content types, content IDs). To download a single message part, use GetMessagePart method.

Note: These fields are bit flags, which means that combinations such as UniqueId|Flags or UniqueId|SequenceNumber|Length are possible - use bitwise OR operator for this (| in C#, Or in VB.NET).

Getting message info #

To get information about a message, use GetMessageInfo method. By default, the Envelope information is retrieved, which is sufficient to display basic info such as From, To, Date and Subject headers.

Tip: You can choose which fields to retrieve to improve the performance of your application.

CSharp

// create IMAP client instance, connect, log in, select folder
// ...

// get Envelope and Body parts of a message
ImapMessageInfo info =
    imap.GetMessageInfo(uniqueId, ImapListFields.Envelope | ImapListFields.Body);

// print info about the message
Console.WriteLine("[{0}] {1}: {2}", info.ReceivedDate, info.From, info.Subject);
if (info.HasBodyText)
    Console.WriteLine(info.BodyText);

VisualBasic

' create IMAP client instance, connect, log in, select folder
' ...

' get Envelope and Body parts of a message
Dim info As ImapMessageInfo =
    imap.GetMessageInfo(uniqueId, ImapListFields.Envelope Or ImapListFields.Body)

' print info about the message
Console.WriteLine("[{0}] {1}: {2}", info.ReceivedDate, info.From, info.Subject)
If info.HasBodyText Then
    Console.WriteLine(info.BodyText)
End If

Working with multiple messages #

Some methods of the Imap object accept a message set as a parameter. This makes it possible to process multiple messages at once, usually in a single round-trip to the server, which can be a benefit on slow connections. All these methods accept a ImapMessageSet argument, which is a set of either individual unique IDs or sequence numbers, or their ranges.

The methods that accept ImapMessageSet argument are:

  • Search
  • GetMessageList
  • CopyMessage
  • SetMessageFlags
  • DeleteMessage
  • UndeleteMessage

Following code demonstrates paged message listing:

CSharp

// create IMAP client instance, connect, log in, select folder
// ...

// page index and size
int pageIndex = 0;
int pageSize = 10;

// create set to retrieve only specific page of message listing
var set = new ImapMessageSet();

int from = (pageIndex * pageSize) + 1;
int to = from + pageSize - 1;

if (to > imap.CurrentFolder.TotalMessageCount)
    to = imap.CurrentFolder.TotalMessageCount;

if (from <= imap.CurrentFolder.TotalMessageCount)
    set.AddRange(from, to);

// get list of specified messages
ImapMessageCollection list = imap.GetMessageList(set);

// print some info
Console.WriteLine("Found {0} message(s).", list.Count);
foreach (ImapMessageInfo info in list)
{
    Console.WriteLine("[{0}] {1}: {2}", info.ReceivedDate, info.From, info.Subject);
}

VisualBasic

' create IMAP client instance, connect, log in, select folder
' ...

' page index and size
Dim pageIndex As Integer = 0
Dim pageSize As Integer = 10

' create set to retrieve only specific page of message listing
Dim [set] = New ImapMessageSet()

Dim [from] As Integer = (pageIndex * pageSize) + 1
Dim [to] As Integer = [from] + pageSize - 1

If [to] > imap.CurrentFolder.TotalMessageCount Then
    [to] = imap.CurrentFolder.TotalMessageCount
End If

If [from] <= imap.CurrentFolder.TotalMessageCount Then
    [set].AddRange([from], [to])
End If

' get list of specified messages
Dim list As ImapMessageCollection = imap.GetMessageList([set])

' print some info
Console.WriteLine("Found {0} message(s).", list.Count)
For Each info As ImapMessageInfo In list
    Console.WriteLine("[{0}] {1}: {2}", info.ReceivedDate, info.From, info.Subject)
Next

Downloading messages #

To download and parse a whole mail message into memory, use the GetMailMessage method:

CSharp

// create IMAP client instance, connect, log in, select folder
// ...

// get mail message
MailMessage mail = imap.GetMailMessage(uniqueId);

// print some info
Console.WriteLine("From: {0}", mail.From);
Console.WriteLine("Subject: {0}", mail.Subject);
if (mail.Attachments.Count > 0)
    Console.WriteLine("Attachments: {0}", mail.Attachments.Count);
if (mail.HasBodyText)
    Console.WriteLine("Body: {0}", mail.BodyText);

VisualBasic

' create IMAP client instance, connect, log in, select folder
' ...

' get mail message
Dim mail As MailMessage = imap.GetMailMessage(uniqueId)

' print some info
Console.WriteLine("From: {0}", mail.From)
Console.WriteLine("Subject: {0}", mail.Subject)
If mail.Attachments.Count > 0 Then
    Console.WriteLine("Attachments: {0}", mail.Attachments.Count)
End If
If mail.HasBodyText Then
    Console.WriteLine("Body: {0}", mail.BodyText)
End If

This retrieves an instance of high-level MailMessage object. If you prefer the low-level API (MimeMessage object), call GetMimeMessage method instead.

Alternatively, you can easily download a message into a file using GetMessage method:

CSharp

// save mail directly to disk
imap.GetMessage(uniqueId, @"C:\MyData\mail.eml");

VisualBasic

' save mail directly to disk
imap.GetMessage(uniqueId, "C:\MyData\mail.eml")

To download the message to a Stream instead, use another GetMessage overload:

CSharp

// prepare stream
var ms = new MemoryStream();

// save mail directly to a stream
imap.GetMessage(uniqueId, ms);

VisualBasic

' prepare stream
Dim ms = New MemoryStream()

' save mail directly to a stream
imap.GetMessage(uniqueId, ms)

Downloading message headers #

To retrieve message headers into an instance of ImapMessageInfo, use GetMessageInfo method with ImapListFields.FullHeaders argument.

It's possible to retrieve headers for multiple messages as well using GetMessageList method, but it may take a long time.

Alternatively, to download the message headers into a file or a stream, use the GetMessageHeaders method:

CSharp

// create IMAP client instance, connect, log in, select folder
// ...

// prepare stream
var ms = new MemoryStream();

// get message headers
imap.GetMessageHeaders(uniqueId, ms);

VisualBasic

' create IMAP client instance, connect, log in, select folder
' ...

' prepare stream
Dim ms = New MemoryStream()

' get message headers
imap.GetMessageHeaders(uniqueId, ms)

Downloading message parts #

IMAP makes it possible to download separate message parts without having to download the whole message. For example, you can download the message envelope and bodies first, but only download individual attachments later when needed.

CSharp

// create IMAP client instance, connect, log in, select folder
// ...

// get message structure info
ImapMessageInfo info = imap.GetMessageInfo(uniqueId, ImapListFields.MessageStructure);

// save all attachments
foreach (ImapMessagePart part in info.GetParts())
{
    // process only attachments
    if (part.Kind != ImapMessagePartKind.Attachment)
        continue;

    // prepare file stream
    string target = Path.Combine(@"C:\MyData", part.FileName);
    using (FileStream stream = File.Create(target))
    {
        // download the attachment
        imap.GetMessagePart(uniqueId, part.Id, stream);
    }
}

VisualBasic

' create IMAP client instance, connect, log in, select folder
' ...

' get message structure info
Dim info As ImapMessageInfo = imap.GetMessageInfo(uniqueId, ImapListFields.MessageStructure)

' save all attachments
For Each part As ImapMessagePart In info.GetParts()
    ' process only attachments
    If part.Kind <> ImapMessagePartKind.Attachment Then
        Continue For
    End If

    ' prepare file stream
    Dim target As String = Path.Combine("C:\MyData", part.FileName)
    Using stream As FileStream = File.Create(target)
        ' download the attachment
        imap.GetMessagePart(uniqueId, part.Id, stream)
    End Using
Next

GetMessagePart method makes it possible to retrieve the text of the message as well. However, it usually easier to use GetMessageInfo(ImapListFields.Body) method and access the bodies through ImapMessageInfo.BodyText and ImapMessageInfo.BodyHtml properties.

Uploading messages #

You can even upload a message to a folder in an IMAP mailbox. The Upload method accepts a local file, stream, MailMessage or MimeMessage objects. You can set flags and/or keywords for the message as well.

CSharp

// create IMAP client instance, connect, log in
// ...

// create new mail message
var mail = new Rebex.Mail.MailMessage();
mail.From = "joe@example.org";
mail.To = "john@example.org";
mail.Subject = "Test";
mail.BodyText = "Hello World!";
mail.BodyHtml = "<strong>Hello World!</strong>";

// upload the message to the "Inbox" folder on the IMAP server
imap.StoreMessage("Inbox", mail);

VisualBasic

' create IMAP client instance, connect, log in
' ...

' create new mail message
Dim mail = New Rebex.Mail.MailMessage()
mail.From = "joe@example.org"
mail.To = "john@example.org"
mail.Subject = "Test"
mail.BodyText = "Hello World!"
mail.BodyHtml = "<strong>Hello World!</strong>"

' upload the message to the "Inbox" folder on the IMAP server
imap.StoreMessage("Inbox", mail)

If the IMAP server supports UIDPLUS extension, StoreMessage method returns the unique ID assigned to the newly uploaded message.

Uploading raw messages #

The Upload method parses the supplied message to ensure the IMAP server gets a message in a format it supports (MIME). When uploading lot of large messages, this can negatively affect the performance. If you are sure your messages are valid and would like to to skip this step, use the StoreRawMessage method instead:

CSharp

// create IMAP client instance, connect, log in
// ...

// upload a mail directly to "Inbox" without parsing its content
using (FileStream input = File.OpenRead(@"C:\MyData\mail.eml"))
{
    imap.StoreRawMessage("Inbox", input, ImapMessageFlags.None, new MailDateTime(DateTime.Now));
}

VisualBasic

' create IMAP client instance, connect, log in
' ...

' upload a mail directly to "Inbox" without parsing its content
Using input As FileStream = File.OpenRead("C:\MyData\mail.eml")
    imap.StoreRawMessage("Inbox", input, ImapMessageFlags.None, New MailDateTime(DateTime.Now))
End Using

If the IMAP server supports UIDPLUS extension, StoreMessageRaw method returns the unique ID assigned to the newly uploaded message.

Copying messages #

To copy a message from current folder to another one, use the CopyMessage:

CSharp

// create IMAP client instance, connect, log in
// ...

// select "Inbox"
imap.SelectFolder("Inbox");

// copy a message from "Inbox" to "My mails"
imap.CopyMessage(uniqueId, "My mails");

VisualBasic

' create IMAP client instance, connect, log in
' ...

' select "Inbox"
imap.SelectFolder("Inbox")

' copy a message from "Inbox" to "My mails"
imap.CopyMessage(uniqueId, "My mails")

If the IMAP server supports UIDPLUS extension, CopyMessage method returns an instance of ImapCopyResult that contains the unique IDs of the original and target messages.

Deleting and undeleting messages #

To delete a mail message, use DeleteMessage method. Please note that this only sets the Deleted message flag. To permanently remove messages marked for deletion, use the Purge method.

CSharp

// create IMAP client instance, connect, log in, select folder
// ...

// delete a message
imap.DeleteMessage(uniqueId);

// permanently remove messages marked as deleted
imap.Purge();

VisualBasic

' create IMAP client instance, connect, log in, select folder
' ...

' delete a message
imap.DeleteMessage(uniqueId)

' permanently remove messages marked as deleted
imap.Purge()

To undelete a message (remove the Deleted flag), use the UndeleteMessage method:

CSharp

// undelete message, which was previously marked as deleted
imap.UndeleteMessage(uniqueId);

VisualBasic

' undelete message, which was previously marked as deleted
imap.UndeleteMessage(uniqueId)

Message flags (seen/unseen, answered/unanswered and more) #

IMAP protocol defines several flags, some of which can be added to or removed from messages by clients. Flags can be retrieved by specifying a ImapListFields.Flags field in GetMessageInfo or GetMessageList calls, and they can be set and removed using SetMessageFlags method.

The following flags are supported and represented by ImapMessageFlags enum:

  • Seen
  • Recent
  • Answered
  • Deleted
  • Flagged
  • Keywords
  • Draft

The following code shows how to search for messages with specific flags by the Search method.
It finds all messages that have not been seen yet (not flagged as Seen):

CSharp

// create IMAP client instance, connect, log in, select folder
// ...

// get list of all 'not-Seen' messages
ImapMessageCollection list = imap.Search(ImapSearchParameter.HasFlagsNoneOf(ImapMessageFlags.Seen));

// print some info
Console.WriteLine("Not-seen messages: {0}", list.Count);
foreach (ImapMessageInfo info in list)
{
    Console.WriteLine("[{0}] {1}: {2}", info.ReceivedDate, info.From, info.Subject);
}

VisualBasic

' create IMAP client instance, connect, log in, select folder
' ...

' get list of all 'not-Seen' messages
Dim list As ImapMessageCollection = imap.Search(ImapSearchParameter.HasFlagsNoneOf(ImapMessageFlags.Seen))

' print some info
Console.WriteLine("Not-seen messages: {0}", list.Count)
For Each info As ImapMessageInfo In list
    Console.WriteLine("[{0}] {1}: {2}", info.ReceivedDate, info.From, info.Subject)
Next

The following code shows how to mark a message as Answered once a reply has been sent:

CSharp

// create IMAP client instance, connect, log in, select folder
// ...

// get the message
MailMessage mail = imap.GetMailMessage(uniqueId);

// create reply message
MailMessage reply = mail.CreateReply(sender, ReplyBodyTransformation.None);

reply.BodyText =
    "I am on holidays till 1st November.\n" +
    "John\n" +
    "\n" +
    "Original message:\n" +
    mail.BodyText;

// send the reply
Smtp.Send(reply, smtpHostName);

// mark the message as answered
imap.SetMessageFlags(uniqueId, ImapFlagAction.Add, ImapMessageFlags.Answered);

VisualBasic

' create IMAP client instance, connect, log in, select folder
' ...

' get the message
Dim mail As MailMessage = imap.GetMailMessage(uniqueId)

' create reply message
Dim reply As MailMessage = mail.CreateReply(sender, ReplyBodyTransformation.None)

reply.BodyText =
    "I am on holidays till 1st November." & vbLf &
    "John" & vbLf &
    vbLf &
    "Original message:" & vbLf &
    Convert.ToString(mail.BodyText)

' send the reply
Smtp.Send(reply, smtpHostName)

' mark the message as answered
imap.SetMessageFlags(uniqueId, ImapFlagAction.Add, ImapMessageFlags.Answered)

Finally, the following code shows how to retrieve flags, and how to remove the Seen flag (added by the server automatically) once the message has been downloaded:

CSharp

// create IMAP client instance, connect, log in, select folder
// ...

// get message flags
ImapMessageInfo info = imap.GetMessageInfo(uniqueId, ImapListFields.Flags);

// download the message
// this should set the SEEN flag automatically by the IMAP server
imap.GetMessage(uniqueId, @"C:\MyData\file.txt");

// mark the message as not-Seen if not seen before downloading
// it means Seen flag has to be removed from the message
if ((info.Flags & ImapMessageFlags.Seen) == 0)
    imap.SetMessageFlags(uniqueId, ImapFlagAction.Remove, ImapMessageFlags.Seen);

VisualBasic

' create IMAP client instance, connect, log in, select folder
' ...

' get message flags
Dim info As ImapMessageInfo = imap.GetMessageInfo(uniqueId, ImapListFields.Flags)

' download the message
' this should set the Seen flag automatically by the IMAP server
imap.GetMessage(uniqueId, "C:\MyData\file.txt")

' mark the message as not-Seen if not seen before downloading
' it means that Seen flag has to be removed from the message
If (info.Flags And ImapMessageFlags.Seen) = 0 Then
    imap.SetMessageFlags(uniqueId, ImapFlagAction.Remove, ImapMessageFlags.Seen)
End If

Message keywords #

Many IMAP servers (such as Gmail) support custom keywords. These are similar to flags, but are user-defined.

The following code demonstrates how to set message keywords and how to use them when searching for messages later:

CSharp

// create IMAP client instance, connect, log in, select folder
// ...

// add some keywords to some messages
imap.SetMessageFlags(1, ImapFlagAction.Add, ImapMessageFlags.Keywords, "A");
imap.SetMessageFlags(2, ImapFlagAction.Add, ImapMessageFlags.Keywords, "B");
imap.SetMessageFlags(3, ImapFlagAction.Add, ImapMessageFlags.Keywords, "A", "B");

// finds message 1 and 3
ImapMessageCollection listA = imap.Search(ImapSearchParameter.Keyword("A"));

// finds message 2 and 3
ImapMessageCollection listB = imap.Search(ImapSearchParameter.Keyword("B"));

// finds message 3
ImapMessageCollection listAandB = imap.Search(
    ImapSearchParameter.Keyword("A"),
    ImapSearchParameter.Keyword("B"));

// finds message 1,2,3
ImapMessageCollection listAorB = imap.Search(
    ImapSearchParameter.Or(
        ImapSearchParameter.Keyword("A"),
        ImapSearchParameter.Keyword("B")));

VisualBasic

' create IMAP client instance, connect, log in, select folder
' ...

' add some keywords to some messages
imap.SetMessageFlags(1, ImapFlagAction.Add, ImapMessageFlags.Keywords, "A")
imap.SetMessageFlags(2, ImapFlagAction.Add, ImapMessageFlags.Keywords, "B")
imap.SetMessageFlags(3, ImapFlagAction.Add, ImapMessageFlags.Keywords, "A", "B")

' finds message 1 and 3
Dim listA As ImapMessageCollection = imap.Search(ImapSearchParameter.Keyword("A"))

' finds message 2 and 3
Dim listB As ImapMessageCollection = imap.Search(ImapSearchParameter.Keyword("B"))

' finds message 3
Dim listAandB As ImapMessageCollection = imap.Search(
    ImapSearchParameter.Keyword("A"),
    ImapSearchParameter.Keyword("B"))

' finds message 1,2,3
Dim listAorB As ImapMessageCollection = imap.Search(
    ImapSearchParameter.Or(
        ImapSearchParameter.Keyword("A"),
        ImapSearchParameter.Keyword("B")))