others-how to solve java mail SMTP TLS error?

1. Purpose

In this post, I will demonstrate how to solve the following error or exception when using java mail to send emails via SMTP over TLS protocol:

javax.mail.MessagingException: Could not convert socket to TLS;
  nested exception is:
    javax.net.ssl.SSLException: Received fatal alert: protocol_version
    at com.sun.mail.smtp.SMTPTransport.startTLS(SMTPTransport.java:1907)
    at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:666)
    at javax.mail.Service.connect(Service.java:295)
    at com.bswen.wx.utils.EmailTest.sendMail(EmailTest.java:109)
    at com.bswen.wx.utils.EmailTest.main(EmailTest.java:58)
Caused by: javax.net.ssl.SSLException: Received fatal alert: protocol_version
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:208)
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
    at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:2023)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1125)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
    at com.sun.mail.util.SocketFetcher.configureSSLSocket(SocketFetcher.java:549)
    at com.sun.mail.util.SocketFetcher.startTLS(SocketFetcher.java:486)
    at com.sun.mail.smtp.SMTPTransport.startTLS(SMTPTransport.java:1902)
    ... 4 more

Process finished with exit code 0



2. Solution

2.1 The code that caused the problem

package com.bswen.email.utils;

import com.sun.mail.smtp.SMTPTransport;
import com.sun.mail.util.MailSSLSocketFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeUtility;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.util.Properties;

/**
 * email utils.
 */
public class EmailTest {
    private static Log log = LogFactory.getLog(EmailTest.class);
    private static final String host = "smtp.bswen.com";
    private static final int port = 587;
    private static final String sender = "[email protected]";
    private static final Properties props;
    private static final String senderPasswd = "******";


    public static  void sendMail(String subject,String body,
                                          String recipients) throws MessagingException {
        Properties tmpProps = props;
        String tmpSender = sender;
        String tmpPasswd = senderPasswd;
        Session mailSession = Session.getInstance(tmpProps, null);
        MimeMessage message = new MimeMessage(mailSession);
        try {
            InternetAddress from = new InternetAddress(tmpSender);
            message.setFrom(from);
            String[] recvUsers = parseRecipients(recipients);
            InternetAddress[] recipientsAdresses = new InternetAddress[recvUsers.length];
            int i=0;
            for(String recvUser:recvUsers) {
                InternetAddress to = new InternetAddress(recvUser);
                recipientsAdresses[i++]=to;
            }
            message.setRecipients(MimeMessage.RecipientType.TO, recipientsAdresses);
            try {
                message.setSubject(subject);
            } catch (UnsupportedEncodingException e) {
                message.setSubject(subject);
            }

            SMTPTransport t =
                    (SMTPTransport) mailSession.getTransport("smtp");
            t.connect(host,port, tmpSender, tmpPasswd);
            t.sendMessage(message, message.getAllRecipients());
        }
        catch (MessagingException e) {
            throw e;
        }
    }
}

The pom dependency of java mail:

        <dependency>
            <groupId>com.sun.mail</groupId>
            <artifactId>javax.mail</artifactId>
            <version>1.4.7</version>
        </dependency>

2.2 The solution

Upgrade the java mail jar :

Using 1.6 javax.mail jar as follows:

        <dependency>
            <groupId>com.sun.mail</groupId>
            <artifactId>javax.mail</artifactId>
            <version>1.6.2</version>
        </dependency>

If you get the following error after upgrading the dependency:

I got this error:

/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/bin/java 
javax.mail.MessagingException: Could not convert socket to TLS;
  nested exception is:
    javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at com.sun.mail.smtp.SMTPTransport.startTLS(SMTPTransport.java:2155)
    at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:752)
    at javax.mail.Service.connect(Service.java:366)
    at com.bswen.wx.utils.EmailTest.sendMail(EmailTest.java:109)
    at com.bswen.wx.utils.EmailTest.main(EmailTest.java:58)
Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1514)
    at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1026)
    at sun.security.ssl.Handshaker.process_record(Handshaker.java:961)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
    at com.sun.mail.util.SocketFetcher.configureSSLSocket(SocketFetcher.java:626)
    at com.sun.mail.util.SocketFetcher.startTLS(SocketFetcher.java:553)
    at com.sun.mail.smtp.SMTPTransport.startTLS(SMTPTransport.java:2150)
    ... 4 more
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:387)
    at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:230)
    at sun.security.validator.Validator.validate(Validator.java:260)
    at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
    at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
    at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1496)
    ... 14 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
    at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382)
    ... 20 more

Process finished with exit code 0

You can just add trust to the SMTP host/server. for example:

props.put("mail.smtp.starttls.enable", "true");
props.put("mail.smtp.ssl.trust", host);
props.put("mail.smtp.ssl.trust", host);

Because:

mail.smtp.ssl.trust String If set, and a socket factory hasn’t been specified, enables use of a MailSSLSocketFactory. If set to “*”, all hosts are trusted. If set to a whitespace separated list of hosts, those hosts are trusted. Otherwise, trust depends on the certificate the server presents.

3. Summary

In this post, I demonstrated how to solve the errors when using java mail to send email via SMTP servers. That’s it, thanks for your reading.