IDLE | Blog | Limilabs https://www.limilabs.com/blog Using Limilabs .net components Fri, 28 Feb 2014 09:28:30 +0000 en-US hourly 1 https://wordpress.org/?v=6.6.5 IMAP IDLE: instant push email notifications https://www.limilabs.com/blog/imap-idle https://www.limilabs.com/blog/imap-idle#comments Thu, 15 Apr 2010 05:22:42 +0000 http://www.limilabs.com/blog/?p=831 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 the 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 […]

The post IMAP IDLE: instant push email notifications first appeared on Blog | Limilabs.

]]>
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 the 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 .NET IMAP library 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 the new notification is received.
  • StopIdle() – stops accepting real-time notifications. This method is thread-safe.

The following sample connects to an 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

Stop IDLE gracefully

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

Drawbacks

IDLE has some drawbacks:

  • It requires constant server connection.
  • IDLE command leaves TCP/IP connection unused for a long time, and although IDLE is reissued/refreshed every 10 minutes (RFC requirement is 29 minutes, but this is much to long), some routers may assume the connection is dead, because of too long period of inactivity.

    Shortening the timeout using Imap.Idle(TimeSpan) overload usually solves this issue. Don’t be afraid of shortening the timeout value as reissuing IDLE command takes less that a hundred bytes of data.

The post IMAP IDLE: instant push email notifications first appeared on Blog | Limilabs.

]]>
https://www.limilabs.com/blog/imap-idle/feed 10