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,而是需要另一个令牌获取提供程序。