Click here to Skip to main content
15,888,968 members
Articles / Programming Languages / C#

How to Access Emails Using the IMAP Protocol

Rate me:
Please Sign up or sign in to vote.
4.53/5 (26 votes)
26 May 2014GPL36 min read 185.9K   7.7K   85   40
This article explains how to use the IMAP protocol to access emails. It explains how to use some of the common IMAP commands.

Introduction

IMAP (Internet Message Access Protocol) is an email messaging protocol which allows transferring of e-mail messages from a server. The protocol is based on commands which are sent from a client such as Mozilla Thunderbird or Microsoft Outlook. These commands allow you to login to a mailbox, get the total message count and the unread message count, view your messages, as well as create, delete, and rename mailboxes.

There are many IMAP controls available for various programming languages, and many articles explaining how to use these controls, but what if you would like to understand how the protocol is used to help you develop your own IMAP control? You may want to develop a small application that sits on your desktop informing you of new emails, or just displaying how many unread email messages you have. If you’re a very adventurous developer, you can try to develop your own email client.

In this article, I will explain how to connect to a mailbox to retrieve emails. This article is intended to be a brief introduction to some of the main IMAP commands. I will not discuss any error handling to make the code more understandable. You can add the error handling yourself.

Connecting to the mailbox

IAMP operates on port 143. In order to connect to the mailbox, we need to connect to this port number using a hostname.

Listing 1.1 below shows all the namespaces we need to include in our project.

Listing 1.1

C#
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Text.RegularExpressions;

Now that we have included the required namespaces, let’s start coding by declaring all the classes we need. Listing 1.2 below shows all the classes we need to declare.

Listing 1.2

C#
private TcpClient _imapClient;
private NetworkStream _imapNs;
private StreamWriter _imapSw;
private StreamReader _imapSr;

We are going to use the TcpClient class to connect to the mailbox server on port 143. Examine the InitializeConnection() method in listing 1.3 below.

Listing 1.3

C#
private void InitializeConnection(string hostname, int port)
{
    try
    {
        _imapClient = new TcpClient(hostname, port);
        _imapNs = _imapClient.GetStream();
        _imapSw = new StreamWriter(_imapNs);
        _imapSr = new StreamReader(_imapNs);

        Console.WriteLine("*** Connected ***");
        Response();
    }
    catch (SocketException ex)
    {
        Console.WriteLine(ex.Message);
    }
}

The InitializeConnection() method takes two arguments, the mailbox hostname and the port number. A TcpClient is instantiated, and the NetworkStream class is used to read and write to the stream. A SocketExeption will be raised if the _imapClient object is unable to connect to the mailbox server.

After successfully connecting to the mailbox server, the server will respond with a message. This is usually an “OK” message indicating that you have connected to the server. The code in Listing 1.4 below shows a very simple method to receive data from the mailbox server.

Listing 1.4

C#
private string Response()
{
    byte[] data = new byte[_imapClient.ReceiveBufferSize];
    int ret = _imapNs.Read(data, 0, data.Length);
    return Encoding.ASCII.GetString(data).TrimEnd();
}

Every time we send a command to the mailbox server, we will use the above Response() method to get the response data from the mailbox server. After getting a response from the server, we need to login using our login credentials.

Login command

The first command we will send to the mailbox server is the login command. Listing 1.5 below is the AuthenticateUser() method, which takes two arguments, the username and the password.

Listing 1.5

C#
public void AuthenticateUser(string username, string password)
{
    _imapSw.WriteLine("$ LOGIN " + username + " " + password);
    _imapSw.Flush();
    Response();
}

The above AuthenticateUser() method sends a “LOGIN” command to the mailbox server. The structure of this command is shown below.

PREFIX LOGIN USERNAME PASSWORD

Each command is followed by a prefix. In the AuthenticateUser() method, the prefix used is the $ symbol. You can use a different prefix of your own, but some characters such as * will not work. Take notice of the Response() method which is being called from the AuthenticateUser() method. As I mentioned earlier, every time we send a command to the mailbox server, we need to get the response from the server. You can print the response to the console, but I decided not to do this.

If the supplied username and password are successfully authenticated, the server will respond with a message such as "$ OK User Loged In". Notice the prefix at the beginning of the message. This prefix will be the prefix you are using.

If, however, your login credentials are not authenticated, the server will respond with a message such as "$ NO Login failed: authentication failure". Using the server's response message, you can do your own exception handling. You can read the first four characters from the response, and determine if the response was an OK or a NO, in which case you can inform the user.

After successful authentication, we can perform a number of tasks, such as get the total number of messages. The MailCount() method in listing 1.6 sends a command to examine the INBOX folder and get the total message count from the server.

Listing 1.6

C#
public int MailCount()
{
    _imapSw.WriteLine("$ STATUS INBOX (messages)");
    _imapSw.Flush();

    string res = Response();
    Match m = Regex.Match(res, "[0-9]*[0-9]");
    return Convert.ToInt32(m.ToString());
}

The STATUS command takes two arguments. The first is the folder, and the second is what is known as a flag. The flag (messages) indicates that you want to get the total number of messages in the inbox. If the command was executed successfully, the server will respond with a message similar to the following:

* STATUS INBOX (MESSAGES 3)

Notice that the server has responded with the total message count in the INBOX folder; in the above response, the total message count is 3. We can also find out how many new messages there are in the inbox. The MailUnreadCount() in listing 1.7 below sends a STATUS command, but it sends an (unseen) flag. This flag tells the mailbox server to return the total count of unread messages.

Listing 1.7

C#
public int MailUnreadCount()
{
    _imapSw.WriteLine("$ STATUS INBOX (unseen)");
    _imapSw.Flush();

    string res = Response();
    Console.WriteLine(res);
    Match m = Regex.Match(res, "[0-9]*[0-9]");
    return Convert.ToInt32(m.ToString());
}

It is time to get some messages from the mailbox server. Before we begin to fetch any messages, we must first select the folder to retrieve the messages from. The SelectInbox() method selects the INBOX folder. After selecting the INBOX folder, we can begin to get messages. Listing 1.8 below sends the SELECT command to the server to select the INBOX folder.

Listing 1.8

C#
public void SelectInbox()
{
    _imapSw.WriteLine("$ SELECT INBOX");
    _imapSw.Flush();
    Response();
}

Finally, we can now send a command to get a single message from the mailbox sever. The command used to get a message is the FETCH command. This command takes two arguments: the first is the message number to retrieve, and the second is a combination of message flags. The GetMessageHeaders () method in Listing 1.9 below takes a single argument of type int.

Listing 1.9

C#
public object GetMessageHeaders(int index)
{
    _imapSw.WriteLine("$ FETCH " + index + 
                      " (body[header.fields (from subject date)])");
    _imapSw.Flush();

    return Response();
}

The above method GetMessageHeaders() sends a FETCH command to the mailbox server, and only gets the from, subject, and date fields from the header of a selected message. This is useful if you want to display messages in a list control to show all the messages, but not the message body.

To get the body of the email, you need to send the FETCH command to the server, but you use the body[text] flag. Listing 2.0 below shows the command to get the message body.

Listing 2.0

C#
public object GetMessage(int index)
{
    _imapSw.WriteLine("$ FETCH " + index + " body[text]");
    _imapSw.Flush();

    return Response();
}

Finally, after we have finished with the mailbox server, we need to logout. This is as easy as sending a LOGOUT command to the server. Listing 2.1 below shows the Disconnect() method which sends a logout command to the mailbox server.

Both the GetMessageHeaders() and GetMessage() methods will return a response which is not formatted. You will need to format the response from the server, and add your own error handling by handling exceptions. To keep the code simple, I have not added any exception handling.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Web Developer
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralRe: Googlemail Access Pin
Syed M Hussain22-Dec-09 0:34
Syed M Hussain22-Dec-09 0:34 
GeneralRe: Googlemail Access Pin
Jayyyman22-Dec-09 1:10
Jayyyman22-Dec-09 1:10 
QuestionRe: Googlemail Access Pin
Md Nasir Uddin (Nahid)8-Mar-11 0:01
Md Nasir Uddin (Nahid)8-Mar-11 0:01 
Generalnot getting response Pin
GourviWasson6-Aug-09 18:29
GourviWasson6-Aug-09 18:29 
GeneralRe: not getting response Pin
SnufflezLee21-Oct-09 0:29
SnufflezLee21-Oct-09 0:29 
QuestionCan't we access tasks, contacts and other like calendar events? Pin
Sree12424-Mar-09 4:21
Sree12424-Mar-09 4:21 
AnswerRe: Can't we access tasks, contacts and other like calendar events? Pin
bob_b30-Jun-09 21:48
bob_b30-Jun-09 21:48 
GeneralImprovements Pin
Ian MacLean24-Sep-08 13:27
Ian MacLean24-Sep-08 13:27 
This was a very good start for a minimal imap client. most others that i've found are a bit bloated.

this code could have been better written, sure, but there was only one glaring technical fault that i found in it. in the original code, every time a command was written, a single line was returned as the server response. but that was bad for a two reasons that i can think of. for starters, some of the commands sent did NOT return simple one-line responses (you would have to keep reading the lines until you get the line that starts off with the same command prefix. that's the signal that the command completed.) secondly, for the commands where the server sends multiple line responses, since the original code only read one line responses for each command, the buffer would often fill up with unread information. that only became a problem when you would go to execute the next command -- you would return with responses from the last command executed! that most definitely threw me off.

private List<string> VerifyWrite(string msg)
{
	writer.WriteLine(msg); writer.Flush();
	Console.WriteLine(msg);

	List<string> resps = new List<string>();
	while(true)
	{
		string ln = reader.ReadLine();
		resps.Add(ln);
		Console.WriteLine(ln);

		//wait until server finishes executing current command
		//checks prefix of the current response line
		if (ln.StartsWith(msg.Substring(0, msg.IndexOf(' '))))
			break;
	}

	return resps;
}</string></string></string>


i basically just took out the read / write methods and put them in a single one that does all the work anyway.
GeneralRe: Improvements Pin
Claudio Nicora29-Sep-08 20:52
Claudio Nicora29-Sep-08 20:52 
GeneralRe: Improvements Pin
shahinhr11-Mar-14 4:47
shahinhr11-Mar-14 4:47 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.