0

With java spring integration written the below code to read the email from gmail. As per logs seems the connection with gmail is formed, but on new email its not reading or not going into handle() method. Please help.

o.s.i.m.AbstractMailReceiver - attempting to receive mail from folder [INBOX]

import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.config.EnableIntegration;
import org.springframework.integration.dsl.IntegrationFlow;
import org.springframework.integration.dsl.IntegrationFlows;
import org.springframework.integration.dsl.Pollers;
import org.springframework.integration.mail.MailReceiver;
import org.springframework.integration.mail.dsl.Mail;
import org.springframework.integration.mail.support.DefaultMailHeaderMapper;
import org.springframework.integration.mapping.HeaderMapper;
import org.springframework.messaging.Message;
import org.springframework.messaging.PollableChannel;

import javax.mail.internet.MimeMessage;

@Log4j2
@Configuration
@EnableIntegration
public class EmailReceiver {
    @Autowired
    private PollableChannel pop3Channel;
    @Bean
    public PollableChannel receivedChannel() {
        return new QueueChannel();
    }
    @Bean
    public IntegrationFlow pop3MailFlow() {
        return IntegrationFlows
                .from(Mail.pop3InboundAdapter("pop.gmail.com", 995, "userName", "password")
                                .javaMailProperties(p -> {
                                    p.put("mail.debug", "true");
                                    p.put("mail.pop3.socketFactory.fallback", "false");
                                    p.put("mail.pop3.port", 995);
                                    p.put("mail.pop3.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
                                    p.put("mail.pop3.socketFactory.port", 995);
                                })
                                .headerMapper(mailHeaderMapper()),                       
                        e -> e.poller(Pollers.fixedRate(5000).maxMessagesPerPoll(1)))
                .handle((payload, header) -> logMail(payload))
                .get();
    }
    public Message logMail(Object payload) {
        Message message = (Message)payload;
        log.info("*******Email[TEST]********* ", payload);
        return message;
    }
    @Bean
    public HeaderMapper<MimeMessage> mailHeaderMapper() {
        return new DefaultMailHeaderMapper();
    }
}
Ganesh
  • 903
  • 1
  • 8
  • 18
  • @Gary Russell - could you please help – Ganesh Mar 03 '22 at 13:12
  • Please, double check your properties with this sample: https://kodejava.org/how-do-i-receive-mail-using-pop3/ (and here: https://stackoverflow.com/questions/16897075/gmail-imap-vs-pop3-when-using-javamail-api). It also might be great to have that `mail.debug` as `true`, so you may observe a reason why your emails are not pulled. – Artem Bilan Mar 03 '22 at 14:21
  • @ArtemBilan- on debug true logs showing svc connected to mail box and reading emails.. but i am not able catch the mail/message in handle() to work on it. Delivered-To: username Received: by 10.58.173.5 with SMTP id bg5csp281922vec; Wed, 18 Jun 2014 20:31:50 -0700 (PDT) X-Received: by 10.68.190.98 with SMTP id gp2mr2333316pbc.88.1403148709725; Wed, 18 Jun 2014 20:31:49 -0700 (PDT) Please suggest – Ganesh Mar 03 '22 at 14:52
  • That `.handle((payload, header)` is request-reply and it is not good to have in the end of flow. You just not going to have a `replyChannel` header. Just because you flow does not start from an inbound gateway. I believe it is not relevant to the problem, just pointing you that there is a flaw in your current logic. Any chances that you can share with us a simple project to try to reproduce? Of course without your credentials - we will use ours. – Artem Bilan Mar 03 '22 at 14:56
  • @ArtemBilan- I have updated the code section with complete code that i am running in Question itself.. Please check and advise – Ganesh Mar 03 '22 at 15:08
  • OK. As I said: your code is wrong with that `handle()` in the end of flow. The request-reply cannot be used in the one-way flow. The framework cannot prevent you from doing that because it cannot guess your logic, but it is clearly visible that your flow is misleading. I know: this is not relevant for the question, but still. Please, try to pop your Gmail account without Spring Integration first. You might just have some error in between which you are missing from your logs to investigate. That's why I asked for the project which we can easy to run on our side. – Artem Bilan Mar 03 '22 at 15:16

1 Answers1

1

The problem is here:

.maxFetchSize(1)

By default the AbstractMailReceiver tries to fetch all the messages from the mail box. And looks like it takes a lot of time.

Another problem that with the .headerMapper(mailHeaderMapper() a Mail.pop3InboundAdapter does not produce a Message but rather byte[]. So, your .handle((payload, header) -> logMail(payload)) not only bad by the request-reply definition in the end of flow, but also fails with ClassCast like this, because you expect the type which is not produced for you:

Caused by: java.lang.ClassCastException: class [B cannot be cast to class org.springframework.messaging.Message ([B is in module java.base of loader 'bootstrap'; org.springframework.messaging.Message is in unnamed module of loader 'app')
at com.firm.demo.EmailReceiver.logMail(EmailReceiver.java:59)
at com.firm.demo.EmailReceiver.lambda$pop3MailFlow$2(EmailReceiver.java:53)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)

Well, no: better to say you are missing the fact that this signature .handle((payload, header) -> logMail(payload)) deals with the payload not the whole message. So, your expectations in the logMail() are wrong. It has to be byte[]. And consider to have a one-way handler over there in the end of flow anyway.

UPDATE

The working code is like this:

@Log4j2
@Configuration
@EnableIntegration
public class EmailReceiver {

    @Autowired
    private PollableChannel pop3Channel;

    private MailReceiver receiver;


    @Bean
    public PollableChannel receivedChannel() {
        return new QueueChannel();
    }


    @Bean
    public IntegrationFlow pop3MailFlow() {
        return IntegrationFlows
                .from(Mail.pop3InboundAdapter("pop.gmail.com", 995, "userName", "password")
                                .javaMailProperties(p -> {
                                    p.put("mail.debug", "false");
                                    p.put("mail.pop3.socketFactory.fallback", "false");
                                    p.put("mail.pop3.port", 995);
                                    p.put("mail.pop3.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
                                    p.put("mail.pop3.socketFactory.port", 995);
                                })
                                .maxFetchSize(1)
                                .headerMapper(mailHeaderMapper()),
                        e -> e.poller(Pollers.fixedRate(5000).maxMessagesPerPoll(1)))
                .handle(this, "logMail")
                .get();
    }


    public void logMail(String payload) {
        log.info("*******Email[TEST]********* \n" + payload);
    }

    @Bean
    public HeaderMapper<MimeMessage> mailHeaderMapper() {
        return new DefaultMailHeaderMapper();
    }


}
Artem Bilan
  • 113,505
  • 11
  • 91
  • 118
  • Which MailReceiver should be in replacement of AbstractMailReceiver. And how ? How get Email contents/details out of byte[]... Where i can add handle()? I understood the details, as i am new to this need your help to correct it. You can commit in repo if possible. – Ganesh Mar 03 '22 at 17:50
  • See an UPDATE in my answer. – Artem Bilan Mar 03 '22 at 18:09
  • Is there any work going on to integrate with ms graph mail api also – Gaurav Rawat Mar 21 '23 at 18:10
  • That's probably more question to Microsoft and their Spring Cloud Azure project. – Artem Bilan Mar 21 '23 at 19:09