Exchange server will not accept username/password provided with javax.mail API

30,445

Apparently, MS Exchange SSL connection is not established properly by Java Mail API. It relies on using SSLSocketFactory for that, but, if I remember correctly, MS Exchange requires a somewhat mixed approach.

Anyway, I have this piece of code in one of my projects:

import javax.net.SocketFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.*;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

public class ExchangeSSLSocketFactory extends SSLSocketFactory {

private SSLSocketFactory sslSocketFactory;
private SocketFactory socketFactory;

public ExchangeSSLSocketFactory() {
    try {
        socketFactory = SocketFactory.getDefault();

        SSLContext context = SSLContext.getInstance("TLS");
        context.init(null, new TrustManager[] { new EmptyTrustManager() }, null);
        sslSocketFactory = (SSLSocketFactory)context.getSocketFactory();
    }
    catch (Exception e) {
        throw new RuntimeException(e);
    }
}

private final class EmptyTrustManager implements X509TrustManager {
    public void checkClientTrusted(X509Certificate[] cert, String authType) throws CertificateException {}

    public void checkServerTrusted(X509Certificate[] cert, String authType) throws CertificateException {}

    public X509Certificate[] getAcceptedIssuers() {
        return new java.security.cert.X509Certificate[0];
    }
}

public static SocketFactory getDefault() {
    return new ExchangeSSLSocketFactory();
}

@Override
public Socket createSocket(Socket socket, String s, int i, boolean flag) throws IOException {
    return sslSocketFactory.createSocket(socket, s, i, flag);
}

@Override
public Socket createSocket(InetAddress inaddr, int i, InetAddress inaddr1, int j) throws IOException {
    return socketFactory.createSocket(inaddr, i, inaddr1, j);
}

@Override
public Socket createSocket(InetAddress inaddr, int i) throws IOException {
    return socketFactory.createSocket(inaddr, i);
}

@Override
public Socket createSocket(String s, int i, InetAddress inaddr, int j) throws IOException {
    return socketFactory.createSocket(s, i, inaddr, j);
}

@Override
public Socket createSocket(String s, int i) throws IOException {
    return socketFactory.createSocket(s, i);
}

@Override
public Socket createSocket() throws IOException {
    return socketFactory.createSocket();
}

@Override
public String[] getDefaultCipherSuites() {
    return sslSocketFactory.getSupportedCipherSuites();
}

@Override
public String[] getSupportedCipherSuites() {
    return sslSocketFactory.getSupportedCipherSuites();
}

}

You tell the Java Mail API to use this socket factory by setting following properties:

  • ssl.SocketFactory.provider
  • mail.smtp.socketFactory.class

to full class name of ExchangeSSLSocketFactory

From your debug output, it seems that you already have:

  • mail.smtp.starttls.enable set to true

With all this in place, the problem should be solved.

Share:
30,445
Ami
Author by

Ami

my about me is currently blank.

Updated on August 05, 2020

Comments

  • Ami
    Ami almost 4 years

    I have a lovely little Java client that sends signed email messages. We have an Exchange server that requires username/password authentication to send a message.

    When I connect to the exchange server, I get this error:

    avax.mail.AuthenticationFailedException: failed to connect
            at javax.mail.Service.connect(Service.java:322)
            at javax.mail.Service.connect(Service.java:172)
    

    When I connect to other servers (Unix servers), I have no problem.

    Below is the full debug trace. I can't figure it out.

    DEBUG: JavaMail version 1.4.2
    DEBUG: successfully loaded resource: /META-INF/javamail.default.providers
    DEBUG: Tables of loaded providers
    DEBUG: Providers Listed By Class Name: {com.sun.mail.smtp.SMTPSSLTransport=javax.mail.Provider[TRANSPORT,smtps,com.sun.mail.smtp.SM}
    DEBUG: Providers Listed By Protocol: {imaps=javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Sun Microsystems, Inc], }
    DEBUG: successfully loaded resource: /META-INF/javamail.default.address.map
    DEBUG: getProvider() returning javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Sun Microsystems, Inc]
    DEBUG SMTP: useEhlo true, useAuth true
    DEBUG SMTP: trying to connect to host "SERVER", port 25, isSSL false
    220 SERVER ESMTP (deca81216f2ecf4fd6fedb030e3dcfd0)
    DEBUG SMTP: connected to host "SERVER", port: 25
    
    EHLO CLIENT
    250-SERVER Hello CLIENT [192.1.1.1], pleased to meet you
    250-STARTTLS
    250-PIPELINING
    250-SIZE 100000000
    250-AUTH LOGIN PLAIN
    250-AUTH=LOGIN PLAIN
    250-8BITMIME
    250 HELP
    DEBUG SMTP: Found extension "STARTTLS", arg ""
    DEBUG SMTP: Found extension "PIPELINING", arg ""
    DEBUG SMTP: Found extension "SIZE", arg "100000000"
    DEBUG SMTP: Found extension "AUTH", arg "LOGIN PLAIN"
    DEBUG SMTP: Found extension "AUTH=LOGIN", arg "PLAIN"
    DEBUG SMTP: Found extension "8BITMIME", arg ""
    DEBUG SMTP: Found extension "HELP", arg ""
    STARTTLS
    220 Ready to start TLS
    EHLO CLIENT
    250-SERVER Hello CLIENT [192.1.1.1], pleased to meet you
    250-PIPELINING
    250-SIZE 100000000
    250-AUTH LOGIN PLAIN
    250-AUTH=LOGIN PLAIN
    250-8BITMIME
    250 HELP
    DEBUG SMTP: Found extension "PIPELINING", arg ""
    DEBUG SMTP: Found extension "SIZE", arg "100000000"
    DEBUG SMTP: Found extension "AUTH", arg "LOGIN PLAIN"
    DEBUG SMTP: Found extension "AUTH=LOGIN", arg "PLAIN"
    DEBUG SMTP: Found extension "8BITMIME", arg ""
    DEBUG SMTP: Found extension "HELP", arg ""
    DEBUG SMTP: Attempt to authenticate
    DEBUG SMTP: check mechanisms: LOGIN PLAIN DIGEST-MD5 
    AUTH LOGIN
    334 VXNlcn5hbWU6
    RVJOXHNsK2FyZmlu
    334 UGFzc3dvcmQ6
    UVdFUnF3ZXIxMjM0IUAjJA==
    535 Error: authentication failed
    DEBUG SMTP: useEhlo true, useAuth true
    DEBUG SMTP: trying to connect to host "SERVER", port 25, isSSL false
    220 SERVER ESMTP (deca81216f2ecf4fd6fedb030e3dcfd0)
    DEBUG SMTP: connected to host "SERVER", port: 25
    
    EHLO CLIENT
    250-SERVER Hello CLIENT [192.1.1.1], pleased to meet you
    250-STARTTLS
    250-PIPELINING
    250-SIZE 100000000
    250-AUTH LOGIN PLAIN
    250-AUTH=LOGIN PLAIN
    250-8BITMIME
    250 HELP
    DEBUG SMTP: Found extension "STARTTLS", arg ""
    DEBUG SMTP: Found extension "PIPELINING", arg ""
    DEBUG SMTP: Found extension "SIZE", arg "100000000"
    DEBUG SMTP: Found extension "AUTH", arg "LOGIN PLAIN"
    DEBUG SMTP: Found extension "AUTH=LOGIN", arg "PLAIN"
    DEBUG SMTP: Found extension "8BITMIME", arg ""
    DEBUG SMTP: Found extension "HELP", arg ""
    STARTTLS
    220 Ready to start TLS
    EHLO CLIENT
    250-SERVER Hello CLIENT [192.1.1.1], pleased to meet you
    250-PIPELINING
    250-SIZE 100000000
    250-AUTH LOGIN PLAIN
    250-AUTH=LOGIN PLAIN
    250-8BITMIME
    250 HELP
    DEBUG SMTP: Found extension "PIPELINING", arg ""
    DEBUG SMTP: Found extension "SIZE", arg "100000000"
    DEBUG SMTP: Found extension "AUTH", arg "LOGIN PLAIN"
    DEBUG SMTP: Found extension "AUTH=LOGIN", arg "PLAIN"
    DEBUG SMTP: Found extension "8BITMIME", arg ""
    DEBUG SMTP: Found extension "HELP", arg ""
    DEBUG SMTP: Attempt to authenticate
    DEBUG SMTP: check mechanisms: LOGIN PLAIN DIGEST-MD5 
    AUTH LOGIN
    334 VXNlcm5hbWU6
    RVJOXHNsZ2FyZmlu
    334 UGFzc3dvcmQ6
    UVdFUnF3ZXIxMjM0IUAjJA==
    535 Error: authentication failed
    Error sending mail: failed to connect
    javax.mail.AuthenticationFailedException: failed to connect
            at javax.mail.Service.connect(Service.java:322)
            at javax.mail.Service.connect(Service.java:172)
            at SignMessage.sendSigned(SignMessage.java:248)
            at SignMessage.main(SignMessage.java:340
    
    • nos
      nos almost 15 years
      I remember some similar thing with non java related clients, the username had to be in the form of DOMAIN\username and depending on how the excahnge server is set up, you might need the suffix also, so e.g. companyname\bob or companyname.COM\bob or companyname.local\bob
    • Ravi Wallau
      Ravi Wallau almost 15 years
      Yeah, I would try that as well. Add the domain information before the username, it should help.
  • Ami
    Ami almost 15 years
    Thanks. Unfortunately that didn't do it. I have two Exchange servers available, they are both configured differently, and the both behave the same way with your code as they did with my code. In both cases the servers are saying they can do GSSAPI NTLM and LOGIN and my system is saying LOGIN PLAIN DIGEST-MD5, so the javax.mail system is trying to do AUTH LOGIN and that is failing. It's weird. It work on every other system, just not exchange. Is there a GSSAPI implementation that I can use?
  • Ami
    Ami over 14 years
    Interesting, but I think that you are experiencing bystander effect. That is, I don't think that the changes you made resulted in the effect that you observed.
  • Admin
    Admin over 14 years
    I think it was due to disabling McAfee. At my workplace McAfee has build in firewall (I have no idea whether it is the way McAfee is bundled) and the firewall was blocking some of the applications.
  • egerardus
    egerardus about 12 years
    Disrelated to the OP's problem, but this answer completely resolved the Exchange Server's "No Logon Method Supported" problem I had been struggling with for about a day. Thanks!
  • Max P Magee
    Max P Magee almost 9 years
    I know this is super-old, but I'm adding the package imports necessary to make this answer complete.