JavaMail使用SSL的方式登录
2016-08-16 19:25
375 查看
[java]
view plain
copy
print?
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
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。修改后,运行程序,又会出现一个新的异常:
[java]
view plain
copy
print?
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
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受信任的证书。那如何产生证书呢?通过下面的代码(如果没有看到请刷新页面):
来自CODE的代码片
InstallCert.java
编译该类并运行,运行时要传一个参数:SSL服务器域名:端口号,如:java InstallCert smtp.sina.com:465,不输端口的话默认为443。运行之后:
[plain]
view plain
copy
print?
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
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有这样的协议支持描述:
[plain]
view plain
copy
print?
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
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,那前面提到的程序只需这样:
[java]
view plain
copy
print?
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
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端口。
view plain
copy
print?
![](https://code.csdn.net/assets/CODE_ico.png)
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。修改后,运行程序,又会出现一个新的异常:
[java]
view plain
copy
print?
![](https://code.csdn.net/assets/CODE_ico.png)
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受信任的证书。那如何产生证书呢?通过下面的代码(如果没有看到请刷新页面):
/* * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * - Neither the name of Sun Microsystems nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *//** * http://blogs.sun.com/andreas/resource/InstallCert.java * Use: * java InstallCert hostname * Example: *% java InstallCert ecc.fedora.redhat.com */ import javax.net.ssl.*;import java.io.*;import java.security.KeyStore;import java.security.MessageDigest;import java.security.cert.CertificateException;import java.security.cert.X509Certificate; /** * Class used to add the server's certificate to the KeyStore * with your trusted certificates. */public class InstallCert { public static void main(String[] args) throws Exception { String host; int port; char[] passphrase; if ((args.length == 1) || (args.length == 2)) { String[] c = args[0].split(":"); host = c[0]; port = (c.length == 1) ? 443 : Integer.parseInt(c[1]); String p = (args.length == 1) ? "changeit" : args[1]; passphrase = p.toCharArray(); } else { System.out.println("Usage: java InstallCert <host>[:port] [passphrase]"); return; } File file = new File("jssecacerts"); if (file.isFile() == false) { char SEP = File.separatorChar; File dir = new File(System.getProperty("java.home") + SEP + "lib" + SEP + "security"); file = new File(dir, "jssecacerts"); if (file.isFile() == false) { file = new File(dir, "cacerts"); } } System.out.println("Loading KeyStore " + file + "..."); InputStream in = new FileInputStream(file); KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); ks.load(in, passphrase); in.close(); SSLContext context = SSLContext.getInstance("TLS"); TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(ks); X509TrustManager defaultTrustManager = (X509TrustManager) tmf.getTrustManagers()[0]; SavingTrustManager tm = new SavingTrustManager(defaultTrustManager); context.init(null, new TrustManager[]{tm}, null); SSLSocketFactory factory = context.getSocketFactory(); System.out.println("Opening connection to " + host + ":" + port + "..."); SSLSocket socket = (SSLSocket) factory.createSocket(host, port); socket.setSoTimeout(10000); try { System.out.println("Starting SSL handshake..."); socket.startHandshake(); socket.close(); System.out.println(); System.out.println("No errors, certificate is already trusted"); } catch (SSLException e) { System.out.println(); e.printStackTrace(System.out); } X509Certificate[] chain = tm.chain; if (chain == null) { System.out.println("Could not obtain server certificate chain"); return; } BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); System.out.println(); System.out.println("Server sent " + chain.length + " certificate(s):"); System.out.println(); MessageDigest sha1 = MessageDigest.getInstance("SHA1"); MessageDigest md5 = MessageDigest.getInstance("MD5"); for (int i = 0; i < chain.length; i++) { X509Certificate cert = chain[i]; System.out.println (" " + (i + 1) + " Subject " + cert.getSubjectDN()); System.out.println(" Issuer " + cert.getIssuerDN()); sha1.update(cert.getEncoded()); System.out.println(" sha1 " + toHexString(sha1.digest())); md5.update(cert.getEncoded()); System.out.println(" md5 " + toHexString(md5.digest())); System.out.println(); } System.out.println("Enter certificate to add to trusted keystore or 'q' to quit: [1]"); String line = reader.readLine().trim(); int k; try { k = (line.length() == 0) ? 0 : Integer.parseInt(line) - 1; } catch (NumberFormatException e) { System.out.println("KeyStore not changed"); return; } X509Certificate cert = chain[k]; String alias = host + "-" + (k + 1); ks.setCertificateEntry(alias, cert); OutputStream out = new FileOutputStream("jssecacerts"); ks.store(out, passphrase); out.close(); System.out.println(); System.out.println(cert); System.out.println(); System.out.println ("Added certificate to keystore 'jssecacerts' using alias '" + alias + "'"); } private static final char[] HEXDIGITS = "0123456789abcdef".toCharArray(); private static String toHexString(byte[] bytes) { StringBuilder sb = new StringBuilder(bytes.length * 3); for (int b : bytes) { b &= 0xff; sb.append(HEXDIGITS[b >> 4]); sb.append(HEXDIGITS[b & 15]); sb.append(' '); } return sb.toString(); } private static class SavingTrustManager implements X509TrustManager { private final X509TrustManager tm; private X509Certificate[] chain; SavingTrustManager(X509TrustManager tm) { this.tm = tm; } public X509Certificate[] getAcceptedIssuers() { throw new UnsupportedOperationException(); } public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { throw new UnsupportedOperationException(); } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { this.chain = chain; tm.checkServerTrusted(chain, authType); } } } |
InstallCert.java
编译该类并运行,运行时要传一个参数:SSL服务器域名:端口号,如:java InstallCert smtp.sina.com:465,不输端口的话默认为443。运行之后:
[plain]
view plain
copy
print?
![](https://code.csdn.net/assets/CODE_ico.png)
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有这样的协议支持描述:
[plain]
view plain
copy
print?
![](https://code.csdn.net/assets/CODE_ico.png)
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,那前面提到的程序只需这样:
[java]
view plain
copy
print?
![](https://code.csdn.net/assets/CODE_ico.png)
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端口。
相关文章推荐
- javamail使用SSL加密方式465端口
- SSH使用证书验证方式登录
- Video : 将使用AD认证的SharePoint网站配置为表单方式登录
- xmanager 的xshell的使用账号密码的登录方式
- SQLSERVER误删除了Windows登录用户验证方式使用Windows身份验证的解决方法
- 使用公钥登录SSL
- AR系列路由器使用SSH用户验证方式为password登录路由器的典型配置
- asp.net使用ODP即oracle连接方式的的防注入登录验证程序
- 域用户登录的方式-使用登录主名和登录名登录
- 禁止和恢复使用Windows身份验证方式登录SQL Server 2000
- python使用xauth方式登录饭否网然后发消息
- jQuery入门学习二:使用jQuery方式实现异步登录验证
- 设置IIS7只使用RC4方式做SSL计算
- Communicator使用TLS方式登录提示证书验证失败问题的解决
- linux 使用非当前登录运行程序方式,如root登录用test运行一个test.sh
- Video : 将使用AD认证的SharePoint网站配置为表单方式登录
- FreeBSD添加一个新用户并允许其使用ssh通过公私钥的方式登录
- 使用SSH密钥方式登录Linux
- SQLSERVER误删除了Windows登录用户验证方式使用Windows身份验证的解决方法
- asp.net使用ODP即oracle连接方式的的防注入登录验证程序