How can I use IMAP4 IDLE..DONE with HigLabo?

Jul 17, 2012 at 8:18 PM

I guess I'm looking for some kind of event to be raised when the IMAP4 server receives an email.

http://tools.ietf.org/html/rfc2177

Coordinator
Jul 19, 2012 at 4:10 AM

Idle command is not completed.
I'll implement it in a next week.
Please wait.

Coordinator
Jul 19, 2012 at 11:01 AM
Edited Jul 19, 2012 at 2:31 PM

I checked in new version which have IDLE command functionality.

----------------------------------------------------------------------------------------------------------------------------
            using (ImapClient cl = new ImapClient("imap.gmail.com", 993, "mailaddress", "pass"))
            {
                cl.Ssl = true;
                cl.ReceiveTimeout = 10 * 60 * 1000;//10 minute for idle
                if (cl.Authenticate() == true)
                {
                    var r = cl.ExecuteExamine("INBOX");
                    var cm = new ImapIdleCommand();
                    cm.MessageReceived += (Object o, ImapIdleCommandMessageReceivedEventArgs e) =>
                    {
                        foreach (var mg in e.MessageList)
                        {
                            String text = String.Format("Type is {0} Number is {1}", mg.MessageType, mg.Number);
                            // Do something....
                        }
                        if (... == true) //Some condition
                        {
                            e.Done = true; //Finish receiving message from server
                        }
                    };
                    while (true)
                    {
                        try
                        {
                            cl.ExecuteIdle(cm); //Block this thread...
                        }
                        catch (SocketException ex) //Exception will raise when timeout
                        {
                        }
                    }
                }
            }
----------------------------------------------------------------------------------------------------------------------------
You may use this code in background thread.

Jul 19, 2012 at 2:49 PM

Thanks for adding this so quickly, higty.

It looks to me like calling ExecuteIdle() will block until the first idle response is received or until the ReceiveTimeout is reached, so this is useful for receiving only one IDLE response.  I see that inside ExecuteIdle(), you send a "DONE" command.  If this assessment is correct, then I feel there might be a problem with this approach:  I cannot rely on ExecuteIdle() to notify me of *each and every* message because a message can arrive on the server right after "DONE" is sent to the server, but before ExecuteIdle() can be called again to look for the next message.

If I'm wrong and the ExecuteIdle() processes all IDLE responses until the ReceiveTimeout is reached, then it would be nice to have a way to terminate the ExecuteIdle from another thread so I don't have to wait for ReceiveTimeout.  This would be useful in the following scenario:  In a batch process, I want to detect the arrival of an email from a particular sender and process it.  Once the email arrives and I've downloaded it, I can terminate the IDLE and close the IMAP connection.

One more really useful feature in my opinion would be an event on the ImapIdleCommand that is raised when the IDLE command is terminated and whether it's terminated because of ReceiveTimeout or explicitly by using the feature that I described in the previous paragraph.

Regardless of what you decide to do, higty, thanks for your hard work on this.

Coordinator
Jul 20, 2012 at 4:28 AM
Edited Jul 20, 2012 at 7:07 AM

My implementation is just " the ExecuteIdle() processes all IDLE responses until the ReceiveTimeout is reached".
cm.MessageReceived += your handler
Your handler will receive message continuously until timeout.
And you can finish receiving by set Done property of ImapIdleCommandMessageReceivedEventArgs object to true.

Version HigLabo20120720
Change set number is 93030

Please try it!!



Jul 20, 2012 at 4:23 PM

Then the only way to issue a "DONE" before ReceiveTimeout is to wait for MessageReceived to be raised.  There is no way to issue a "DONE" asyncronously, before ReceiveTimeout is reached.

In other words, IDLE will run for up to ReceiveTimeout ms, but can be terminated before then by setting the Done property of ImapIdleCommandMessageReceivedEventArgs object to true.

Coordinator
Jul 21, 2012 at 11:35 AM

I see what is your requirement.
I'll redesign API in next week.
Please wait...

Coordinator
Jul 24, 2012 at 2:22 AM

I checked in new version.
Here is a sample code for use it.

--------------------------------------------------------------------------------
            using (ImapClient cl = new ImapClient("imap.gmail.com", 993, "mail address", "pass"))
            {
                cl.Ssl = true;
                cl.ReceiveTimeout = 10 * 60 * 1000;//10 minute
                if (cl.Authenticate() == true)
                {
                    var r = cl.ExecuteExamine("INBOX");
                    using (var cm = cl.CreateImapIdleCommand()) //You must dispose ImapIdleCommand object
                    {
                        cm.MessageReceived += (Object o, ImapIdleCommandMessageReceivedEventArgs e) =>
                        {
                            foreach (var mg in e.MessageList)
                            {
                                String text = String.Format("Type is {0} Number is {1}", mg.MessageType, mg.Number);
                                Console.WriteLine(text);
                            }
                        };
                        cl.ExecuteIdle(cm);

                        while (true)
                        {
                            var line = Console.ReadLine();
                            if (line == "done")
                            {
                                cl.ExecuteDone(cm);
                                break;
                            }
                        }
                    }
                }
            }
--------------------------------------------------------------------------------

Jul 24, 2012 at 7:33 PM

Looks good!