Search code examples
spring-integration

ImapIdleChannelAdapter infinite loop on AUTHENTICATIONFAILED


I'm using ImapIdleChannelAdapter to listen to mailboxes, taking a list with credentials in a database. If a password is wrong, I get an AUTHENTICATIONFAILED. The problem is that it will never stop trying to reconnect. I tried to set shouldReconnectAutomatically to false, but it will just stop the IdleTask from resubmitting, not the ReceivingTask.

Code from ImapIdleChannedAdapter:

private class ReceivingTask implements Runnable {

        ReceivingTask() {
        }

        @Override
        public void run() {
            if (isRunning()) {
                try {
                    ImapIdleChannelAdapter.this.idleTask.run();
                    logger.debug("Task completed successfully. Re-scheduling it again right away.");
                }
                catch (Exception ex) { //run again after a delay
                    logger.warn(ex, () -> "Failed to execute IDLE task. Will attempt to resubmit in "
                            + ImapIdleChannelAdapter.this.reconnectDelay + " milliseconds.");
                    ImapIdleChannelAdapter.this.receivingTaskTrigger.delayNextExecution();
                    publishException(ex);
                }
            }
        }

    }


    private class IdleTask implements Runnable {

        IdleTask() {
        }

        @Override
        public void run() {
            if (isRunning()) {
                try {
                    logger.debug("waiting for mail");
                    ImapIdleChannelAdapter.this.mailReceiver.waitForNewMessages();
                    Folder folder = ImapIdleChannelAdapter.this.mailReceiver.getFolder();
                    if (folder != null && folder.isOpen() && isRunning()) {
                        Object[] mailMessages = ImapIdleChannelAdapter.this.mailReceiver.receive();
                        logger.debug(() -> "received " + mailMessages.length + " mail messages");
                        for (Object mailMessage : mailMessages) {
                            Runnable messageSendingTask = createMessageSendingTask(mailMessage);
                            if (isRunning()) {
                                ImapIdleChannelAdapter.this.sendingTaskExecutor.execute(messageSendingTask);
                            }
                        }
                    }
                }
                catch (MessagingException ex) {
                    logger.warn(ex, "error occurred in idle task");
                    if (ImapIdleChannelAdapter.this.shouldReconnectAutomatically) {
                        throw new IllegalStateException("Failure in 'idle' task. Will resubmit.", ex);
                    }
                    else {
                        throw new org.springframework.messaging.MessagingException(
                                "Failure in 'idle' task. Will NOT resubmit.", ex);
                    }
                }
            }
        }

    }

So in my logs I get infinite:

WARN 2777 --- [ask-scheduler-3] o.s.i.mail.ImapIdleChannelAdapter        : Failed to execute IDLE task. Will attempt to resubmit in 10000 milliseconds.

org.springframework.messaging.MessagingException: Failure in 'idle' task. Will NOT resubmit.; nested exception is javax.mail.AuthenticationFailedException: [AUTHENTICATIONFAILED] Invalid credentials (Failure)
    at org.springframework.integration.mail.ImapIdleChannelAdapter$IdleTask.run(ImapIdleChannelAdapter.java:290)
    at org.springframework.integration.mail.ImapIdleChannelAdapter$ReceivingTask.run(ImapIdleChannelAdapter.java:246)
    at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
    at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:95)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266)
    at java.util.concurrent.FutureTask.run(FutureTask.java)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
Caused by: javax.mail.AuthenticationFailedException: [AUTHENTICATIONFAILED] Invalid credentials (Failure)
    at com.sun.mail.imap.IMAPStore.protocolConnect(IMAPStore.java:708)
    at javax.mail.Service.connect(Service.java:342)
    at javax.mail.Service.connect(Service.java:222)
    at javax.mail.Service.connect(Service.java:171)
    at org.springframework.integration.mail.AbstractMailReceiver.connectStoreIfNecessary(AbstractMailReceiver.java:331)
    at org.springframework.integration.mail.AbstractMailReceiver.openFolder(AbstractMailReceiver.java:338)
    at org.springframework.integration.mail.ImapMailReceiver.waitForNewMessages(ImapMailReceiver.java:176)
    at org.springframework.integration.mail.ImapIdleChannelAdapter$IdleTask.run(ImapIdleChannelAdapter.java:271)
    ... 11 common frames omitted

Those logs are odd:

Failed to execute IDLE task. Will attempt to resubmit in 10000 milliseconds
Failure in 'idle' task. Will NOT resubmit.

Is there a possibility to stop the reconnexion attempts? I don't really want to set the reconnectDelay to absurd duration... It does not feel right.

Thank you!


Solution

  • Add an ApplicationListener<ImapIdleExceptionEvent> bean (or an @EventListener method) to receive ImapIdleExceptionEvents.

    You can then stop the adapter in the event listener (the channel adapter is the source of the event).