You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用XOAuth2+Spring Boot+JavaMail通过Office365 SMTP发件认证失败求助

问题:Java应用通过SMTP(office365) + XOAuth2认证发送邮件失败

概述

我正尝试在Java应用中通过SMTP服务器smtp.office365.com,采用XOAuth2协议完成认证后发送邮件。

Azure AD配置信息

  1. 注册新应用程序
    1.1 在认证部分
    • 添加“桌面和移动应用”平台,并为重定向URI选择MSAL
    • 启用“无键盘”流程
      1.2 在证书和机密部分
    • 生成有效的客户端机密(Client Secret)
  2. 在托管应用程序中
    2.1 在用户部分
    • 添加发件邮箱地址(messagerie@domain.com)所属的用户

application.properties配置

# Spring
spring.mail.host=smtp.office365.com
spring.mail.protocol=smtp
spring.mail.port=587
spring.mail.username=messagerie@domain.com
spring.mail.properties.mail.smtp.ssl.enable=false
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.sasl.enable=true
spring.mail.properties.mail.smtp.sasl.mechanisms=XOAUTH2
spring.mail.properties.mail.smtp.auth.xoauth2.authority=https://login.microsoftonline.com/e***a/
spring.mail.properties.mail.smtp.auth.xoauth2.client.id=b***c
spring.mail.properties.mail.smtp.auth.xoauth2.client.secret=4***A
spring.mail.properties.mail.smtp.auth.xoauth2.scope=https://graph.microsoft.com/.default
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.test-connection=false
spring.mail.properties.mail.debug=true

MailHelper.java代码

@Component
public class MailHelper {
    private String clientId;
    private String clientSecret;
    private String scope;
    private String authority;
    private String username;
    private JavaMailSender emailSender;

    private IAuthenticationResult getToken() throws MalformedURLException {
        final IConfidentialClientApplication app = ConfidentialClientApplication.builder(
                this.clientId, 
                ClientCredentialFactory.createFromSecret(this.clientSecret))
            .authority(this.authority)
            .build();
        final ClientCredentialParameters parameters = ClientCredentialParameters.builder(
                Collections.singleton(this.scope))
            .build();
        return app
            .acquireToken(parameters)
            .join();
    }

    public void send(final MimeMessage message) throws MessagingException {
        if (StringUtils.isNoneBlank(this.clientId, this.clientSecret, this.scope, this.authority)) {
            try {
                final StringBuilder passwordBuilder = new StringBuilder();
                passwordBuilder.append("user=").append(this.username)
                        .append('\u0001')
                        .append("auth=").append("Bearer ").append(getToken().accessToken())
                        .append('\u0001').append('\u0001');

                final String base64Password = Base64.getEncoder().encodeToString(passwordBuilder.toString().getBytes(StandardCharsets.UTF_8));

                ((JavaMailSenderImpl) this.emailSender).setPassword(base64Password);
            } catch (final MalformedURLException e) {
                throw new MessagingException("无法初始化OAuth2连接", e);
            }
        }
        this.emailSender.send(message);
    }
}

补充信息

  • messagerie@domain.com账号可通过登录密码连接该SMTP发送邮件
  • 通过MSAL4J获取accessToken的过程正常
  • 尝试过直接将accessToken传入((JavaMailSenderImpl) this.emailSender).setPassword(base64Password);,而非拼接用户信息与accessToken
  • 尝试使用Microsoft GraphAPI,但除OAuth信息外仍要求输入密码,因此未深入探索该方案

错误信息

  • JavaMail返回:535 5.7.3 Authentication unsuccessful [LO4P265CA0135.GBRP265.PROD.OUTLOOK.COM]
  • SMTP返回:DEBUG SMTP: SASL authentication failed,被封装在org.springframework.mail.MailAuthenticationException: Authentication failed; nested exception is javax.mail.AuthenticationFailedException: failed to connect 中

解决方案

1. 补全Azure AD应用权限

当前用的客户端凭证模式需要应用拥有Exchange Online的SMTP.Send应用权限,且必须完成管理员授权:

  • 进入Azure AD应用的「API权限」页面
  • 添加权限 → 选择「Exchange」→「应用权限」→ 勾选SMTP.Send
  • 点击「授予管理员同意」,确保权限生效

2. 修正Scope配置

https://graph.microsoft.com/.default不适用于SMTP协议,替换为SMTP专属Scope:

spring.mail.properties.mail.smtp.auth.xoauth2.scope=https://outlook.office365.com/SMTP.Send

3. 简化JavaMail的OAuth2认证逻辑

JavaMailSenderImpl原生支持XOAuth2,无需手动拼接Base64密码,直接设置token即可:

public void send(final MimeMessage message) throws MessagingException {
    if (StringUtils.isNoneBlank(this.clientId, this.clientSecret, this.scope, this.authority)) {
        try {
            IAuthenticationResult tokenResult = getToken();
            JavaMailSenderImpl senderImpl = (JavaMailSenderImpl) this.emailSender;
            // 直接在Session中设置OAuth2 token
            senderImpl.getSession().getProperties().put("mail.smtp.auth.xoauth2.token", tokenResult.accessToken());
        } catch (final MalformedURLException e) {
            throw new MessagingException("无法初始化OAuth2连接", e);
        }
    }
    this.emailSender.send(message);
}

4. 关于Microsoft GraphAPI的说明

GraphAPI发送邮件不需要密码,你遇到的密码要求是配置错误。正确做法是:

  • 给应用添加Mail.Send应用权限并完成管理员授权
  • 使用Graph Java SDK调用POST /users/{userId}/sendMail接口,全程只用OAuth2 token,无需密码

5. 额外检查项

  • 确认authority中的租户ID正确(格式:https://login.microsoftonline.com/{你的租户ID}/)
  • 检查客户端机密是否过期
  • 确认发件邮箱属于当前Azure AD租户,且已正确关联到应用

内容的提问来源于stack exchange,提问作者Léo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 05:25:40