JavaMail 无法连接到 SMTP 主机 SSL 465:handshake_failure

JavaMail Could not connect to SMTP host SSL 465: handshake_failure

在我的网络服务器提供商禁用旧的安全协议(版本)和密码套件后,我无法再连接到 smtp 服务器。这是我的原始配置,但不再可能进行加密通信(SSL、TLS)。

这个问题的根源是什么?

DEBUG: setDebug: JavaMail version 1.5.5 (JDK 1.7)

当我在没有 SSL 的情况下尝试同样的操作时(在代码中注释),它工作正常,所以网络服务器一定有问题。有趣的事实:Outlook 工作正常(使用相同的凭据)!

public static void main(final String[] args) throws Exception {
    System.setProperty("javax.net.debug", "all");

    final Properties props = new Properties();

    // use SSL (worked before ssl-update on mailserver, where old security protocols were disabled)
    props.put("mail.smtp.ssl.socketFactory", "javax.net.ssl.SSLSocketFactory");
    props.put("mail.smtp.socketFactory.port", "465");
    props.put("mail.smtp.socketFactory.fallback", "false");
    props.put("mail.smtp.host", "alfa3022.alfahosting-server.de");
    props.put("mail.smtp.port", "465");
    props.put("mail.smtp.ssl.enable", "true");

    // no ssl (works fine!):
    // props.put("mail.debug", "true");
    // props.put("mail.smtp.host", SMTP_HOST_NAME);
    // props.put("mail.smtp.auth", "true");
    // props.put("mail.smtp.port", 587);

    final Session session = Session.getInstance(props, new javax.mail.Authenticator() {
        @Override
        protected PasswordAuthentication getPasswordAuthentication() {
            return new PasswordAuthentication(getEmailUsername(), getEmailPassword());
        }
    });

    session.setDebug(true);
    final Message msg = new MimeMessage(session);
    final InternetAddress addressFrom = new InternetAddress("test@test.com");
    msg.setFrom(addressFrom);

    // [...] create email object and add contents to msg
    msg.setRecipient(Message.RecipientType.BCC, new InternetAddress("dummy@test.com"));
    Transport.send(msg);

}

当我执行电子邮件服务器的握手模拟时,它告诉我 java 不工作?? https://www.ssllabs.com/ssltest/analyze.html?d=alfa3022.alfahosting-server.de

有什么区别或者我没看到什么?

您可以使用openssl来测试证书,这样您就可以解决握手失败的问题。

openssl s_client -connect mail.alfahosting-server.de:443

当我对你提到的那个主机进行操作时,我实际上得到了:

Verify return code: 20 (unable to get local issuer certificate)

What could be the source of this problem?

答:

SSLHandshakeExceptionIOException的子类,所以你不需要显式地catch。大多数开发人员不需要显式捕获,但它可以帮助您更轻松地诊断任何 IOException 的原因。

应用 -Djavax.net.debug=all 属性 时,与此 SSLHandshakeException 相关的失败将在日志中算法协商后立即出现。

因此,System.setProperty("javax.net.debug", "all"); 在您的代码中出错。

What is the root cause of occuring SSLHandshakeException? How to prevent it?

答:

SSLHandshakeException 最可能的原因是算法支持。 JDK 提供了一个名为 JCE Unlimited Strength 的单独包,旨在添加比默认可用的算法支持更强大的算法支持。 Qualys SSL Labs 提供了一个不同的 server SSL test,它将枚举服务器支持的算法。

添加更强的算法:JCE Unlimited Strength

在高安全性环境中,加强 JDK 中算法的一种方法是通过 JCE Unlimited Strength 策略文件。在这种特殊情况下,替换 JDK 7 中的那些策略文件允许它使用现有算法的更强大的变体并成功连接。

JCE 无限强度下载:JDK 8, JDK 7, or JDK 6.

资源Link:

  1. Diagnosing TLS, SSL, and HTTPS

你可以试试

您需要设置证书,才能访问 SMTP 端口。

System.setProperty("javax.net.ssl.trustStore","key");
System.setProperty("javax.net.ssl.trustStorePassword","password");

要生成 KeyStore 和 TrustStore,请遵循 tutorial


来自Marvin Pinto的回答,

当您尝试连接的服务器没有来自授权 CA 的有效证书时,通常会抛出 javax.net.ssl.SSLHandshakeException 异常。

简而言之,您尝试连接的服务器很可能使用的是自签名证书,您必须在 Java 代码中适应这一点。 This involves creating a custom KeyStore,等等。有关完整的实施细节,请参阅 this Stack Overflow 答案。

If you want to clarify your conception completely, then read the tutorial which is for use of SSL with JavaMail.

相关Link:

  1. JAVAMAIL API FAQ
  2. 收到致命警报:handshake_failure 通过 SSLHandshakeException