IMAP IDLE in C# and VB.NET

The IDLE mode is a feature of an IMAP protocol that enables a client to monitor the server's real-time notifications about the selected folder. These notifications may include new messages arriving, erased old messages, flag changes, etc.

Before enabling the IDLE mode, you must select the targeted folder. By keeping track of changes in the number of messages in the folder, you can find out if a new message has arrived or if any message was deleted.

The following example shows how to enable IDLE mode and listen to the server notifications.

Using an IDLE mode with IMAP client in C# and VB.NET
Screenshot of ImapClient working in IDLE mode
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using GemBox.Email;
using GemBox.Email.Imap;

class Program
{
    static void Main()
    {
        // If using Professional version, put your serial key below.
        ComponentInfo.SetLicense("FREE-LIMITED-KEY");

        using (var imap = new ImapClient("<ADDRESS> (e.g. imap.gmail.com)"))
        {
            imap.Connect();
            imap.Authenticate("<USERNAME>", "<PASSWORD>");
            imap.SelectInbox();

            using (var listener = new ImapListener(imap))
            {
                listener.MessagesChanged += OnMessagesChanged;
                imap.IdleEnable();

                Console.WriteLine("Press any key to exit...");
                Console.ReadKey();

                imap.IdleDisable();
                listener.MessagesChanged -= OnMessagesChanged;
            }
        }
    }

    static void OnMessagesChanged(object sender, ImapListenerEventArgs e)
    {
        foreach (var info in e.NewMessages)
            Console.WriteLine($"Message '{info.Uid}' received.");

        foreach (var info in e.OldMessages)
            Console.WriteLine($"Message '{info.Uid}' deleted.");
    }
}

class ImapListener : IDisposable
{
    private readonly ImapClient client;
    private Dictionary<string, ImapMessageInfo> messages;
    private bool running;
    private Thread listenerThread;

    public event EventHandler<ImapListenerEventArgs> MessagesChanged;

    public ImapListener(ImapClient client)
    {
        this.client = client;
        this.messages = this.GetMessages();
        this.running = true;
        this.listenerThread = new Thread(Listen) { IsBackground = true };
        this.listenerThread.Start();
    }

    private Dictionary<string, ImapMessageInfo> GetMessages()
    {
        return this.client.ListMessages().ToDictionary(info => info.Uid, info => info);
    }

    private void Listen()
    {
        while (this.running)
        {
            Thread.Sleep(100);

            // Compare the previous and current message count of the selected folder.
            int comparison = this.client.SelectedFolder.Count.CompareTo(this.messages.Count);
            if (comparison == 0)
                continue;

            var currentMessages = this.GetMessages();
            var emptyMessages = Enumerable.Empty<ImapMessageInfo>();

            // New message(s) was added.
            if (comparison > 0)
            {
                var newMessages = currentMessages
                    .Where(message => !this.messages.ContainsKey(message.Key))
                    .Select(message => message.Value);
                this.MessagesChanged?.Invoke(this, new ImapListenerEventArgs(newMessages, emptyMessages));
            }
            // Old message(s) was deleted.
            else
            {
                var oldMessages = this.messages
                    .Where(message => !currentMessages.ContainsKey(message.Key))
                    .Select(message => message.Value);
                this.MessagesChanged?.Invoke(this, new ImapListenerEventArgs(emptyMessages, oldMessages));
            }

            this.messages = currentMessages;
        }
    }

    public void Dispose()
    {
        this.running = false;
        this.listenerThread?.Join(5000);
        this.listenerThread = null;
    }
}

class ImapListenerEventArgs : EventArgs
{
    public IEnumerable<ImapMessageInfo> NewMessages { get; }
    public IEnumerable<ImapMessageInfo> OldMessages { get; }
    public ImapListenerEventArgs(IEnumerable<ImapMessageInfo> newMessages, IEnumerable<ImapMessageInfo> oldMessages)
    {
        this.NewMessages = newMessages;
        this.OldMessages = oldMessages;
    }
}
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Threading
Imports GemBox.Email
Imports GemBox.Email.Imap

Module Program

    Sub Main()

        ' If using Professional version, put your serial key below.
        ComponentInfo.SetLicense("FREE-LIMITED-KEY")

        Using imap As New ImapClient("<ADDRESS> (e.g. imap.gmail.com)")
            imap.Connect()
            imap.Authenticate("<USERNAME>", "<PASSWORD>")
            imap.SelectInbox()

            Using listener = New ImapListener(imap)
                AddHandler listener.MessagesChanged, AddressOf OnMessagesChanged
                imap.IdleEnable()

                Console.WriteLine("Press any key to exit...")
                Console.ReadKey()

                imap.IdleDisable()
                RemoveHandler listener.MessagesChanged, AddressOf OnMessagesChanged
            End Using
        End Using

    End Sub

    Private Sub OnMessagesChanged(sender As Object, e As ImapListenerEventArgs)
        For Each info In e.NewMessages
            Console.WriteLine($"Message '{info.Uid}' received.")
        Next

        For Each info In e.OldMessages
            Console.WriteLine($"Message '{info.Uid}' deleted.")
        Next
    End Sub

End Module

Class ImapListener
    Implements IDisposable

    Private ReadOnly client As ImapClient
    Private messages As Dictionary(Of String, ImapMessageInfo)
    Private running As Boolean
    Private listenerThread As Thread

    Public Event MessagesChanged As EventHandler(Of ImapListenerEventArgs)

    Public Sub New(client As ImapClient)
        Me.client = client
        Me.messages = Me.GetMessages()
        Me.running = True
        Me.listenerThread = New Thread(AddressOf Listen) With {.IsBackground = True}
        Me.listenerThread.Start()
    End Sub

    Private Function GetMessages() As Dictionary(Of String, ImapMessageInfo)
        Return Me.client.ListMessages().ToDictionary(Function(info) info.Uid, Function(info) info)
    End Function

    Private Sub Listen()
        While Me.running
            Thread.Sleep(100)

            ' Compare the previous and current message count of the selected folder.
            Dim comparison As Integer = Me.client.SelectedFolder.Count.CompareTo(Me.messages.Count)
            If comparison = 0 Then Continue While

            Dim currentMessages = Me.GetMessages()
            Dim emptyMessages = Enumerable.Empty(Of ImapMessageInfo)()

            If comparison > 0 Then
                ' New message(s) was added.
                Dim newMessages = currentMessages
                .Where(Function(message) Not Me.messages.ContainsKey(message.Key))
                .Select(Function(message) message.Value)
                Me.MessagesChanged?.Invoke(Me, New ImapListenerEventArgs(newMessages, emptyMessages))
            Else
                ' Old message(s) was deleted.
                Dim oldMessages = Me.messages
                    .Where(Function(message) Not currentMessages.ContainsKey(message.Key))
                    .Select(Function(message) message.Value)
                Me.MessagesChanged?.Invoke(Me, New ImapListenerEventArgs(emptyMessages, oldMessages))
            End If

            Me.messages = currentMessages
        End While
    End Sub

    Public Sub Dispose()
        Me.running = False
        Me.listenerThread?.Join(5000)
        Me.listenerThread = Nothing
    End Sub
End Class

Class ImapListenerEventArgs
    Inherits EventArgs
    Public ReadOnly Property NewMessages As IEnumerable(Of ImapMessageInfo)
    Public ReadOnly Property OldMessages As IEnumerable(Of ImapMessageInfo)
    Public Sub New(newMessages As IEnumerable(Of ImapMessageInfo), oldMessages As IEnumerable(Of ImapMessageInfo))
        Me.NewMessages = newMessages
        Me.OldMessages = oldMessages
    End Sub
End Class

See also


Next steps

GemBox.Email is a .NET component that enables you to read, write, receive, and send emails from your .NET applications using one simple API.

Download Buy