Search code examples
javaemailjakarta-mailimap

IMAP Idle, possibility to miss events?


I'm implementing a mail listener in java, the listener enters IDLE until a new mail arrives, it prints the email subject and goes back into IDLE immediately again.

Is there a chance that I will miss events (new emails) between the two IDLEs that I'm issuing?

For example, I've tried sleeping for 10 seconds before going into IDLE again, and within these 10 seconds I sent 2 emails to the inbox I'm monitoring, and after the 10 seconds when I went back into IDLE my MessageCountListener only got called once, for the first email. The second was missed.

Maybe I shouldn't rely on MessageCountListener?

       messageCountListener = new MessageCountListener() {
            //lets go into idle again and then handle the message
            public void messagesAdded(MessageCountEvent ev) {
                Message message = ev.getMessages()[0];
                try {
                    SimpleLogger.info("New message, subject: " + message.getSubject());
                } catch (MessagingException e) {
                    e.printStackTrace();
                }

                //GeneralUtility.threadSleep(8000);

                startImapIdle();
            }

startImapIdle() is called initially and then gets re-called from messagesAdded() like above.

private void startImapIdle() {
    SimpleLogger.info("Idling now");

    Runnable r = () -> {
        try {
            inboxFolder.idle(false);
        } catch (FolderClosedException e) {
            SimpleLogger.warn("Push Error: [DISCONNECT]", e);
            GeneralUtility.threadSleep(mailListenerRetryInterval);
            startListening(inboxFolder);
        } catch (StoreClosedException e) {
            SimpleLogger.warn("Push Error: [GLOBAL DISCONNECT]", e);
            GeneralUtility.threadSleep(mailListenerRetryInterval);
            initConnection();
        } catch (MessagingException e) {
            SimpleLogger.warn("Push Error: [NO IDLE]", e);
            GeneralUtility.threadSleep(mailListenerRetryInterval);
            initConnection();
        } catch (Exception e) {
            SimpleLogger.warn("Push Error: [UNKNOWN]", e);
            GeneralUtility.threadSleep(mailListenerRetryInterval);
            initConnection();
        }
    };

    imapIdleThread = new Thread(r);
    imapIdleThread.start();
}

edit: (new code)

   private void startImapIdle() {
        while(true) {
            try {
                SimpleLogger.info("Idling now");
                MailUtility.ensureFolderOpen(folder);
                folder.idle();
            } catch (FolderClosedException e) {
                SimpleLogger.warn("Push Error: [DISCONNECT]", e);
                GeneralUtility.threadSleep(mailListenerRetryInterval);
                startListening();
                break;
            } catch (StoreClosedException e) {
                SimpleLogger.warn("Push Error: [GLOBAL DISCONNECT]", e);
                GeneralUtility.threadSleep(mailListenerRetryInterval);
                initConnection();
                break;
            } catch (MessagingException e) {
                SimpleLogger.warn("Push Error: [NO IDLE]", e);
                GeneralUtility.threadSleep(mailListenerRetryInterval);
                initConnection();
                break;
            } catch (Exception e) {
                SimpleLogger.warn("Push Error: [UNKNOWN]", e);
                GeneralUtility.threadSleep(mailListenerRetryInterval);
                initConnection();
                break;
            }
        }
    }

Solution

  • How are you doing this? The below code works pretty well.

    inbox.addMessageCountListener(new MessageCountAdapter() { ... })

    Of course you need to have another infinite loop something like:

              while (true) {
                      IMAPFolder f = (IMAPFolder)inbox;
                      f.idle();
              }