Search code examples
javamicrosoft-exchange

Java and Microsoft Exchange Connection Dropped by server?


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.

Solution

  • 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.