Posts Tagged ‘IMAP’

POP3 vs IMAP

Thursday, August 5th, 2010

POP3 and IMAP are application-layer Internet standard protocols used by local e-mail clients to retrieve e-mails from a remote server over a TCP/IP connection. Virtually all modern e-mail clients and mail servers support both protocols as a means of transferring e-mail messages from a server.

They are both text-based. Both transmit more or less same amount of data.

Here is the brief comparison of both:

POP3 IMAP
Intended message store Client Server
Download message YES YES
Download message headers YES YES
Download specific message part (single attachment) NO YES
Delete message YES YES
Send message NO (use SMTP) NO (use SMTP)
Get only unseen messages NO YES
Mark message Seen/Unseen NO YES
Server side search NO YES
Folders NO YES
Sent items NO YES
SSL YES YES
Push email NO YES

Mail.dll supports both POP3 and IMAP (and SMTP), give it a try at:
http://www.lesnikowski.com/mail/

The handshake failed due to an unexpected packet format

Monday, July 26th, 2010

Most likely your server requires implicit SSL. So first try to connect without SSL:

// C#

client.Connect("imap.example.com");
' VB.NET

client.Connect("imap.example.com");

Then, before logging-in, start implicit SSL negotiation. The command name differs for different protocols:

In case of IMAP:

// C#

client.StartTLS();
' VB.NET

client.StartTLS()

In case of POP3:

// C#

client.STLS();
' VB.NET

client.STLS()

In case of SMTP:

// C#

client.StartTLS();
' VB.NET

client.StartTLS()

Now, your connection is secured.

Remember that you can ignore SSL certificate errors using ServerCertificateValidate event:

// C#

client.ServerCertificateValidate +=
    (sender, e) => { e.IsValid = true; };
' VB.NET

client.ServerCertificateValidate += Function(sender, e) Do
	e.IsValid = True
End Function

Download parts of email message

Thursday, July 8th, 2010

Some times you know you’ll receive large emails, and you only need to access some parts without downloading entire messages .

Mail.dll .NET IMAP client allows you to download only needed parts of the specified message.

First you need to get the structure of the message.
There are two methods for that: GetBodyStructureByUID and GetBodyStructure.

BodyStructure contains information about plain text, html, and all attachments of the message. It does not contain any data though.

To download text parts of the email (like html or plain text) you can use: GetMimePartTextByUID or GetMimePartText.

To download attachments use: GetMimePartByUID or GetMimePart.

Here’s the full sample for this feature:

// C#

using(Imap imap = new Imap())
{
	imap.Connect("imap.server.com");
	imap.Login("user", "password");

	imap.SelectInbox();
	List<long> uidList = imap.SearchFlag(Flag.Unseen);
	foreach (long uid in uidList)
	{
		// Get the structure of the email
		BodyStructure structure = imap.GetBodyStructureByUID(uid);

		// Download only text and html parts
		string text = imap.GetMimePartTextByUID(uid, structure.Text);
		string html = imap.GetMimePartTextByUID(uid, structure.Html);

		Console.WriteLine(text);
		Console.WriteLine(html);

		// Show all attachments' filenames
		foreach(MimeStructure attachment in structure.Attachments)
		{
			Console.WriteLine(attachment.FileName);
			// You can also download entire attachment
			byte[] bytes = imap.GetMimePartByUID(uid, attachment);
		}
	}
	imap.Close(true);
}
' VB.NET

Using imap As New Imap()
	imap.Connect("imap.server.com")
	imap.Login("user", "password")

	imap.SelectInbox()
	Dim uidList As List(Of Long) = imap.SearchFlag(Flag.Unseen)
	For Each uid As Long In uidList
		' Get the structure of the email
		Dim struct As BodyStructure = imap.GetBodyStructureByUID(uid)

		' Download only text and html parts
		Dim text As String = imap.GetMimePartTextByUID(
			uid, struct.Text)
		Dim html As String = imap.GetMimePartTextByUID(
			uid, struct.Html)

		Console.WriteLine(text)
		Console.WriteLine(html)

		' Show all attachments' filenames
		For Each attachment As MimeStructure In struct.Attachments
			Console.WriteLine(attachment.FileName)
			' You can also download entire attachment
			Dim bytes As Byte() = imap.GetMimePartByUID(
				uid, attachment)
		Next
	Next
	imap.Close(True)
End Using

Peek message on IMAP server

Tuesday, July 6th, 2010

When you access messages stored on IMAP server, it automatically adds \Seen flag to the messages you have downloaded.

If you don’t want this behavior, there are two things you can do.

First is to use Examine method instead of Select:

// C#

using(Imap imap = new Imap())
{
    imap.Connect("imap.server.com");
    imap.Login("user", "password");

    imap.ExamineInbox(); // -or- imap.Examine("Inbox");

    // ...

    imap.Close(true);
}
' VB.NET

Using imap As New Imap
    imap.Connect("imap.server.com")
    imap.Login("user", "password")

    imap.SelectInbox()

    imap.ExamineInbox() ' -or- imap.Examine("Inbox")

    ' ...

    imap.Close(True)
End Using

Examine puts mailbox (also called folder) into read-only state, so no \Seen flag is added.
The drawback is that you can not delete a message.

Second approach is to use one of the Peek methods on the IMAP client:

// C#

using(Imap imap = new Imap())
{
    imap.Connect("imap.server.com");
    imap.Login("user", "password");

    imap.SelectInbox();
    List<long> uidList = imap.SearchFlag(Flag.Unseen);
    foreach (long uid in uidList)
    {
        IMail email = new MailBuilder()
            .CreateFromEml(imap.PeekMessageByUID(uid));
        Console.WriteLine(email.Subject);
    }
    imap.Close(true);
}
' VB.NET

Using imap As New Imap
    imap.Connect("imap.server.com")
    imap.Login("user", "password")

    imap.SelectInbox()
    Dim uidList As List(Of Long) = imap.SearchFlag(Flag.Unseen)

    For Each uid As Long In uidList
        Dim email As IMail = New MailBuilder() _
            .CreateFromEml(imap.PeekMessageByUID(uid))
        Console.WriteLine(email.Subject)
    Next
    imap.Close(True)
End Using

There are Peek methods for downloading headers and even parts of the email message.

You can download Mail.dll IMAP client here.

OAuth with IMAP

Monday, June 28th, 2010

OAuth is an open protocol to allow secure API authorization in a simple and standard method from desktop and web applications.

In this post I’ll show how to access GMail account using OAuth authentication method. The key advantage of this method is that it allows an application to access users email without knowing user’s password.

You can read more on OAuth authentication with Google accounts here:
http://code.google.com/apis/accounts/docs/OAuth_ref.html

Gmail IMAP and SMTP using OAuth:
http://code.google.com/apis/gmail/oauth/protocol.html

If your application is not registered, please select HMAC-SHA1 and use the following key and secret:
consumer key: “anonymous”
consumer secret: “anonymous”

You can manage your domains here:
https://www.google.com/accounts/ManageDomains

The following code makes several HTTP requests to authenticate your application. It also fires up the web browser, so the user can allow or deny the application to access his emails.

const string userEmailAccount = "alice@gmail.com";
const string consumerKey = "anonymous";
const string consumerSecret = "anonymous";

// First: get request token
ParameterList parameters1 = OAuth.ForUrl(
        "https://www.google.com/accounts/OAuthGetRequestToken")
    .Consumer(consumerKey, consumerSecret)
    .AddParameter("scope", "https://mail.google.com/")
    .AddParameter(OAuthParameterName.OAuthCallback, "oob")
    .Sign()
    .ExecuteWebRequest();

// Second: user interaction
string url2 = OAuth.ForUrl(
        "https://www.google.com/accounts/OAuthAuthorizeToken")
   .Consumer(consumerKey, consumerSecret)
   .Token(parameters1.GetValue(OAuthParameterName.OAuthToken))
   .TokenSecret(parameters1.GetValue(OAuthParameterName.OAuthTokenSecret))
   .Sign()
   .GetUrl();

// Fire up the browser
Process.Start(url2);
Console.WriteLine("Please enter the key: ");
string key = Console.ReadLine().Trim();

// Third: get access token
ParameterList parameters3 = OAuth.ForUrl(
        "https://www.google.com/accounts/OAuthGetAccessToken")
   .Consumer(consumerKey, consumerSecret)
   .Token(parameters1.GetValue(OAuthParameterName.OAuthToken))
   .TokenSecret(parameters1.GetValue(OAuthParameterName.OAuthTokenSecret))
   .AddParameter("oauth_verifier", key)
   .Sign()
   .ExecuteWebRequest();

// Log-in to IMAP server using XOAuth
using (Imap client = new Imap())
{
    client.ConnectSSL(TestConstants.GmailImapServer);

    string imapUrl = string.Format(
        "https://mail.google.com/mail/b/{0}/imap/", userEmailAccount);

    string oauthImapKey = OAuth.ForUrl(imapUrl)
        .Consumer(consumerKey, consumerSecret)
        .Token(parameters3.GetValue(OAuthParameterName.OAuthToken))
        .TokenSecret(parameters3.GetValue(OAuthParameterName.OAuthTokenSecret))
        .Sign()
        .GetXOAuthKey();

    client.LoginOAUTH(oauthImapKey);

    // Now you can access user's emails.

    client.Close(true);
}