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

email, exchange-server, jakarta-mail, java, smtp-auth

Solution

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.

Problem

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 ```

Original source