背景
今天在做发邮件的功能,在我的电脑上本机测试发邮件是没有问题的,我使用的是javax.mail的jar包来实现的发邮件的功能,但是在服务器上测试该功能的时候出现了错误,错误如下:
javax.mail.MessagingException: Could not connect to SMTP host: smtphz.qiye.163.com, port: 465;
nested exception is:
javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
at com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:1972)
at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:642)
at javax.mail.Service.connect(Service.java:295)
at javax.mail.Service.connect(Service.java:176)
很奇怪,我的电脑是可以的,但是服务器上是不行的。
解决
初步怀疑是jdk的问题,可能我本机的jdk里面添加过相关的证书(此时我并未查证,主要还得现去找命令。。。),于是我直接在服务器上的jdk里面添加了smtphz.qiye.163.com:465相关的证书,操作如下:
-
使用 openssl 导出目标服务器的证书:
openssl s_client -connect smtphz.qiye.163.com:465 -showcerts < /dev/null | openssl x509 -outform PEM > smtp_cert.pem
-
将生成的证书导入 Java 的信任库(cacerts 文件)
keytool -import -alias smtp_cert -keystore $JAVA_HOME/jre/lib/security/cacerts -file smtp_cert.pem
另外:我的JAVA_HOME是没有设置的,是空的,我用的是ubuntu系统,所以常见的jdk的安装目录是在:ls /usr/lib/jvm/ 目录下
-
检查证书是否已成功导入:
keytool -list -keystore $JAVA_HOME/jre/lib/security/cacerts -alias smtp_cert
此时需要输入密码,默认密码是:changeit。如果你更改过密码,那么请输入更改后的密码。
-
重启应用
一番操作下来还是不生效。那么就得换思路了。我是在代码中强制指定了属性的设置:
Properties props = new Properties();
props.put("mail.smtp.host", "smtphz.qiye.163.com");
props.put("mail.smtp.port", "465");
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.ssl.enable", "true");
// 这里加上了这一行的属性设置
props.put("mail.smtp.ssl.protocols", "TLSv1.2");
Session session = Session.getInstance(props, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("your-email@example.com", "your-password");
}
});
然后重启服务后就生效了。
当然也可以尝试启用所有可用的 SSL/TLS 协议,确保客户端能够匹配服务器支持的协议:
props.put("mail.smtp.ssl.protocols", "TLSv1.2 TLSv1.1 TLSv1 SSLv3");