Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

How to Access Emails Using the IMAP Protocol

4.53/5 (26 votes)
26 May 2014GPL36 min read 1   7.8K  
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)