IMAP IDLE: instant push email notifications
IDLE is an IMAP protocol extension described in RFC 2177. It allows an IMAP client to indicate to the server that it is ready to accept real-time notifications about changes (e.g new message) in the currently selected folder.
This feature is not available for every IMAP server. You need to check if your IMAP server supports ImapExtension.Idle extension.
Mail.dll IMAP client supports IDLE command.
There are two Imap class methods, that allow client to receive notifications:
- Idle() – starts accepting real-time notifications. The method hangs until new notification is received.
- StopIdle() – stops accepting real-time notifications.
The following sample connects to IMAP server and starts to receive notifications. When new message arrives (or an old message is deleted) it displays new message count. Then searches IMAP server for unseen messages, downloads them, and displays subjects of all new messages.
using (Imap client = new Imap())
{
client.ConnectSSL("imap.server.com");
client.Login("user@server.com", "password");
FolderStatus folderStatus = client.SelectInbox();
Console.WriteLine("Total message count: {0}",
folderStatus.MessageCount);
while(true)
{
FolderStatus currentStatus = client.Idle();
Console.WriteLine("Total message count: {0}",
currentStatus.MessageCount);
foreach(long uid in client.Search(Flag.Unseen))
{
IMail email = new MailBuilder().CreateFromEml(
client.GetHeadersByUID(uid));
Console.WriteLine(email.Subject);
}
}
client.Close();
}
' VB.NET code
Using client As New Imap()
client.ConnectSSL("imap.server.com")
client.Login("user@server.com", "password")
Dim folderStatus As FolderStatus = client.SelectInbox()
Console.WriteLine("Total message count: {0}",_
folderStatus.MessageCount)
While True
Dim currentStatus As FolderStatus = client.Idle()
Console.WriteLine("Total message count: {0}",_
currentStatus.MessageCount)
For Each uid As Long In client.Search(Flag.Unseen)
Dim email As IMail = New MailBuilder()_
.CreateFromEml(client.GetHeadersByUID(uid))
Console.WriteLine(email.Subject)
Next
End While
client.Close()
End Using

In this next sample we’ll handle stop gracefully. As you can see StopIdle method is thread safe. This means that it can be used from any other thread (for example UI thread).
// C# code
using (Imap client = new Imap())
{
client.ConnectSSL("imap.server.com");
client.Login("user@server.com", "password");
FolderStatus folderStatus = client.SelectInbox();
Console.WriteLine("Total message count: {0}",
currentStatus.MessageCount);
bool stop = false;
// We start a new thread to handle user input, enter = stop idle
new Thread(() =>
{
Console.ReadLine();
client.StopIdle();
stop = true;
}).Start();
while(stop == false)
{
FolderStatus currentStatus = client.Idle();
if (stop == true)
break;
Console.WriteLine("Total message count: {0}",
currentStatus.MessageCount);
foreach(long uid in client.Search(Flag.Unseen))
{
IMail email = new MailBuilder().CreateFromEml(
client.GetHeadersByUID(uid));
Console.WriteLine(email.Subject);
}
}
client.Close();
}
' VB.NET code
Using client As New Imap()
client.ConnectSSL("imap.server.com")
client.Login("user@server.com", "password")
Dim folderStatus As FolderStatus = client.SelectInbox()
Console.WriteLine("Total message count: {0}",_
currentStatus.MessageCount)
Dim [stop] As Boolean = False
' We start a new thread to handle user input, enter = stop idle
New Thread(Function() Do
Console.ReadLine()
client.StopIdle()
[stop] = True
End Function).Start()
While [stop] = False
Dim currentStatus As FolderStatus = client.Idle()
If [stop] = True Then
Exit While
End If
Console.WriteLine("Total message count: {0}",_
currentStatus.MessageCount)
For Each uid As Long In client.Search(Flag.Unseen)
Dim email As IMail = New MailBuilder()_
.CreateFromEml(client.GetHeadersByUID(uid))
Console.WriteLine(email.Subject)
Next
End While
client.Close()
End Using
IDLE command leaves TCP/IP connection unused for a long time. In some cases it may cause routers to decide that this connection is no longer needed. By default Mail.dll reissues IDLE command automatically every 29 minutes. You can shorten this time by using Idle(TimeSpan).
January 8th, 2012 at 01:27
Is there a command where client.SelectInbox() can be replaced so that you can get the all mail folder instead? I figure that would be better so that only one IDLE connection is required for an account. Is there a way to find out which email goes with which folder in this case?
January 8th, 2012 at 21:52
@Scott
You can use any folder name:
client.Select("All Mail")In case of Gmail you may want to use CommonFolders class to get the All Mail folder name:
http://www.limilabs.com/blog/localized-gmail-imap-folders
> Is there a way to find out which email goes with which folder in this case?
In case of Gmail you can get all labels for specified message:
http://www.limilabs.com/blog/get-gmail-labels-for-specified-messages
January 15th, 2012 at 14:44
[...] use push email [...]
March 15th, 2012 at 10:13
hello
sir,when i access email through email.idle notification,i want also mark the email to read
can you tell me how can i do this
March 15th, 2012 at 14:49
@Saqib,
If you download the message (GetMessageByUID) usually server marks it as seen automatically.
You can also use MarkMessageSeenByUID method:
http://www.limilabs.com/blog/mark-emails-as-read-with-imap
Take a look at all Mail.dll samples, most likely you’ll find the code you need there.
May 10th, 2012 at 12:14
[...] use push email [...]