JavaMail 和 Oauth2:异常 "Can't send command to SMTP host" / "SSLHandshakeException: No appropriate protocol"
JavaMail and Oauth2: Exception "Can't send command to SMTP host" / "SSLHandshakeException: No appropriate protocol"
我尝试使用带有 OAuth2 的 JavaMail 发送邮件时出现以下异常:
javax.mail.MessagingException: Can't send command to SMTP host (javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate))
我已经检查了数十篇 Whosebug 帖子和 none 的解决方案。
这是我的 javamail 配置(注释掉了我尝试过的其他一些配置):
...
String oauth2_access_token = <procedure to aquire a token>;
Properties props = new Properties();
props.put("mail.host",config.getString("MAILSERVER"));
props.put("mail.smtp.port", config.getString("MAILPORT"));
props.put("mail.smtp.auth", "true");
props.put("mail.transport.protocol", "smtp");
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.smtp.starttls.required", "true");
props.put("mail.smtp.ssl.protocols", "TLSv1.1 TLSv1.2 TLSv1.3");
//props.put("mail.smtp.ssl.trust", "*");
props.put("mail.smtp.auth.mechanisms", "XOAUTH2");
//props.put("mail.smtp.auth.xoauth2.disable", false);
//props.put("mail.smtp.sasl.enable", "true");
//props.put("mail.smtp.auth.login.disable","true");
//props.put("mail.smtp.auth.plain.disable","true");
props.put("mail.debug", "true");
props.put("mail.debug.auth", "true");
// Connect
javax.mail.Session mailSession = javax.mail.Session.getInstance(props);
mailSession.setDebug(true);
SMTPTransport transport = (SMTPTransport) mailSession.getTransport("smtp");
transport.connect(config.getString("MAILSERVER"),
Integer.parseInt(config.getString("MAILPORT")), config.getString("MAILUSER"), oauth2_access_token);
这是一些输出:
[apache-tomcat-9.0.54]: DEBUG SMTP: useEhlo true, useAuth false
DEBUG SMTP: trying to connect to host "smtp.office365.com", port 587, isSSL false
[apache-tomcat-9.0.54]: 220 SOMEANONYMIZEDSERVERPREFIX.outlook.office365.com Microsoft ESMTP MAIL Service ready at Wed, 16 Mar 2022 10:16:37 +0000
DEBUG SMTP: connected to host "smtp.office365.com", port: 587
[apache-tomcat-9.0.54]: EHLO MY_COMPUTER_NAME
[apache-tomcat-9.0.54]: 250-SOMEANONYMIZEDSERVERPREFIX.outlook.office365.com Hello [MY_IP_ADRESS]
250-SIZE 157286400
250-PIPELINING
250-DSN
250-ENHANCEDSTATUSCODES
250-STARTTLS
250-8BITMIME
250-BINARYMIME
250-CHUNKING
250 SMTPUTF8
STARTTLS
[apache-tomcat-9.0.54]: 220 2.0.0 SMTP server ready
[apache-tomcat-9.0.54]: EHLO MY_COMPUTER_NAME
[apache-tomcat-9.0.54]: ERROR 2022-03-16 11:16:39,407 [..MyProgramException..] - javax.mail.MessagingException: Can't send command to SMTP host (javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate))
我认为这与发出 AUTH 命令有关,因为它未在输出中列出。通过 TLS 的连接已成功建立,因此我认为 SSLHandshake 异常可能具有误导性。那么给出了什么?
会不会和token有关?我必须用于令牌获取的范围是“.default”。 “Mail.Send”无效。
我正在使用最新的 JavaMail 版本 1.6.2 和 AdoptOpenJdk 11.0.12。
我还仔细检查了 java.security 配置。 TLS 1v2 和 1v3 算法未禁用。
我自己找到了解决方案。也许有人可以利用它:
据我所知,上面的代码没有错。实际原因是,我不应该使用带有客户端凭据的令牌获取,而应该只使用 username/password 和客户端 ID。
我不确定 JavaMail 是否支持这个,因为在文档中我找不到任何关于它的信息。关于此的罕见示例通常与客户端凭据有关。
正如你在上面看到的,没有触发 AUTH 命令,因为我显然没有权限。
我还需要做的是使用 Microsoft Graph API,不仅是通过“password/username 提供商”(this type) instead of the "client credential provider" (link) but also to actually trigger a send mail command via Microsoft Graph API (link) 获取令牌。
在我的案例中,客户端凭据提供者不够用,因为管理员没有指定发送邮件的权限。
因此,我不再为此使用 JavaMail,而是需要另一个令牌获取提供程序。
我尝试使用带有 OAuth2 的 JavaMail 发送邮件时出现以下异常:
javax.mail.MessagingException: Can't send command to SMTP host (javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate))
我已经检查了数十篇 Whosebug 帖子和 none 的解决方案。
这是我的 javamail 配置(注释掉了我尝试过的其他一些配置):
...
String oauth2_access_token = <procedure to aquire a token>;
Properties props = new Properties();
props.put("mail.host",config.getString("MAILSERVER"));
props.put("mail.smtp.port", config.getString("MAILPORT"));
props.put("mail.smtp.auth", "true");
props.put("mail.transport.protocol", "smtp");
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.smtp.starttls.required", "true");
props.put("mail.smtp.ssl.protocols", "TLSv1.1 TLSv1.2 TLSv1.3");
//props.put("mail.smtp.ssl.trust", "*");
props.put("mail.smtp.auth.mechanisms", "XOAUTH2");
//props.put("mail.smtp.auth.xoauth2.disable", false);
//props.put("mail.smtp.sasl.enable", "true");
//props.put("mail.smtp.auth.login.disable","true");
//props.put("mail.smtp.auth.plain.disable","true");
props.put("mail.debug", "true");
props.put("mail.debug.auth", "true");
// Connect
javax.mail.Session mailSession = javax.mail.Session.getInstance(props);
mailSession.setDebug(true);
SMTPTransport transport = (SMTPTransport) mailSession.getTransport("smtp");
transport.connect(config.getString("MAILSERVER"),
Integer.parseInt(config.getString("MAILPORT")), config.getString("MAILUSER"), oauth2_access_token);
这是一些输出:
[apache-tomcat-9.0.54]: DEBUG SMTP: useEhlo true, useAuth false
DEBUG SMTP: trying to connect to host "smtp.office365.com", port 587, isSSL false
[apache-tomcat-9.0.54]: 220 SOMEANONYMIZEDSERVERPREFIX.outlook.office365.com Microsoft ESMTP MAIL Service ready at Wed, 16 Mar 2022 10:16:37 +0000
DEBUG SMTP: connected to host "smtp.office365.com", port: 587
[apache-tomcat-9.0.54]: EHLO MY_COMPUTER_NAME
[apache-tomcat-9.0.54]: 250-SOMEANONYMIZEDSERVERPREFIX.outlook.office365.com Hello [MY_IP_ADRESS]
250-SIZE 157286400
250-PIPELINING
250-DSN
250-ENHANCEDSTATUSCODES
250-STARTTLS
250-8BITMIME
250-BINARYMIME
250-CHUNKING
250 SMTPUTF8
STARTTLS
[apache-tomcat-9.0.54]: 220 2.0.0 SMTP server ready
[apache-tomcat-9.0.54]: EHLO MY_COMPUTER_NAME
[apache-tomcat-9.0.54]: ERROR 2022-03-16 11:16:39,407 [..MyProgramException..] - javax.mail.MessagingException: Can't send command to SMTP host (javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate))
我认为这与发出 AUTH 命令有关,因为它未在输出中列出。通过 TLS 的连接已成功建立,因此我认为 SSLHandshake 异常可能具有误导性。那么给出了什么?
会不会和token有关?我必须用于令牌获取的范围是“.default”。 “Mail.Send”无效。
我正在使用最新的 JavaMail 版本 1.6.2 和 AdoptOpenJdk 11.0.12。
我还仔细检查了 java.security 配置。 TLS 1v2 和 1v3 算法未禁用。
我自己找到了解决方案。也许有人可以利用它:
据我所知,上面的代码没有错。实际原因是,我不应该使用带有客户端凭据的令牌获取,而应该只使用 username/password 和客户端 ID。
我不确定 JavaMail 是否支持这个,因为在文档中我找不到任何关于它的信息。关于此的罕见示例通常与客户端凭据有关。
正如你在上面看到的,没有触发 AUTH 命令,因为我显然没有权限。
我还需要做的是使用 Microsoft Graph API,不仅是通过“password/username 提供商”(this type) instead of the "client credential provider" (link) but also to actually trigger a send mail command via Microsoft Graph API (link) 获取令牌。
在我的案例中,客户端凭据提供者不够用,因为管理员没有指定发送邮件的权限。
因此,我不再为此使用 JavaMail,而是需要另一个令牌获取提供程序。