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

Outlook邮件服务器发件OAuth2认证失败问题求助(含代码)

解决Outlook SMTP OAuth2认证失败问题

问题概述

尝试通过Outlook SMTP服务器发送邮件,微软调整认证机制后,已在Azure注册应用并配置权限,但使用OAuth2认证时仍抛出以下错误:

javax.mail.AuthenticationfailedException: 535 5.7.3 Authentication unsuccesful [SI2PR6CA0e12.apcprd6.prod.outlook.com 224-11-1T96:16:51.8952 809172787151CE]

代码问题分析

你提供的代码存在核心问题:获取到OAuth2 Access Token后,并未在邮件发送流程中使用该令牌完成认证。具体来说:

  • sendEmail方法中创建Session时传入了null作为Authenticator,没有实现OAuth2的认证逻辑
  • 缺少SMTP OAuth2相关的配置属性,服务器无法识别你使用的是OAuth2认证方式

Azure配置检查要点

  • 认证流程适配性:
    • 若使用个人Outlook邮箱(@outlook.com/@hotmail.com),客户端凭证流(client_credentials grant type)不被支持,需改用授权码流(Authorization Code Flow)
    • 若使用Office 365商业账户,需确保应用注册为组织账户类型,并已添加Mail.Send应用权限(而非委托权限),且完成管理员同意
  • 权限配置验证:
    登录Azure门户,进入应用注册→API权限,确认已添加Microsoft Graph下的Mail.Send应用权限,且状态为“已授予”
  • 租户ID正确性:
    商业账户需使用对应租户ID,个人邮箱若尝试使用客户端凭证流会失败,需切换认证流程

修正后的代码

以下是调整后的完整代码,包含OAuth2认证逻辑:

package com.tianrun.common.email;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Properties;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

public class OAuth2Helper {
    public static void main(String[] args) throws Exception {
        // 注意:个人邮箱请改用授权码流获取token,以下代码仅适用于Office 365商业账户
        String accessToken = getAccessToken();
        sendEmail(accessToken, "****@outlook.com", "******", "Subject", "Body of the email");
    }

    private static String getAccessToken() throws Exception {
        String clientId = "****";
        String clientSecret = "****";
        String tenantId = "*****";
        String scope = "https://graph.microsoft.com/.default"; // 改用Microsoft Graph的scope,更推荐

        String authUrl = "https://login.microsoftonline.com/" + tenantId + "/oauth2/v2.0/token";
        URL url = new URL(authUrl);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        conn.setDoOutput(true);

        String postParams = "client_id=" + clientId +
                "&scope=" + scope +
                "&client_secret=" + clientSecret +
                "&grant_type=client_credentials";

        conn.getOutputStream().write(postParams.getBytes());

        BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
        String inputLine;
        StringBuffer content = new StringBuffer();
        while ((inputLine = in.readLine()) != null) {
            content.append(inputLine);
        }
        in.close();
        conn.disconnect();

        // 建议使用JSON库解析(如Jackson),避免字符串分割的脆弱性
        String accessToken = content.toString().split("\"access_token\":\"")[1].split("\"")[0];
        System.out.println(accessToken);
        return accessToken;
    }

    private static void sendEmail(String accessToken, String sender, String recipient, String subject, String body)
            throws MessagingException {
        Properties props = new Properties();
        props.setProperty("mail.debug", "true");
        props.setProperty("mail.smtp.auth", "true");
        props.setProperty("mail.host", "smtp.office365.com");
        props.setProperty("mail.transport.protocol", "smtp");
        props.setProperty("mail.smtp.port", "587");
        props.put("mail.smtp.ssl.protocols", "TLSv1.2");
        props.put("mail.smtp.starttls.enable", "true");
        // 关键:启用XOAUTH2认证机制
        props.setProperty("mail.smtp.auth.mechanisms", "XOAUTH2");

        // 自定义OAuth2认证器
        Session session = Session.getInstance(props, new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                // 返回空用户名,密码为OAuth2 Access Token
                return new PasswordAuthentication("", accessToken);
            }
        });

        Message message = new MimeMessage(session);
        message.setFrom(new InternetAddress(sender));
        message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipient));
        message.setSubject(subject);
        message.setText(body);

        Transport.send(message);
    }
}

额外注意事项

  • 推荐使用JSON库(如Jackson、Gson)解析Access Token响应,避免字符串分割导致的解析错误
  • 个人Outlook邮箱需切换至授权码流:引导用户登录获取授权码,再换取Access Token,具体逻辑需调整getAccessToken方法
  • 确保使用的JavaMail版本为最新(如jakarta.mail:jakarta.mail-api:2.1.0及对应实现),旧版本可能不支持XOAUTH2

内容的提问来源于stack exchange,提问作者Erik John

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 10:34:53