Quantcast
Channel: Blog | Limilabs
Viewing all articles
Browse latest Browse all 120

Get new emails using IMAP

$
0
0

This article describes how to receive new email messages using Mail.dll .NET IMAP library.

In many situations you can relay on IMAP server to keep track which messages are unseen and just download unseen messages from IMAP server. However when user interaction or other program connecting and downloading emails may remove UNSEEN flag from the message, you may be forced to manually track which messages where already downloaded and which are new.

You could of course download all Unique IDs (UIDs) of the messages that are in the mailbox, but there is a more elegant way.

Unique IDs (UIDs) in IMAP have some very interesting feature – they are assigned in incremental order. This means that new messages always have higher UIDs than old ones.

This is the reason you only need to remember the newest (greatest) UID that was downloaded during a previous session (connection to the IMAP server). On the next session you need to search IMAP for UIDs that are greater than the one remembered.

First we need to load largest uid from the previous session and connect to the IMAP server. In this exmaple we select INBOX, but you can use Select method to select different folder.

// C#

long largestUID = LoadLargestFromPreviousRun();

using (Imap imap = new Imap ())
{
    imap.Connect("imap.example.com");  // or ConnectSSL for SSL
    imap.Login("user", "password");

    imap.SelectInbox();
' VB.NET

Dim largestUID As Long = LoadLargestFromPreviousRun()

Using imap As New Imap ()
    imap.Connect("imap.example.com")   ' or ConnectSSL for SSL
    imap.Login("user", "password")

    imap.SelectInbox()

Next step is to select folder, download unique ids (UIDs) larger than largestUID value that was stored on the previous run. This way we obtain uids of the new emails.

// C#

List<long> uids = imap.Search().Where( _
    Expression.UID(Range.From(largestUID + 1)));

' VB.NET

Dim uids As List(Of Long) = imap.Search().Where(
    Expression.UID(Range.From(largestUID + 1)))

You should note +1 in the code above. It is used because Range.From creates a range of uids greater or equal to the specified value.

Finally we’ll iterate through the UID list and use GetMessageByUID method to download each message from the server. You can use MailBuilder class to parse those email messages, extract attachments and process them anyway you like. The last step is to save the last UID that was processed:

// C#

foreach (long uid in uids)
{
    string eml = imap.GetMessageByUID(uid);
    IMail email = new MailBuilder().CreateFromEml(eml);

    Console.WriteLine(email.Subject);
    Console.WriteLine(email.Text);
   
    SaveLargestUID(uid);
}
' VB.NET

For Each uid As Long In uids
	Dim eml As String = imap.GetMessageByUID(uid)
	Dim email As IMail = New MailBuilder().CreateFromEml(eml)

	Console.WriteLine(email.Subject)
	Console.WriteLine(email.Text)

	SaveLargestUID(uid)
Next

UIDs across sessions – UIDValidity

It is advised for IMAP servers to not change UIDs between sessions. There are however situations when server may invalidate all UIDs that were in the mailbox previously.

Consider a user that deletes a folder (mailbox) including all its messages and creates new one with exactly the same name. All uids that were downloaded previously are no longer valid – they simply don’t exist in this folder anymore.

You can recognize such situation by comparing FolderStatus.UIDValidity value. If the FolderStatus.UIDValidity number hasn’t changed, then the UIDs are still valid. Below is the sample showing how to print UIDValidity:

// C#

FolderStatus status = client.SelectInbox();
Console.WriteLine(status.UIDValidity);

' VB.NET

Dim status As FolderStatus = client.SelectInbox()
Console.WriteLine(status.UIDValidity)

Entire samples

Below you can find full samples in both C# and VB.NET:

// C#

using Limilabs.Mail;
using Limilabs.Client.IMAP;

internal class LastRun
{
    public long UIDValidtiy { get; set; }
    public long LargestUID { get; set; }
}

private static void Main(string[] args)
{
    LastRun last = LoadPreviousRun();

    using (Imap imap = new Imap())
    {
        imap.Connect("imap.example.com"); // or ConnectSSL for SSL
        imap.Login("user", "password");

        FolderStatus status = imap.SelectInbox();

        List<long> uids;
        if (status.UIDValidity == last.UIDValidtiy)
        {
            uids = imap.Search().Where(
                Expression.UID(Range.From(last.LargestUID + 1)));
        }
        else
        {
            uids = imap.GetAll();
        }

        foreach (long uid in uids)
        {
            string eml = imap.GetMessageByUID(uid);
            IMail email = new MailBuilder()
                .CreateFromEml(eml);

            Console.WriteLine(email.Subject);
            Console.WriteLine(email.Text);

            LastRun current = new LastRun
                                  {
                                      UIDValidtiy = status.UIDValidity, 
                                      LargestUID = uid
                                  };
            SaveThisRun(current);
        }
        imap.Close();
    }
}
' VB.NET

Imports Limilabs.Mail
Imports Limilabs.Client.IMAP

Friend Class LastRun
	Public Property UIDValidtiy() As Long
		Get
			Return m_UIDValidtiy
		End Get
		Set
			m_UIDValidtiy = Value
		End Set
	End Property
	Private m_UIDValidtiy As Long
	Public Property LargestUID() As Long
		Get
			Return m_LargestUID
		End Get
		Set
			m_LargestUID = Value
		End Set
	End Property
	Private m_LargestUID As Long
End Class

Private Shared Sub Main(args As String())
    Dim last As LastRun = LoadPreviousRun()

    Using imap As New Imap()
        imap.Connect("imap.example.com")		' or ConnectSSL for SSL
        imap.Login("user", "password")

        Dim status As FolderStatus = imap.SelectInbox()

        Dim uids As List(Of Long)
        If status.UIDValidity = last.UIDValidtiy Then
            uids = imap.Search().Where( _
                Expression.UID(Range.From(last.LargestUID + 1)))
        Else
            uids = imap.GetAll()
        End If

        For Each uid As Long In uids
            Dim eml As String = imap.GetMessageByUID(uid)
            Dim email As IMail = New MailBuilder().CreateFromEml(eml)

            Console.WriteLine(email.Subject)
            Console.WriteLine(email.Text)

            Dim current As New LastRun() With { _
                .UIDValidtiy = status.UIDValidity, _
                .LargestUID = uid _
            }
            SaveThisRun(current)
        Next
        imap.Close()
    End Using
End Sub

Viewing all articles
Browse latest Browse all 120

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>