之前一直采用jre-1.8和jdk-1.8,基本还顺利。今年升级了服务器硬件,顺便就升级了jre和jdk到版本17,然后就出现了一些问题。其中最棘手的就是这个javax.mail报的错:
- Exception in thread "main" java.lang.RuntimeException: javax.mail.MessagingException: Could not convert socket to TLS;
- nested exception is:
- javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
- at util.EmailEncrypt.sendMessageToMe(EmailEncrypt.java:60)
- at util.EmailEncrypt.main(EmailEncrypt.java:17)
- Caused by: javax.mail.MessagingException: Could not convert socket to TLS;
- nested exception is:
- javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
- 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:317)
- at javax.mail.Service.connect(Service.java:176)
- at javax.mail.Service.connect(Service.java:125)
- at javax.mail.Transport.send0(Transport.java:194)
- at javax.mail.Transport.send(Transport.java:124)
- at util.EmailEncrypt.sendMessageToMe(EmailEncrypt.java:56)
- ... 1 more
- Caused by: javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
- at java.base/sun.security.ssl.HandshakeContext.
(HandshakeContext.java:172) - at java.base/sun.security.ssl.ClientHandshakeContext.
(ClientHandshakeContext.java:103) - at java.base/sun.security.ssl.TransportContext.kickstart(TransportContext.java:240)
- at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:448)
- at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:426)
- 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)
- ... 8 more
原代码如下:
- public static void main(String[] args) {
- EmailEncrypt.sendMessageToMe("toMe", "toMeOnly");
- }
-
- public static void sendMessageToMe(String subject, String body) {
-
- // 服务器名称: smtp.office365.com
- // 端口: 587
- // 加密方法: STARTTLS
-
- final String username = "*****";
- final String password = "*****";
-
- Properties props = new Properties();
- props.put("mail.smtp.auth", "true");
- props.put("mail.smtp.starttls.enable", "true");
- props.put("mail.smtp.host", "smtp.office365.com");
- props.put("mail.smtp.port", "587");
-
- Session session = Session.getInstance(props,
- new javax.mail.Authenticator() {
- protected PasswordAuthentication getPasswordAuthentication() {
- return new PasswordAuthentication(username, password);
- }
- });
-
- try {
- Message message = new MimeMessage(session);
- message.setFrom(new InternetAddress("*****"));
- message.setRecipients(Message.RecipientType.TO, InternetAddress.parse("*****"));
- message.setSubject(subject);
- message.setText(body);
-
- Transport.send(message);
- System.out.println("Done");
-
- } catch (MessagingException e) {
- throw new RuntimeException(e);
- }
- }
试过一些方法:
一、在代码中增加props.put("mail.smtp.ssl.trust", "smtp-mail.outlook.com"),没成功。
二、去/jdk-17.jdk/Contents/Home/lib/security调整文件,没找到对应的表述。
三、问过C知道,建议我:“禁用TLS,在代码中设置mail.smtp.starttls.enable为false。”这就是扯淡,毕竟outlook要求采用STARTTLS,我如果不设置,怎么可能连得上服务器呢?
四、问了星火,其中有一条:“检查您的JavaMail代码是否正确设置了TLS选项。确保您已正确指定了TLS端口和协议版本。例如,对于Gmail,TLS端口是587,协议版本是STARTTLS。”好像是有点意思,但我开始没有理解。
最后,直接去了bing国际,看到一位外国友人给出以下方法:
props.put("mail.smtp.ssl.protocols", "TLSv1.2");
成功。
再看星火给的答案是相对靠谱的,Java-17需要显式指定TLS的协议版本,才可以正确运行。
有兴趣的同学,可以再试一下TLSv1.1、TLSv1.3之类的。