Introduction
Everyone who has a computer or mobile device has used mail. Mail system is an old, traditional simple protocol.
The purpose of this article (Part 3) is to explore the inside of the IMAP protocol and show you how to implement it with C#.
You can get libraries that include Mail, Twitter, Facebook, dropbox, Windows Live at http://higlabo.codeplex.com/.
IMAP
You can select two protocols to receive mail from a mailbox. This article describes about
the IMAP protocol. Here is a basic flow to receive mail.
- Open connection
- Authenticate
- SelectFolder
- Fetch
- Logout

Open connection
See Open connection section of this post.
http://www.codeproject.com/Articles/399207/Understanding-the-insides-of-the-SMTP-mail-protoco
Authenticate
At first, you must authenticate the mailbox with your username and password.
ImapClient.cs
public ImapCommandResult ExecuteLogin()
{
if (this.EnsureOpen() == ImapConnectionState.Disconnected) { throw new MailClientException(); }
String commandText = String.Format(this.Tag + " LOGIN {0} {1}", this.UserName, this.Password);
String s = this.Execute(commandText, false);
ImapCommandResult rs = new ImapCommandResult(this.Tag, s);
if (rs.Status == ImapCommandResultStatus.Ok)
{
this._State = ImapConnectionState.Authenticated;
}
else
{
this._State = ImapConnectionState.Connected;
}
return rs;
}
Get folder list
After authenticate, you must select a folder to get the actual mail data. To select
a folder, you would like to get the folder list which exists in the mailbox.
You can get the folder list by sending a list command to the mail server.
public ListResult ExecuteList(String folderName, Boolean recursive)
{
this.ValidateState(ImapConnectionState.Authenticated);
List<ListLineResult> l = new List<ListLineResult>();
String name = "";
Boolean noSelect = false;
Boolean hasChildren = false;
String rc = "%";
if (recursive == true)
{
rc = "*";
}
String s = this.Execute(String.Format(this.Tag + " LIST \"{0}\" \"{1}\"", folderName, rc), false);
foreach (Match m in RegexList.GetListFolderResult.Matches(s))
{
name = NamingConversion.DecodeString(m.Groups["name"].Value);
foreach (Capture c in m.Groups["opt"].Captures)
{
if (c.Value.ToString() == "\\Noselect")
{
noSelect = true;
}
else if (c.Value.ToString() == "\\HasNoChildren")
{
hasChildren = false;
}
else if (c.Value.ToString() == "\\HasChildren")
{
hasChildren = true;
}
}
l.Add(new ListLineResult(name, noSelect, hasChildren));
}
return new ListResult(l);
}
Under the hood, such a command text is sent to the mail server:
tag1 LIST "" "*"
The response text from the server is like this:
* LIST (\HasNoChildren) "/" "INBOX"
* LIST (\HasNoChildren) "/" "Notes"
* LIST (\Noselect \HasChildren) "/" "[Gmail]"
* LIST (\HasNoChildren) "/" "[Gmail]/All Mail"
......
* LIST (\HasNoChildren) "/" "[Gmail]/Trash"
tag1 OK Success
The ListResult, ListLineResult class diagrams are like below.


You can get all folders by calling the GetAllFolders method of the ImapClient class.
MailMessage mg = null;
using (ImapClient cl = new ImapClient("imap.gmail.com"))
{
cl.Port = 993;
cl.Ssl = true;
cl.UserName = "xxxxx";
cl.Password = "yyyyy";
var bl = cl.Authenticate();
if (bl == true)
{
var l = cl.GetAllFolders();
}
}
Select folder
Before you receive mail from the server, you must select the folder in your mailbox. To select
the folder,
you send a select command to the server. Here is the inside of the ExecuteSelect method of
the ImapClient class.
public SelectResult ExecuteSelect(String folderName)
{
this.ValidateState(ImapConnectionState.Authenticated);
String commandText = String.Format(this.Tag + " Select {0}", NamingConversion.EncodeString(folderName));
String s = this.Execute(commandText, false);
var rs = this.GetSelectResult(folderName, s);
this.CurrentFolder = new ImapFolder(rs);
return rs;
}
Client send below text to server.
tag1 Select INBOX
Server return response text to client
* FLAGS (\Answered \Flagged \Draft \Deleted \Seen $Forwarded)
* OK [PERMANENTFLAGS (\Answered \Flagged \Draft \Deleted \Seen $Forwarded \*)] Flags permitted.
* OK [UIDVALIDITY 594544687] UIDs valid.
* 223 EXISTS
* 0 RECENT
* OK [UIDNEXT 494] Predicted next UID.
tag1 OK [READ-WRITE] INBOX selected. (Success)
This response text would be represented as SelectResult class.

The ImapClient class has a SelectFolder method that is easy to use.And this method returns
an ImapFolder object that is created from SelectResult object inside of SelectFolder method.
public ImapFolder SelectFolder(String folderName)
{
var rs = this.ExecuteSelect(folderName);
return new ImapFolder(rs);
}
Here is the ImapFolder class diagram:

Get message
After folder selection, you can get the mail list using the Fetch command. You can get
the actual mail message data by calling the GetMessage method of
the ImapClient class.
Here is a sample code to receive a mail message:
private static void ImapMailReceive()
{
MailMessage mg = null;
using (ImapClient cl = new ImapClient("imap.gmail.com"))
{
cl.Port = 993;
cl.Ssl = true;
cl.UserName = "xxxxx";
cl.Password = "yyyyy";
var bl = cl.Authenticate();
if (bl == true)
{
var folder = cl.SelectFolder("[Gmail]/All Mail");
for (int i = 0; i < folder.MailCount; i++)
{
mg = cl.GetMessage(i + 1);
}
}
}
}
You must pass an index to the GetMessage method larger than 1. Please
make sure that the first value is 1, not zero.
Client send below text
tag1 FETCH 1 (BODY[])
Server would return below text
* 1 FETCH (BODY[] {2370}
Delivered-To: xxxx@gmail.com
To: = <yyyyy@gmail.com>
Date: Thu, 23 Apr 2009 08:22:21 +0900
From: <xxxxx@gmail.com>
Subject: Test Mail
...Mail body data....
)
tag1 OK Success
Format is same to Pop3Message.ImapClient class extract text and pass it to MailMessage class and create MailMessage object.
Attached file, HTML mail, .eml file
Aattached file, HTML mail, .eml file are the same as for the POP3 protocol.
Please see this article: Understanding the insides of the POP3 mail protocol: Part 2.
Delete mail
Here is the delete process on IMAP:

You add a flag as delete to the selected mail that you indicate by mail index. These marked mails will be deleted when you send
the EXPUNGE command.
You can delete a mail by using the DeleteEMail method of the
ImapClient object.
protected void Button1_Click(object sender, EventArgs e)
{
MailMessage mg = null;
String htmlText = "";
using (ImapClient cl = new ImapClient("imap.gmail.com"))
{
cl.Port = 993;
cl.Ssl = true;
cl.UserName = "xxxxx";
cl.Password = "yyyyy";
var folder = cl.SelectFolder("[Gmail]/All Mail");
cl.DeleteEMail(1, 2, 3);
}
}
There is no authenticate required since all processes (open connection, authenticate, select folder, expunge, logout) will automatically execute inside of
the DeleteEMail method.
Here is an implementation of the DeleteEMail method.
public Boolean DeleteEMail(params Int64[] mailIndex)
{
this.ValidateState(ImapConnectionState.Authenticated, true);
return this.DeleteEMail(this.CurrentFolder.Name, mailIndex);
}
public Boolean DeleteEMail(params Int64[] mailIndex)
{
if (this.EnsureOpen() == ImapConnectionState.Disconnected) { return false; }
if (this.Authenticate() == false) { return false; }
for (int i = 0; i < mailIndex.Length; i++)
{
var rs = this.ExecuteStore(mailIndex[i], StoreItem.FlagsAdd, @"\Deleted");
if (rs.Status != ImapCommandResultStatus.Ok) { return false; }
}
this.ExecuteExpunge();
this.ExecuteLogout();
return true;
}
Manage read or unread
IMAP is a new protocol after POP3 to solve POP3 problem. IMAP has a search command that can receive only unread mail.
So you don't have to manage read state in your application. The only thing you must do is to send
a search command to the mail server. Here is a sample code to receive unread mail list from
a server.
MailMessage mg = null;
using (ImapClient cl = new ImapClient("imap.gmail.com"))
{
cl.Port = 993;
cl.Ssl = true;
cl.UserName = "xxxxx";
cl.Password = "yyyyy";
var bl = cl.Authenticate();
if (bl == true)
{
var folder = cl.SelectFolder("[Gmail]/All Mail");
var list = cl.ExecuteSearch("UNSEEN UNDELETED");
for (int i = 0; i < list.MailIndexList.Count; i++)
{
mg = cl.GetMessage(list.MailIndexList[i]);
}
}
}
Client send below text under the hood.
tag1 SEARCH UNSEEN UNDELETED
Server would return such text to client
* SEARCH 1 2 3 4 9 10 11 12 13 14 17 18 19 20 21 22 30 32 33
tag1 OK SEARCH completed (Success)
This response text is represented as SearchResult class.

You can easily get mail index list by Search command.It is pretty easy compared with POP3.
Draft mail
You can save a draft mail to the mail server by calling the Append command.
MailMessage mg = null;
using (ImapClient cl = new ImapClient("imap.gmail.com"))
{
cl.Port = 993;
cl.Ssl = true;
cl.UserName = "xxxxx";
cl.Password = "yyyyy";
var bl = cl.Authenticate();
if (bl == true)
{
var smg = new SmtpMessage("xxx@gmail.com", "yyy@hotmail.com",
"yyy@hotmail.com", "This is a test mail.", "Hi.Is it correct??");
cl.ExecuteAppend("GMail/Drafts", smg.GetDataText(), "\\Draft", DateTimeOffset.Now);
}
}
You can get a draft mail by the same process shown above.
MailMessage mg = null;
using (ImapClient cl = new ImapClient("imap.gmail.com"))
{
cl.Port = 993;
cl.Ssl = true;
cl.UserName = "xxxxx";
cl.Password = "yyyyy";
var bl = cl.Authenticate();
if (bl == true)
{
var folder = cl.SelectFolder("[Gmail]/Drafts");
mg = cl.GetMessage(1);
var smg = mg.CreateSmtpMessage();
}
}
To send a mail, see this article:
Understanding the insides
of the SMTP Mail protocol: Part 1.
Subscribe
You can subscribe a folder that you want to watch.
MailMessage mg = null;
using (ImapClient cl = new ImapClient("imap.gmail.com"))
{
cl.Port = 993;
cl.Ssl = true;
cl.UserName = "xxxxx";
cl.Password = "yyyyy";
var bl = cl.Authenticate();
if (bl == true)
{
cl.ExecuteSubscribe("CodeProject");
cl.ExecuteSubscribe("Codeplex");
}
}
Once you subscribe to a folder, you can get the folder list using the below code.
MailMessage mg = null;
using (ImapClient cl = new ImapClient("imap.gmail.com"))
{
cl.Port = 993;
cl.Ssl = true;
cl.UserName = "xxxxx";
cl.Password = "yyyyy";
var bl = cl.Authenticate();
if (bl == true)
{
var rs = cl.ExecuteLsub("", false);
foreach (var line in rs.Lines)
{
var folder = new ImapFolder(line);
}
}
}
Idle command
Imap has a idle command that enable you to receive a message(new mail,deleted...etc) from server.
using (ImapClient cl = new ImapClient("imap.gmail.com", 993, "user name", "password"))
{
cl.Ssl = true;
cl.ReceiveTimeout = 10 * 60 * 1000; if (cl.Authenticate() == true)
{
ImapFolder r = cl.SelectFolder("INBOX");
using (var cm = cl.CreateImapIdleCommand())
{
cm.MessageReceived +=
(Object o, ImapIdleCommandMessageReceivedEventArgs e) =>
{
foreach (var mg in e.MessageList)
{
String text = String.Format("Type is {0} Number is {1}"
, mg.MessageType, mg.Number);
Console.WriteLine(text);
}
};
cl.ExecuteIdle(cm);
while (true)
{
var line = Console.ReadLine();
if (line == "done")
{
cl.ExecuteDone(cm);
break;
}
}
}
}
}
When you receive new mail and the count of INBOX folder changed, server will send client a text as response.
* 224 EXISTS
If you delete a mail, server send such text to client.
* 224 EXPUNGE
* 223 EXISTS
You can receive these message by register event handler to MessageReceived event.
cm.MessageReceived += (Object o, ImapIdleCommandMessageReceivedEventArgs e) =>
{
foreach (var mg in e.MessageList)
{
String text = String.Format("Type is {0} Number is {1}"
, mg.MessageType, mg.Number);
Console.WriteLine(text);
}
};
ImapIdleCommandMessageReceivedEventArgs object has MessageList property that is List.
ImapIdleCommandMessage has two property MessageType and Number.
You can know what happen in the server and pop up notification window to user with idle command.
Other...
IMAP has so many specifications that I could not cover in this article. I focuses
on the most important topics for IMAP beginners to start easily.
I hope this article will help you. Thank you for reading.
Related articles are listed here:
History
- 2012/06/25: First post.
- 2012/07/06: Modify source code and article
- 2012/07/24: Modify source code and add some detail description about Idle and other