使用JavaMail和自签名证书

6

我有一个包含以下代码的servlet:

System.setProperty("javax.net.ssl.keyStore", getServletContext().getRealPath("keystore.jks"));
System.setProperty("javax.net.ssl.keyStorePassword", "123456");
System.setProperty("javax.net.ssl.trustStore",getServletContext().getRealPath("keystore.jks"));
System.setProperty("javax.net.ssl.trustStorePassword","123456");

SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket("127.0.0.1", 606);

使用这段代码,我能够使用SSL(这在我的情况下是必须的)。在同一个servlet中,我需要使用JavaMail发送电子邮件。当我尝试发送此电子邮件而不使用其他代码中的证书时,它可以正常工作,但当我尝试使用它时,会返回以下消息: 使用端口465 ->

DEBUG: setDebug: JavaMail version 1.4.7
DEBUG: setDebug: JavaMail version 1.4.7
DEBUG: getProvider() returning javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle]
DEBUG SMTP: useEhlo true, useAuth true
DEBUG SMTP: useEhlo true, useAuth true
DEBUG SMTP: trying to connect to host "smtp.gmail.com", port 465, isSSL false

然后被卡住了 =p。

使用587端口 ->

DEBUG: setDebug: JavaMail version 1.4.7
DEBUG: getProvider() returning javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle]
DEBUG SMTP: useEhlo true, useAuth true
DEBUG SMTP: useEhlo true, useAuth true
DEBUG SMTP: trying to connect to host "smtp.gmail.com", port 587, isSSL false
220 mx.google.com ESMTP g66sm55412571yhd.11 - gsmtp
DEBUG SMTP: connected to host "smtp.gmail.com", port: 587

EHLO RAI-PC
250-mx.google.com at your service, [201.82.118.174]
250-SIZE 35882577
250-8BITMIME
250-STARTTLS
250 ENHANCEDSTATUSCODES
DEBUG SMTP: Found extension "SIZE", arg "35882577"
DEBUG SMTP: Found extension "8BITMIME", arg ""
DEBUG SMTP: Found extension "STARTTLS", arg ""
DEBUG SMTP: Found extension "ENHANCEDSTATUSCODES", arg ""
DEBUG SMTP: use8bit false
MAIL FROM:<raiavancinifranco@gmail.com>
530 5.7.0 Must issue a STARTTLS command first. g66sm55412571yhd.11 - gsmtp
DEBUG SMTP: got response code 530, with response: 530 5.7.0 Must issue a STARTTLS command first. g66sm55412571yhd.11 - gsmtp

RSET
250 2.1.5 Flushed g66sm55412571yhd.11 - gsmtp
DEBUG SMTP: MessagingException while sending, THROW: 
com.sun.mail.smtp.SMTPSendFailedException: 530 5.7.0 Must issue a STARTTLS command first. g66sm55412571yhd.11 - gsmtp

    at com.sun.mail.smtp.SMTPTransport.issueSendCommand(SMTPTransport.java:2108)
    at com.sun.mail.smtp.SMTPTransport.mailFrom(SMTPTransport.java:1609)
    at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1117)
    at javax.mail.Transport.send0(Transport.java:195)
    at javax.mail.Transport.send(Transport.java:124)
    at servlet.Main.service(Main.java:221)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
QUIT
221 2.0.0 closing connection g66sm55412571yhd.11 - gsmtp
Jul 10, 2013 7:04:40 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [servletMain] in context with path [/servicotcc] threw exception
java.lang.RuntimeException: com.sun.mail.smtp.SMTPSendFailedException: 530 5.7.0 Must issue a STARTTLS command first. g66sm55412571yhd.11 - gsmtp

    at servlet.Main.service(Main.java:226)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Caused by: com.sun.mail.smtp.SMTPSendFailedException: 530 5.7.0 Must issue a STARTTLS command first. g66sm55412571yhd.11 - gsmtp

    at com.sun.mail.smtp.SMTPTransport.issueSendCommand(SMTPTransport.java:2108)
    at com.sun.mail.smtp.SMTPTransport.mailFrom(SMTPTransport.java:1609)
    at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1117)
    at javax.mail.Transport.send0(Transport.java:195)
    at javax.mail.Transport.send(Transport.java:124)
    at servlet.Main.service(Main.java:221)
    ... 17 more

属性代码如下:
Properties props = new Properties();
props.put("mail.smtp.host", "smtp.gmail.com");
props.put("mail.smtp.socketFactory.port", "465");
props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.port", "465");

我不能像这样发送电子邮件(我不确定具体原因是什么)。我该怎么办?

-- 编辑 --

在将谷歌SMTP证书导入我的密钥库并更改端口和属性后:

Properties props = new Properties(); 
props.put("mail.smtp.host", "smtp.gmail.com");
props.put("mail.smtp.socketFactory.port", "465");
props.put("mail.smtp.socketFactory.class", sslsocketfactory);
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.port", "465");
props.put("mail.smtp.ssl.enable", "true");
props.put("mail.smtp.starttls.enable", "true");

我的输出变成了:

DEBUG: setDebug: JavaMail version 1.4.7
DEBUG: getProvider() returning javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle]
DEBUG SMTP: useEhlo true, useAuth true
DEBUG SMTP: useEhlo true, useAuth true
DEBUG SMTP: trying to connect to host "smtp.gmail.com", port 465, isSSL true
Jul 10, 2013 8:26:46 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [servletMain] in context with path [/servicotcc] threw exception
java.lang.RuntimeException: javax.mail.MessagingException: Could not connect to SMTP host: smtp.gmail.com, port: 465;
  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 servlet.Main.service(Main.java:229)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Caused by: javax.mail.MessagingException: Could not connect to SMTP host: smtp.gmail.com, port: 465;
  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.openServer(SMTPTransport.java:1961)
    at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:654)
    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 servlet.Main.service(Main.java:224)
    ... 17 more
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(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 com.sun.mail.util.SocketFetcher.configureSSLSocket(SocketFetcher.java:549)
    at com.sun.mail.util.SocketFetcher.createSocket(SocketFetcher.java:354)
    at com.sun.mail.util.SocketFetcher.getSocket(SocketFetcher.java:237)
    at com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:1927)
    ... 24 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(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)
    ... 36 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)
    ... 42 more
3个回答

15

摆脱Socket Factory相关内容:

设置各种socketFactory属性。很久以前,JavaMail没有内置对SSL连接的支持,因此需要设置这些属性来使用SSL。多年来已经不再需要这样做了;删除这些属性并简化您的代码。在当前版本的JavaMail中启用SSL支持的最简单方法是将属性"mail.smtp.ssl.enable"设置为"true"。(根据需要将"smtp"替换为"imap"或"pop3")。

请参阅这些Gmail示例

Gmail证书需要在您的信任存储库中,而不是您的密钥存储库中。


6
解决方案 - 将属性更改为:
 Properties props = new Properties();
 props.put("mail.smtp.host", "smtp.gmail.com");
 props.put("mail.smtp.socketFactory.port", "587");
 props.put("mail.smtp.socketFactory.class", "javax.net.SocketFactory");
 props.put("mail.smtp.auth", "true");
 props.put("mail.smtp.port", "587");
 props.put("mail.smtp.ssl.enable", "false");
 props.put("mail.smtp.starttls.enable", "true");
 props.put("mail.smtp.ssl.trust", "smtp.gmail.com");

2
这有什么区别?"mail.smtp.ssl.enable","false"是做什么用的? - Menelaos
1
删除所有具有套接字工厂的属性。对于SSL连接,请使用props.put("mail.smtp.ssl.enable", "true"),对于TLS连接,请使用props.put("mail.smtp.starttls.enable", "true"); - kevenlolo
@MenelaosBakopoulos 不同之处在于 mail.smtp.ssl.trust 属性。请参考我的回答。 - Stefan Haberl

0

我可能有点晚加入这个项目,但我遇到了与连接到在Docker容器中运行的SMTP服务器相同的问题。

SMTP服务器会在每次容器启动时重新创建自签名证书,我不想一直尝试将该证书导入到我的本地信任存储库中。

关键在于设置mail.smtp.ssl.trust属性以包括您要连接到的主机,使得Java Mail将接受自签名证书。

https://javaee.github.io/javamail/docs/api/com/sun/mail/smtp/package-summary.html

供参考,我的工作属性(在这种情况下是在旧式的Spring XML文件中指定的,但你可以理解这个想法):

<property name="javaMailProperties">
  <props>
    <prop key="mail.smtp.auth">true</prop>
    <prop key="mail.smtp.starttls.enable">true</prop>
    <prop key="mail.smtp.ssl.protocols">TLSv1.2</prop>
    <prop key="mail.smtp.ssl.trust">*</prop> <!-- put your host name there or just use * for all -->
  </props>
</property>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接