Posts Tagged ‘IMAP’

2-legged OAuth with Gmail

Friday, October 21st, 2011

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 2-legged OAuth authentication method. The basic idea is that domain administrator can use this method to access user 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

Remember to add reference to Mail.dll and appropriate namespaces.

// C#

using Limilabs.Client.IMAP;
using Limilabs.Client.Authentication;
using Limilabs.Client.Authentication.Google;

const string consumerKey = "example.com";
const string consumerSecret = "secret";
const string email = "pat@example.com";

Gmail2LeggedOAuth oauth = new Gmail2LeggedOAuth(
    consumerKey, consumerSecret);

using (Imap client = new Imap())
{
    client.ConnectSSL("imap.gmail.com");

    string oauthImapKey = oauth.GetXOAuthKeyForImap(email);

    client.LoginOAUTH(oauthImapKey);

    //...

    client.Close();
}
' VB.NET

Imports Limilabs.Client.IMAP
Imports Limilabs.Client.Authentication
Imports Limilabs.Client.Authentication.Google

Const  consumerKey As String = "example.com"
Const  consumerSecret As String = "secret"
Const  email As String = "pat@example.com"

Dim oauth As New Gmail2LeggedOAuth(consumerKey, consumerSecret)

Using client As New Imap()
	client.ConnectSSL("imap.gmail.com")

	Dim oauthImapKey As String = oauth.GetXOAuthKeyForImap(email)

	client.LoginOAUTH(oauthImapKey)

	'...

	client.Close()
End Using

Here are the google apps configuration screens:

Get supported authentication methods (IMAP, POP3, SMTP)

Thursday, October 6th, 2011

You can use SupportedAuthenticationMethods to retrieve all authentication methods supported by the server:

// C#

using (Imap client = new Imap())
{
    client.ConnectSSL("imap.example.org");
    client.UseBestLogin("user", "password");

    Console.WriteLine("Supported methods:");

    foreach (var method in client.SupportedAuthenticationMethods())
    {
        Console.WriteLine(method.Name);
    }

    Console.WriteLine("Supports CramMD5:");

    bool supportsCramMD5 = client.SupportedAuthenticationMethods()
        .Contains(ImapAuthenticationMethod.CramMD5);

    Console.WriteLine(supportsCramMD5);

    client.Close();
}
' VB.NET

Using client As New Imap()
    client.ConnectSSL("imap.example.org")
    client.UseBestLogin("user", "password")

    Console.WriteLine("Supported methods:")

    For Each method As ImapAuthenticationMethod In client.SupportedAuthenticationMethods()
	    Console.WriteLine(method.Name)
    Next

    Console.WriteLine("Supports CramMD5:")

    Dim supportsCramMD5 As Boolean = client.SupportedAuthenticationMethods() _
        .Contains(ImapAuthenticationMethod.CramMD5)

    Console.WriteLine(supportsCramMD5)

    client.Close()
End Using

For example Gmail produces following output:

Supported method s:
IMAP4rev1
UNSELECT
IDLE
NAMESPACE
QUOTA
ID
XLIST
CHILDREN
X-GM-EXT-1
UIDPLUS
COMPRESS

Supports CramMD5:
False

We take great care for the API to look similar for all protocols (IMAP, POP3, SMTP).

Here’s the sample for POP3:

// C#

using (Pop3 client = new Pop3())
{
    client.ConnectSSL("pop3.example.org");
    client.UseBestLogin("user", "password");

    Console.WriteLine("Supported methods:");

    foreach (var method in client.SupportedAuthenticationMethods())
    {
        Console.WriteLine(method.Name);
    }

    Console.WriteLine("Supports CramMD5:");

    bool supportsCramMD5 = client.SupportedAuthenticationMethods()
        .Contains(Pop3AuthenticationMethod.CramMD5);

    Console.WriteLine(supportsCramMD5);

    client.Close();
}
' VB.NET

Using client As New Pop3()
    client.ConnectSSL("pop3.example.org")
    client.UseBestLogin("user", "password")

    Console.WriteLine("Supported methods:")

    For Each method As Pop3AuthenticationMethod In client.SupportedAuthenticationMethods()
	    Console.WriteLine(method.Name)
    Next

    Console.WriteLine("Supports CramMD5:")

    Dim supportsCramMD5 As Boolean = client.SupportedAuthenticationMethods() _
        .Contains(Pop3AuthenticationMethod.CramMD5)

    Console.WriteLine(supportsCramMD5)

    client.Close()
End Using

Here’s the sample for SMTP:

// C#

using (Smtpclient = new Smtp())
{
    client.Connect("smtp.example.org");
    client.UseBestLogin("smtp", "password");

    Console.WriteLine("Supported methods:");

    foreach (var method in client.SupportedAuthenticationMethods())
    {
        Console.WriteLine(method.Name);
    }

    Console.WriteLine("Supports CramMD5:");

    bool supportsCramMD5 = client.SupportedAuthenticationMethods()
        .Contains(SmtpAuthenticationMethod.CramMD5);

    Console.WriteLine(supportsCramMD5);

    client.Close();
}
' VB.NET

Using client As New Smtp()
    client.Connect("smtp.example.org")
    client.UseBestLogin("user", "password")

    Console.WriteLine("Supported methods:")

    For Each method As SmtpAuthenticationMethod In client.SupportedAuthenticationMethods()
	    Console.WriteLine(method.Name)
    Next

    Console.WriteLine("Supports CramMD5:")

    Dim supportsCramMD5 As Boolean = client.SupportedAuthenticationMethods() _
        .Contains(SmtpAuthenticationMethod.CramMD5)

    Console.WriteLine(supportsCramMD5)

    client.Close()
End Using

Get supported server extensions (IMAP, POP3, SMTP)

Thursday, October 6th, 2011

Not every server supports same extensions. There are 3 classes that represent server extensions for each email protocol: ImapExtension, Pop3Extension and SmtpExtension. Those classes contain static properties with well-know extensions like: ImapExtension.Idle or ImapExtension.Sort or Pop3Extension.STLS etc.

You can use SupportedExtensions method to retrieve all protocol extensions supported by the server.

Get supported IMAP server extensions

// C#

using (Imap client = new Imap())
{
    client.ConnectSSL("imap.example.org");
    client.UseBestLogin("user", "password");

    Console.WriteLine("Supported extensions:");

    foreach (ImapExtension extension in client.SupportedExtensions())
    {
        Console.WriteLine(extension.Name);
    }

    Console.WriteLine("Supports IDLE:");

    bool supportsIdle = client.SupportedExtensions()
        .Contains(ImapExtension.Idle);

    Console.WriteLine(supportsIdle);

    client.Close();
}
' VB.NET

Using client As New Imap()
    client.ConnectSSL("imap.example.org")
    client.UseBestLogin("user", "password")

    Console.WriteLine("Supported extensions:")

    For Each extension As ImapExtension In client.SupportedExtensions()
	    Console.WriteLine(extension.Name)
    Next

    Console.WriteLine("Supports IDLE:")

    Dim supportsIdle As Boolean = client.SupportedExtensions() _
        .Contains(ImapExtension.Idle)

    Console.WriteLine(supportsIdle)

    client.Close()
End Using

For example Gmail produces following output:

Supported extensions:
IMAP4rev1
UNSELECT
IDLE
NAMESPACE
QUOTA
ID
XLIST
CHILDREN
X-GM-EXT-1
UIDPLUS
COMPRESS

Supports IDLE:
True

We take great care for the API to look similar for all protocols (IMAP, POP3, SMTP).

Get supported POP3 server extensions

// C#

using (Pop3 client = new Pop3())
{
    client.ConnectSSL("pop3.example.org");
    client.UseBestLogin("user", "password");

    Console.WriteLine("Supported extensions:");

    foreach (Pop3Extension extension in client.SupportedExtensions())
    {
        Console.WriteLine(extension.Name);
    }

    Console.WriteLine("Supports TOP:");

    bool supportsTop= client.SupportedExtensions()
        .Contains(Pop3Extension.Top);

    Console.WriteLine(supportsTop);

    client.Close();
}
' VB.NET

Using client As New Pop3()
    client.ConnectSSL("pop3.example.org")
    client.UseBestLogin("user", "password")

    Console.WriteLine("Supported extensions:")

    For Each extension As Pop3Extension In client.SupportedExtensions()
	    Console.WriteLine(extension.Name)
    Next

    Console.WriteLine("Supports TOP:")

    Dim supportsTop As Boolean = client.SupportedExtensions() _
        .Contains(Pop3Extension.Top)

    Console.WriteLine(supportsTop)

    client.Close()
End Using

Get supported SMTP server extensions

// C#

using (Smtpclient = new Smtp())
{
    client.Connect("smtp.example.org");
    client.UseBestLogin("smtp", "password");

    Console.WriteLine("Supported extensions:");

    foreach (SmtpExtension  extension in client.SupportedExtensions())
    {
        Console.WriteLine(extension.Name);
    }

    Console.WriteLine("Supports STARTTLS:");

    bool supportsStartTLS = client.SupportedExtensions()
        .Contains(SmtpExtension.StartTLS);

    Console.WriteLine(supportsStartTLS);

    client.Close();
}
' VB.NET

Using client As New Smtp()
    client.Connect("smtp.example.org")
    client.UseBestLogin("user", "password")

    Console.WriteLine("Supported extensions:")

    For Each extension As SmtpExtension In client.SupportedExtensions()
	    Console.WriteLine(extension.Name)
    Next

    Console.WriteLine("Supports STARTTLS:")

    Dim supportsStartTLS As Boolean = client.SupportedExtensions() _
        .Contains(SmtpExtension.StartTLS)

    Console.WriteLine(supportsStartTLS)

    client.Close()
End Using

Remove attachments from email

Thursday, October 6th, 2011

First I want to make one thing clear, neither POP3 nor IMAP protocols does not provide any way to remove attachments from existing emails.
This is because email stored on the server is immutable.
With IMAP protocol you can copy it to different folder, you can apply some flags (SEEN) to it, but you can’t change any part of the message.

The second important thing is that attachments are not stored separately from the message text and headers – they are embedded inside the email.

Nevertheless Mail.dll provides an easy way to create new email without the attachments from existing email message.

// C#

IMail original = new MailBuilder().CreateFromEml(eml);
IMail email = original.RemoveAttachments().Create();
' VB.NET

Dim original As IMail = New MailBuilder().CreateFromEml(eml)
Dim email As IMail = original.RemoveAttachments().Create()

RemoveAttachments method also has an overloaded version that allows to remove only visual (content-disposition: inline) or/and non-visual (content-disposition: attachment) attachments:

// C#

MailBuilder RemoveAttachments();

MailBuilder RemoveAttachments(
    bool removeVisuals,
    bool removeNonVisuals);
' VB.NET

Function RemoveAttachments() As MailBuilder

Function RemoveAttachments( _
    removeVisuals As Boolean, _
    removeNonVisuals As Boolean) As MailBuilder

The following example illustrates the full process of downloading email from IMAP server,
creating new email, with the same information, but without attachments, and finally uploading it, and removing the original message:

// C#

using(Imap imap = new Imap())
{
    imap.ConnectSSL("imap.example.org");
    imap.UseBestLogin("user", "password");
    imap.SelectInbox();

    foreach (long uid in imap.GetAll())
    {
        string eml = imap.GetMessageByUID(uid);
        IMail original = new MailBuilder().CreateFromEml(eml);
        if (original.Attachments.Count > 0)
        {
            IMail email = original.RemoveAttachments().Create();

            imap.UploadMessage("Inbox", email);

            imap.DeleteMessageByUID(uid);
        }
    }
    imap.Close();
}
' VB.NET

Using imap As New Imap()
   imap.ConnectSSL("imap.example.org")
   imap.UseBestLogin("user", "password")
   imap.SelectInbox()

   For Each uid As Long In imap.GetAll()
      Dim eml As String = imap.GetMessageByUID(uid)
      Dim original As IMail = New MailBuilder().CreateFromEml(eml)
      If original.Attachments.Count > 0 Then
         Dim email As IMail = original.RemoveAttachments().Create()

         imap.UploadMessage("Inbox", email)

         imap.DeleteMessageByUID(uid)
      End If
   Next
   imap.Close()
End Using

Create Gmail url-ID via IMAP

Tuesday, August 30th, 2011

This is Gmail link that points to certain conversation (entire thread):

https://mail.google.com/mail/u/0/#inbox/13216515baefe747

“13216515baefe747″ is the Gmail thread-ID in hex.

Here’s the code that:

  1. Selects “All Mail” folder
  2. Gets the newest message UID
  3. Obtains Gmail thread ID for this message (X-GM-THRID)
  4. Converts it to hex
  5. Creates the url that points to the Gmail conversation
// C# version

using (Imap client = new Imap())
{
    client.ConnectSSL("imap.gmail.com");
    client.Login("pat@gmail.com", "password");

    // Select 'All Mail' folder
    CommonFolders common = new CommonFolders(client.GetFolders());
    client.Select(common.AllMail);

    // get IMAP uid of the newest message
    long lastUid = client.GetAll().Last();

    // get message info
    MessageInfo info = client.GetMessageInfoByUID(lastUid);

    // extract Gmail thread ID
    Int64 threadId = Int64.Parse(info.Envelope.GmailThreadId);
    string threadIdAsHex = threadId.ToString("X");

    // create url
    string url = string.Format(
        "https://mail.google.com/mail/u/0/#inbox/{0}",
        threadIdAsHex);

    Console.WriteLine(url);

    client.Close();
}
' VB.NET version

Using client As New Imap()
	client.ConnectSSL("imap.gmail.com")
	client.Login("pat@gmail.com", "password")

	' Select 'All Mail' folder
	Dim common As New CommonFolders(client.GetFolders())
	client.Select(common.AllMail)

	' get IMAP uid of the newest message
	Dim lastUid As Long = client.GetAll().Last()

	' get message info
	Dim info As MessageInfo = client.GetMessageInfoByUID(lastUid)

	' extract Gmail thread ID
	Dim threadId As Int64 = Int64.Parse(info.Envelope.GmailThreadId)
	Dim threadIdAsHex As String = threadId.ToString("X")

	' create url
	Dim url As String = String.Format( _
		"https://mail.google.com/mail/u/0/#inbox/{0}", _
		threadIdAsHex)

	Console.WriteLine(url)

	client.Close()
End Using

Here you can find some more information about how to search by X-GM-THRID and all other Gmail IMAP extensions.