本文来自: 高爽|Coder,原文地址: http://blog.csdn.net/ghsau/article/details/17779165,转载请注明。
以这个错误信息为文章标题是不是更醒目一点,这是JavaMail使用SSL的方式登录邮箱时抛出的异常。代码如:
public class JavaMailTest1 {
public static void main(String[] args) throws MessagingException {
Properties props = new Properties();
props.setProperty("mail.debug", "true");
props.setProperty("mail.smtp.auth", "true");
props.setProperty("mail.transport.protocol", "smtp");
// SSL
props.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
props.setProperty("mail.smtp.socketFactory.fallback", "false");
props.setProperty("mail.smtp.port", "465");
props.setProperty("mail.smtp.socketFactory.port", "465");
Session session = Session.getInstance(props);
Message msg = new MimeMessage(session);
msg.setText("你好吗?");
msg.setFrom(new InternetAddress("发件箱地址"));
Transport transport = session.getTransport();
transport.connect("smtp.sina.com", "用户名", "密码");
transport.sendMessage(msg, new Address[] {new InternetAddress("收件箱地址")});
transport.close();
}
}
解决该问题方式:将端口号修改成465。通常服务器的SSL端口是443,邮箱服务器中的是465。修改后,运行程序,又会出现一个新的异常:
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.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)
这通常意味着是该服务器使用的是测试证书(使用密钥工具可能产生的),而不是从一个著名的商业证书颁发机构如Verisign或GoDaddy的证书。 在此情况下,但由于JSSE(
Java(TM)SecureSocketExtension)不能假定一个交互式的用户存在,它只是在默认情况下会抛出异常。解决该问题的思路就是将你要连接的SSL服务器的证书添加为JSSE受信任的证书。那如何产生证书呢?通过下面的代码(如果没有看到请刷新页面): 编译该类并运行,运行时要传一个参数:SSL服务器域名:端口号,如:java InstallCert smtp.sina.com:465,不输端口的话默认为443。运行之后:
Loading KeyStore C:\Program Files\Java\jre7\lib\security\cacerts...
Opening connection to smtp.sina.com:465...
Starting SSL handshake...
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(Unknown Source)
at sun.security.ssl.SSLSocketImpl.fatal(Unknown Source)
at sun.security.ssl.Handshaker.fatalSE(Unknown Source)
at sun.security.ssl.Handshaker.fatalSE(Unknown Source)
at sun.security.ssl.ClientHandshaker.serverCertificate(Unknown Source)
at sun.security.ssl.ClientHandshaker.processMessage(Unknown Source)
at sun.security.ssl.Handshaker.processLoop(Unknown Source)
at sun.security.ssl.Handshaker.process_record(Unknown Source)
at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at InstallCert.main(InstallCert.java:97)
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(Unknown Source)
at sun.security.validator.PKIXValidator.engineValidate(Unknown Source)
at sun.security.validator.Validator.validate(Unknown Source)
at sun.security.ssl.X509TrustManagerImpl.validate(Unknown Source)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(Unknown Source)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source)
at InstallCert$SavingTrustManager.checkServerTrusted(InstallCert.java:192)
at sun.security.ssl.AbstractTrustManagerWrapper.checkServerTrusted(Unknown Source)
... 9 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(Unknown Source)
at java.security.cert.CertPathBuilder.build(Unknown Source)
... 17 more
Server sent 1 certificate(s):
1 Subject CN=*.sina.com, O="Sina.com Technology(China)Co.,ltd", L=Beijing, ST=Beijing, C=CN, SERIALNUMBER=mL/iTnzl-0Pr1rH-6U2RZH/h3zFjZxoK
Issuer CN=GeoTrust SSL CA, O="GeoTrust, Inc.", C=US
sha1 43 a9 5b bc 9b 86 85 99 e3 21 63 af b0 09 78 4a 67 25 d7 a1
md5 90 c2 45 da 67 68 cd c2 44 56 21 ef ed c6 6b 5e
Enter certificate to add to trusted keystore or 'q' to quit: [1]
抛出了与我们程序中同样的错误,这里我们输入1,回车。它又输出了一堆信息,这里不粘了,这时证书已经生成了,在哪呢?在InstallCert.java所在的目录中,有一个名为jssecacerts的文件,这就是我们要的证书。将其放到我们程序所在的JSSE中,$JAVA_HOME/jre/lib/security。这时,再次运行我们的发邮件程序,发送成功。
更新2014-01-04:
今天无意中看到了JavaMail有这样的协议支持描述:
Protocol Store or Uses Supports
Name Transport? SSL? STARTTLS?
-------------------------------------------------
imap Store No Yes
imaps Store Yes N/A
pop3 Store No Yes
pop3s Store Yes N/A
smtp Transport No Yes
smtps Transport Yes N/A
Transport使用SSL连接邮箱协议名称需要使用smtps,而不是smtp,那前面提到的程序只需这样:
public class JavaMailTest1 {
public static void main(String[] args) throws MessagingException {
Properties props = new Properties();
props.setProperty("mail.debug", "true");
props.setProperty("mail.smtp.auth", "true");
// 协议名称设置为smtps,会使用SSL
props.setProperty("mail.transport.protocol", "smtps");
Session session = Session.getInstance(props);
Message msg = new MimeMessage(session);
msg.setText("你好吗?");
msg.setFrom(new InternetAddress("发件箱地址"));
Transport transport = session.getTransport();
transport.connect("smtp.sina.com", "用户名", "密码");
transport.sendMessage(msg, new Address[] {new InternetAddress("收件箱地址")});
transport.close();
}
}
这样,JavaMail会自动使用SSL,并且使用465端口。
参考: https://java.net/projects/javamail/pages/InstallCert http://infposs.blogspot.com/2013/06/installcert-and-java-7.html
本文来自: 高爽|Coder,原文地址: http://blog.csdn.net/ghsau/article/details/17779165,转载请注明。