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