无法使用 OAuth 2 通过雅加达邮件连接到 Office 365 SMTP 服务器

Unable to connect to Office 365 SMTP Server via Jakarta Mail using OAuth 2


我目前正在尝试将 OAuth2 集成到 java 应用程序的现有电子邮件基础结构中。该应用程序使用 Jakarta 邮件,根据他们的文档支持 OAuth2 (https://eclipse-ee4j.github.io/mail/OAuth2)。出于某种原因,我正在努力连接到 Office 365 SMTP 服务器,而通过 IMAP 连接工作得很好。所以这是我到目前为止一直在做的事情:
  1. 创建 Office 365 开发者帐户,填充用户和用户数据。
  2. 登录azure后台,配置app注册,包括回调url等,以及以下api权限:https://i.stack.imgur.com/lXjER.png
  3. 使用以下验证方式url创建验证码:
https://login.microsoftonline.com/{my_tenant_id}/oauth2/v2.0/authorize?
client_id={my_client_id}&
state=state_to_check&
redirect_uri=http://localhost:5555/callback/authorization&
scope=offline_access https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/POP.AccessAsUser.All https://outlook.office.com/SMTP.Send
&response_type=code

如您所见,我正在使用以下范围:

offline_access 
https://outlook.office.com/IMAP.AccessAsUser.All 
https://outlook.office.com/POP.AccessAsUser.All 
https://outlook.office.com/SMTP.Send
  1. 检索授权码并使用它来获取刷新和访问令牌,得到以下响应:
{
    "token_type": "Bearer",
    "scope": "https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/Mail.Read https://outlook.office.com/Mail.Read.All https://outlook.office.com/Mail.Read.Shared https://outlook.office.com/Mail.ReadBasic https://outlook.office.com/Mail.ReadWrite https://outlook.office.com/Mail.Send https://outlook.office.com/Mail.Send.All https://outlook.office.com/Mail.Send.Shared https://outlook.office.com/POP.AccessAsUser.All https://outlook.office.com/SMTP.Send https://outlook.office.com/User.Read",
    "expires_in": 3599,
    "ext_expires_in": 3599,
    "access_token": ...,
    "refresh_token": ...
}

所以我想说,到目前为止,关于 OAuth 2.0 身份验证过程的一切都按预期进行。现在,继续使用访问令牌来访问用户的电子邮件帐户,我在我们的应用程序的电子邮件逻辑中添加了以下几行以通过 OAuth 启用 IMAP:

[more props stuff here]

if (useOauth) {
    props.put("mail." + protocol + ".auth", "true");
    props.put("mail." + protocol + ".auth.mechanisms", "XOAUTH2");
    props.put("mail." + protocol + ".auth.login.disable", "true");
    props.put("mail." + protocol + ".auth.plain.disable", "true");
}

return Session.getInstance(props);

这工作得很好,我可以通过 IMAP 连接、读取文件夹、消息等。我的问题是,如果我尝试以类似的方式为 SMTP 修改我们的代码,我会收到以下错误:

Exception in thread "main" jakarta.mail.AuthenticationFailedException: 451 4.7.0 Temporary server error. Please try again later. PRX4  [AM9P191CA0011.EURP191.PROD.OUTLOOK.COM]

    at com.sun.mail.smtp.SMTPTransport$Authenticator.authenticate(SMTPTransport.java:947)
    at com.sun.mail.smtp.SMTPTransport.authenticate(SMTPTransport.java:858)
    at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:762)
    at jakarta.mail.Service.connect(Service.java:342)
    at jakarta.mail.Service.connect(Service.java:222)
    at jakarta.mail.Service.connect(Service.java:243)
    at Application.main(Application.java:52)

我查看了在 github (https://github.com/eino-makitalo/vesa-mailtest/tree/master/src/main) 上找到的以下示例应用程序以及 Whosebug 上的几个答案,看看我是否遗漏了任何专门为 SMTP 设置的属性但是我使用以下配置使 运行ning 陷入同样的​​错误:

        Properties props = new Properties();
        props.put("mail.smtp.auth.xoauth2.disable", "false");
        props.put("mail.smtp.auth.mechanisms", "XOAUTH2");
        props.put("mail.smtp.starttls.enable", "true");

        props.put("mail.smtp.host","smtp.office365.com");
        props.put("mail.smtp.port", "587");
        props.put("mail.transport.protocol","smtp");

        props.put("mail.smtp.auth", "true");
        props.put("mail.smtp.auth.login.disable","true");
        props.put("mail.smtp.auth.plain.disable","true");

        props.put("mail.debug.auth", "true");

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

        Transport transport = session.getTransport("smtp");
        transport.connect( username, token);

现在我希望,也许有人 运行 以前解决过这个问题,并且可以帮助我。我能找到的关于上述异常帖子的唯一问题都与自定义交换服务器设置有关,以及您应该如何在这些服务器上配置 DNS 设置。但我认为这与我无关,因为我没有尝试连接到自定义交换服务器。

更新: 所以我用 google 服务尝试了相同的配置,它适用于 IMAP 和 SMTP,所以肯定是 Microsoft 服务有问题。但我仍然不确定我还能尝试什么让它发挥作用。

好的,找到问题了:出于某种原因,我没有想到尝试明确请求 openId 范围。不知道为什么,但出于某种原因,如果您没有明确指定,我会自动请求它。在明确请求 openId 后,SMTP 和 IMAP 都可以工作。