0

I'm using Java Springboot to read the inbox of a Microsoft Exchange account (I am already able to send emails programmatically). When I try to read the inbox folder I receive a general error:

javax.mail.MessagingException: Connection dropped by server?

Username and password are of course correct.

I use the following configuration:

  Properties mailProps = new Properties();
  mailProps.setProperty("mail.transport.protocol","smtp");
  mailProps.setProperty("mail.smtp.auth","true");
  mailProps.setProperty("mail.smtp.starttls.enable","true");
  mailProps.setProperty("mail.debug","false");      
  mailProps.setProperty("mail.smtp.sasl.mechanisms.oauth2.oauthToken", password);
  Session session = Session.getDefaultInstance(mailProps);   
  Store store = session.getStore("imaps");      
  store.connect("outlook.office365.com", 143,  username, password); //username and password are omitted
  Folder emailFolder = store.getFolder("inbox");
  emailFolder.open(Folder.READ_ONLY);

UPDATE: Since I can get the inbox from the Thunderbird client, I set up the code following the configuration on Thunderbird. Now I have:

DEBUG: getProvider() returning javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Oracle]
DEBUG IMAPS: mail.imap.fetchsize: 16384
DEBUG IMAPS: mail.imap.ignorebodystructuresize: false
DEBUG IMAPS: mail.imap.statuscachetimeout: 1000
DEBUG IMAPS: mail.imap.appendbuffersize: -1
DEBUG IMAPS: mail.imap.minidletime: 10
DEBUG IMAPS: enable STARTTLS
DEBUG IMAPS: closeFoldersOnStoreFailure
DEBUG IMAPS: trying to connect to host "outlook.office365.com", port 143, isSSL true
javax.mail.MessagingException: Unsupported or unrecognized SSL message
at it.spring.platform.services.communication.mail.MailTest.read(MailTest.java:53)

For the sake of clarity and completeness I add the full Spring code I wrote to read the inbox:

import javax.mail.MessagingException;
import javax.mail.Store;

public class JavaMailReader
{
 private Store store;
 private String username;
 private String password;
 private String host;
 private int port;
 private String inbox;

 public JavaMailReader(Store store, String host, int port, String   username, String password, String inbox)
 { 
   this.host=host;
   this.port=port;
   this.store=store;
   this.username=username;
   this.password=password;
   this.inbox=inbox;
   this.port = port;
  }

  public void connect() throws MessagingException
  {
    store.connect(host, port, username, password);       
  }

  public Store getStore()
  {
   return store;
  }   

  public String getInboxFolderName()
  {
    return this.inbox;
  }    
}

  @Bean
public JavaMailReader emailReader(@Value("imaps") String protocol,

                                  
@Value("${mailreceiver.mail.host}")  String host,

                                  @Value("${mailreceiver.mail.port}") Integer port,

                                  @Value("${mailreceiver.mail.password}")  String password,

                                  @Value("${mailreceiver.mail.username}") String username) throws NoSuchProviderException, MessagingException

{

  Properties mailProps = new Properties();      

  mailProps.setProperty("mail.transport.protocol","imaps");

  mailProps.setProperty("mail.imaps.auth","true");      

  mailProps.setProperty("mail.debug","true");       

  mailProps.setProperty("mail.imaps.sasl.mechanisms.oauth2.oauthToken", password);      

  Session session = Session.getDefaultInstance(mailProps);   

  Store store = session.getStore(protocol);      

  return new JavaMailReader (store, host, port, username, password, "inbox");

}

 //testing
  @Test
  public void read() throws NoSuchProviderException, MessagingException

{     

  Message[] messages = mailService.getInbox(); //getInbox("Inbox")

  Message found=null;

  for(Message m: messages)

  {

    if(m.getSubject().equalsIgnoreCase(subject))

    {

        found=m;

        break;

    }

  }

  assertNotNull(found);

  mailService.closeReader();

}

UPDATE 2: As suggested, I changed the port to 993 and removed starttls:

  Properties mailProps = new Properties(); 
  mailProps.setProperty("mail.transport.protocol","imaps");
  mailProps.setProperty("mail.imaps.auth","true");      
  mailProps.setProperty("mail.debug","true"); 
  maililProps.
  setProperty("mail.imaps.sasl.mechanisms.oauth2.oauthToken",  password);
  Session session = Session.getDefaultInstance(mailProps);  
  Store store = session.getStore(protocol);     
  return new JavaMailReader (store, host, port, username, password, "inbox");

Now I have the error:

DEBUG IMAPS: trying to connect to host "outlook.office365.com", port 993, isSSL true
* OK The Microsoft Exchange IMAP4 service is ready. [ a string here omitted for security reason==]
A0 CAPABILITY
* CAPABILITY IMAP4 IMAP4rev1 AUTH=PLAIN AUTH=XOAUTH2 SASL-IR UIDPLUS ID UNSELECT CHILDREN IDLE NAMESPACE LITERAL+
A0 OK CAPABILITY completed.
DEBUG IMAPS: AUTH: PLAIN
DEBUG IMAPS: AUTH: XOAUTH2
DEBUG IMAPS: protocolConnect login, host=outlook.office365.com, 
user= the user-email-here, password=<non-null>
DEBUG IMAPS: AUTHENTICATE PLAIN command trace suppressed
DEBUG IMAPS: AUTHENTICATE PLAIN command result: A1 NO AUTHENTICATE failed.
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 3.159 s 
javax.mail.AuthenticationFailedException: AUTHENTICATE failed.
Discipulos
  • 423
  • 8
  • 23

2 Answers2

2

Based on your settings, you seem to try to connect to the O365 IMAP server on port 143 (default IMAP port) using SSL protocol:

trying to connect to host "outlook.office365.com", port 143, isSSL true

This can't work because the server will respond with the default plaintext banner text (i.e. * OK The Microsoft Exchange IMAP4 service is ready) while your client is expecting an SSL handshake, hence the error Unsupported or unrecognized SSL message.

You should use the default IMAPS protocol port which is 993 (also documented here). Then the connection will be an IMAPS (TLS) connection and your settings should work.

Also, STARTTLS is irrelevant in this scenario.

Tasos P.
  • 3,994
  • 2
  • 21
  • 41
  • Thank you. I changed the port to 992 and removed starttls. No I have the error: DEBUG IMAPS: AUTHENTICATE PLAIN command result: A1 NO AUTHENTICATE failed javax.mail.AuthenticationFailedException: AUTHENTICATE failed (see Update 2) – Discipulos Nov 29 '22 at 16:09
  • Now that the original connection issue is resolved, you need to fix the authentication issue which is mostly about proper credentials. AFAIK you can't just use your username and password pair for IMAP; you need to get a proper authentication token as described [here](https://learn.microsoft.com/en-us/exchange/client-developer/legacy-protocols/how-to-authenticate-an-imap-pop-smtp-application-by-using-oauth). [This answer](https://stackoverflow.com/questions/61597263/office-365-xoauth2-for-imap-and-smtp-authentication-fails) is also related. – Tasos P. Nov 30 '22 at 10:38
  • Is there anyway to read the inbox without token? (in a similary way as I'm doing with the outbox) – Discipulos Nov 30 '22 at 12:41
0

Your settings may work for SMTP, but what you want is reading email, and for that you have to use IMAP or POP3 (or Microsoft Graph, but that uses a complete different API).

So you have to provide a different configuration:

Properties mailProps = new Properties();
mailProps.setProperty("mail.transport.protocol","imaps");
mailProps.setProperty("mail.imaps.auth","true");
mailProps.setProperty("mail.imaps.starttls.enable","true");
mailProps.setProperty("mail.debug","false");      
mailProps.setProperty("mail.imaps.sasl.mechanisms.oauth2.oauthToken", password);
Session session = Session.getDefaultInstance(mailProps);   
Store store = session.getStore("imaps");      
store.connect("outlook.office365.com", 143,  username, password); //username and password are omitted
Folder emailFolder = store.getFolder("inbox");
emailFolder.open(Folder.READ_ONLY);

I have replaced all occurences of "smtp" with "imaps", to configure the IMAPS protocol (otherwise, you would have provided settings for the SMTP protocol, and that is for sending emails …

If you want to do both in one go, you have to have both settings (one with "imaps", the other one with "smtp"), and when you want to use POP3, you use "pop3" instead (or "imap" if it is not IMAPS, but IMAP).

I do not have an Exchange account at hand, so I cannot test the exact settings, but I can tell that the default settings that you used will not work for sure (you did not provide any particular setting for IMAP(S), so it had been the default …).

Next you should keep in mind that Office365 is a beast! You can have a lot of fun with it, in particular when accessing it to get your mail out of it. As long as you move one or the other mail once in a blue moon, everything is fine. But when you start with bulk volumes it will get nasty if you do not have especially paid for it. Although this affects mainly sending, you can get also funny error messages when reading emails.

Again, the settings I provided will show only how the configuration property names should look like, I do not guarantee that they work with the given values! You even may have to provide additional configuration settings.

And "STARTTLS" does not make sense for the *S protocols, as they are running on TLS right from the beginning. Nevertheless, you can set it; you can also set "mail.imaps.clothilde" as "She is nice" … it will just be ignored.

tquadrat
  • 3,033
  • 1
  • 16
  • 29
  • I tried your configuration, both by enabling and disabling outh2, same error. – Discipulos Nov 27 '22 at 09:25
  • As said, I just found that already the names for the configuration values were wrong. And that I cannot test it myself, because I do not have an Office365 account that I could use. Set `mail.debug` to true, capture the output and paste it into your question. – tquadrat Nov 27 '22 at 15:13
  • Thank you for your time. I added the debug info (Update section of the question) – Discipulos Nov 29 '22 at 07:58