Java 邮件无法使用 tls 或 ssl 连接到 smtp

Posted

技术标签:

【中文标题】Java 邮件无法使用 tls 或 ssl 连接到 smtp【英文标题】:Java mail cannot connect to smtp using tls or ssl 【发布时间】:2020-06-24 12:44:29 【问题描述】:

0

我正在尝试从 Java 连接到邮件服务器。我已经能够使用相同的代码从 Java 成功连接到许多邮件服务器,包括 Gmail、Rackspace、GoDaddy 等,但是无论我尝试什么设置,这个都无法正常工作。

    props.put("mail.smtp.auth", "true");
    props.put("mail.smtp.starttls.enable", "true");
    props.put("mail.smtp.host", this.outgoingHost);
    props.put("mail.smtp.port", 587);
    props.put("mail.smtp.ssl.trust", this.outgoingHost);
    session = Session.getInstance(props, new javax.mail.Authenticator() 
        protected PasswordAuthentication getPasswordAuthentication() 
            return new PasswordAuthentication(username, password);
        
    );

这失败了,javax.mail.MessagingException: Could not convert socket to TLS;嵌套异常是:javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?

我也试过了,

    props.put("mail.smtp.host", this.outgoingHost);
    props.put("mail.smtp.port", 587);
    props.put("mail.smtp.socketFactory.port", 587);
    props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
    props.put("mail.smtp.auth", "true");
    props.put("mail.smtp.ssl.trust", this.outgoingHost);
    session = Session.getInstance(props, new javax.mail.Authenticator() 
        protected PasswordAuthentication getPasswordAuthentication() 
            return new PasswordAuthentication(username, password);
        
    );

这失败了,javax.mail.SendFailedException: Invalid Addresses;嵌套异常是:com.sun.mail.smtp.SMTPAddressFailedException: 550 SMTP AUTH is required for message submit on port 587

我也尝试了 465 端口,但它超时了。

我能够从 Thunderbird 电子邮件客户端使用相同的 smtp 设置发送邮件(相同的主机/端口/用户/密码,但它必须做其他事情)。

使用 Java 邮件 1.51

有什么想法吗?

【问题讨论】:

永远不要使用套接字工厂属性。尝试使用更新的 JavaMail 以防万一。将 JavaMail 调试输出与您正在使用的代码一起发布。 邮件服务器是由您还是您的组织管理?还是类似GMail的邮件服务? 您使用的是 Linux 吗?你可以运行nc -zvw3 outgoingHost 587 来检查服务器是否正在监听587 端口?检查 TLS 运行 openssl s_client -connect outgoingHost:587 -starttls smtp 不,邮件服务器属于客户端。 openssl 能够连接到服务器,我也能够使用相同的设置(主机/端口/tls)从 Thunderbird 电子邮件客户端进行连接。 【参考方案1】:

当您使用 SSL (smtps) 时,您不使用 STARTTLS (msa),反之亦然。 SSL 默认使用端口465,TLS 默认使用端口587。您可能还必须使用 mail.smtp.ssl.protocolsmail.smtps.ssl.protocols 设置 SSL 协议,以指定将为 SSL/TLS 连接启用的 SSL 协议。您最好避免覆盖 PasswordAuthentication 以发送凭据并使用 SMTPTransport connect 方法。同样非常重要的是,对于 SSL,您必须将 smtps 用于 mail.transport.protocol 并使用 mail.smtps 道具而不是 mail.smtp。我将提供 SSL 和 TLS 的示例。

您可以使用session.setDebug(true)props.put("mail.debug", "true") 在控制台中调试并查看整个通信;这将很有帮助,因为您将看到与服务器的整个 telnet 通信。

使用 TLS (STARTTLS) 587:

// Set debug so we see the whole communication with the server
props.put("mail.debug", "true");

props.put("mail.transport.protocol", "smtp");
props.put("mail.host", outgoingHost);
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.port", "587");

// Enable STARTTLS
props.put("mail.smtp.starttls.enable", "true");

// Accept only TLS 1.1 and 1.2
props.setProperty("mail.smtp.ssl.protocols", "TLSv1.1 TLSv1.2");

Session session = Session.getInstance(props, null);
session.setDebug(true);

// Create an SMTP transport from the session
SMTPTransport t = (SMTPTransport)session.getTransport("smtp");

// Connect to the server using credentials
t.connect(outgoingHost, username, password);

// Send the message
t.sendMessage(msg, msg.getAllRecipients());

使用 STARTTLS 的示例调试输出:

注意 TRANSPORT 协议是smtp

DEBUG: JavaMail version 1.5.1
...
DEBUG: setDebug: JavaMail version 1.5.1
DEBUG: getProvider() returning javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle]
DEBUG SMTP: useEhlo true, useAuth true
DEBUG SMTP: trying to connect to host "mail.example.com", port 587, isSSL false
220-srv.example.com ESMTP Exim 4.92 #2 Wed, 18 Mar 2020 15:55:56 +0200 
220-We do not authorize the use of this system to transport unsolicited, 
220 and/or bulk e-mail.
DEBUG SMTP: connected to host "mail.example.com", port: 587

EHLO host.docker.internal
250-srv.example.com Hello ppp.home.provider.com [x.x.x.x]
250-8BITMIME
250-PIPELINING
250-AUTH PLAIN LOGIN
250-STARTTLS
250 HELP
DEBUG SMTP: Found extension "SIZE", arg "52428800"
DEBUG SMTP: Found extension "8BITMIME", arg ""
DEBUG SMTP: Found extension "PIPELINING", arg ""
DEBUG SMTP: Found extension "AUTH", arg "PLAIN LOGIN"
DEBUG SMTP: Found extension "STARTTLS", arg ""
DEBUG SMTP: Found extension "HELP", arg ""
STARTTLS
220 TLS go ahead
EHLO host.docker.internal
250-srv.example.com Hello ppp.home.provider.com [x.x.x.x]
250-SIZE 52428800
250-8BITMIME
250-PIPELINING
250-AUTH PLAIN LOGIN
250 HELP
DEBUG SMTP: Found extension "SIZE", arg "52428800"
DEBUG SMTP: Found extension "8BITMIME", arg ""
DEBUG SMTP: Found extension "PIPELINING", arg ""
DEBUG SMTP: Found extension "AUTH", arg "PLAIN LOGIN"
DEBUG SMTP: Found extension "HELP", arg ""
DEBUG SMTP: Attempt to authenticate using mechanisms: LOGIN PLAIN DIGEST-MD5 NTLM 
DEBUG SMTP: AUTH LOGIN command trace suppressed
DEBUG SMTP: AUTH LOGIN succeeded
DEBUG SMTP: use8bit false
MAIL FROM:<user@example.com>
250 OK
RCPT TO:<otheruser@mail.com>
250 Accepted
DEBUG SMTP: Verified Addresses
DEBUG SMTP:   otheruser@mail.com
DATA
354 Enter message, ending with "." on a line by itself
Date: Wed, 18 Mar 2020 15:55:57 +0200 (EET)
From: user@example.com
To: otheruser@mail.com
Message-ID: <1899073220.0.1584539759931.JavaMail.user@mail.example.com>
Subject: Test from JAVA!
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
X-Mailer: smtpsend

Message from the JAVA app STARTTLS!
.
250 OK id=1jEZAt-009Y7x-5Z
Response: 250 OK id=1jEZAt-009Y7x-5Z

QUIT
221 srv.example.com closing connection

使用 SSL 465:

// Set debug so we see the whole communication with the server
props.put("mail.debug", "true");

// All mail props for protocol will be mail.smtps

// We set smtps transport protocol for SSL
props.put("mail.transport.protocol", "smtps");
props.put("mail.host", outgoingHost);
props.put("mail.smtps.auth", "true");
props.put("mail.smtps.port", "465");
props.put("mail.smtps.ssl.trust", outgoingHost);
props.put("mail.smtps.ssl.enable", "true");

// Accept only TLS 1.1 and 1.2
props.setProperty("mail.smtps.ssl.protocols", "TLSv1.1 TLSv1.2");

Session session = Session.getInstance(props, null);
session.setDebug(true);

// Create an SMTP transport from the session
SMTPTransport t = (SMTPTransport)session.getTransport("smtps");

// Connect to the server using credentials
t.connect(outgoingHost, username, password);

// Send the message
t.sendMessage(msg, msg.getAllRecipients());

使用 SSL 的示例调试输出:

注意 TRANSPORT 协议是smtps

DEBUG: JavaMail version 1.5.1
...
DEBUG: setDebug: JavaMail version 1.5.1
DEBUG: getProvider() returning javax.mail.Provider[TRANSPORT,smtps,com.sun.mail.smtp.SMTPSSLTransport,Oracle]
DEBUG SMTP: useEhlo true, useAuth true
DEBUG SMTP: trying to connect to host "mail.example.com", port 465, isSSL true
220-srv.example.com ESMTP Exim 4.92 #2 Wed, 18 Mar 2020 16:09:51 +0200 
220-We do not authorize the use of this system to transport unsolicited, 
220 and/or bulk e-mail.
DEBUG SMTP: connected to host "mail.example.com", port: 465

EHLO host.docker.internal
250-srv.example.com Hello ppp.home.provider.com [x.x.x.x]
250-SIZE 52428800
250-8BITMIME
250-PIPELINING
250-AUTH PLAIN LOGIN
250 HELP
DEBUG SMTP: Found extension "SIZE", arg "52428800"
DEBUG SMTP: Found extension "8BITMIME", arg ""
DEBUG SMTP: Found extension "PIPELINING", arg ""
DEBUG SMTP: Found extension "AUTH", arg "PLAIN LOGIN"
DEBUG SMTP: Found extension "HELP", arg ""
DEBUG SMTP: Attempt to authenticate using mechanisms: LOGIN PLAIN DIGEST-MD5 NTLM 
DEBUG SMTP: AUTH LOGIN command trace suppressed
DEBUG SMTP: AUTH LOGIN succeeded
DEBUG SMTP: use8bit false
MAIL FROM:<user@example.com>
250 OK
RCPT TO:<otheruser@mail.com>
250 Accepted
DEBUG SMTP: Verified Addresses
DEBUG SMTP:   otheruser@mail.com
DATA
354 Enter message, ending with "." on a line by itself
Date: Wed, 18 Mar 2020 16:09:50 +0200 (EET)
From: user@example.com
To: otheruser@mail.com
Message-ID: <1620303253.0.1584540592904.JavaMail.user@mail.example.com>
Subject: Test from JAVA!
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
X-Mailer: smtpsend

Message from the JAVA app SSL!
.
250 OK id=1jEZOK-009bbA-5C
Response: 250 OK id=1jEZOK-009bbA-5C

QUIT
221 srv.example.com closing connection

【讨论】:

SMTP 现在更可能是 STARTTLS。我只想提一下端口 465 已被弃用,并且由于它由 Cisco 正式持有,因此不应与任何相关邮件一起使用。 @NPULSENET 是的,我同意,465 现在已弃用。端口465smtps 协议,端口587msa (What is the difference between ports 465 and 587?)。我将其添加到我的答案中,因为 OP 确实提到了它,并且也许他们的客户端有一个仅支持 SSL over 465 的服务器。事实上,我的所有服务器(第三个托管服务提供商)仍然支持465 和端口25,但如果支持,应该始终使用587 谢谢,我会试试调试选项。但是,因为我有太多失败的尝试,客户端的邮件服务器现在阻止了我......需要从不同的 IP 尝试 @James 是的。服务器很可能有"ConfigServer Security & Firewall (csf)",它将临时块添加到登录尝试失败次数过多的IP。使用默认配置,这些 IP 将在 30 分钟后解除阻止,但您可以重新启动路由器以获取新 IP 并尝试再次连接到 SMPT 服务器。这种情况下很难调试。【参考方案2】:

检查此链接以启用权限(如果发件人有谷歌电子邮件):

Link Permission Google

未经许可,您不能从非谷歌开发的应用登录。

对于登录仅使用您的邮件域。例如:text@gmail.com -> 文本

【讨论】:

以上是关于Java 邮件无法使用 tls 或 ssl 连接到 smtp的主要内容,如果未能解决你的问题,请参考以下文章

Java Secure Websocket - 从 TLS 证书文件加载 SSL 上下文并连接到 WSS URI

自 SSL/TLS 证书更新以来,Django 应用程序未连接到 RDS

Amazon MQ 客户端使用哪个 TLS/SSL 版本连接到代理?

使用 JDBC Thin 和 JKS 的 Oracle 数据库 TLS1.2/SSL 连接

在 Codeigniter 中无法发送电子邮件 - fsockopen():无法连接到 ssl://smtp.gmail.com:465(连接被拒绝)

请求被中止 无法在共享托管服务器 C# 上创建 ssl/tls 安全通道