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

使用PHPMailer调用Microsoft OAuth令牌时出现invalid_client错误

问题:无法通过OAuth2使用Office365 SMTP发送邮件

我的Microsoft配置

  • 认证设置:[链接]
  • API权限:[链接]
  • 令牌配置:为空
  • 公开API:为空

获取令牌的代码(运行正常)

new \Stevenmaguire\OAuth2\Client\Provider\Microsoft([
    'clientId'                  => "my_id...",
    'clientSecret'              => "my_secret...",
    'redirectUri'               => "https://example.com/get/get_oauth_token.php",
    'accessType'                => 'offline',
    // Optional (what is this doing??)
    'urlAuthorize'              => 'https://login.windows.net/common/oauth2/authorize',
    'urlAccessToken'            => 'https://login.windows.net/common/oauth2/token',
    'urlResourceOwnerDetails'   => 'https://outlook.office.com/api/v1.0/me'
    ]);
$authUrl = $provider->getAuthorizationUrl([
    'scope' => ['wl.basic', 'wl.signin', 'wl.emails'] // 不清楚需要哪些权限,是否要和应用权限对应?
]);
$_SESSION['oauth2state'] = $provider->getState();
header('Location: ' . $authUrl);

使用令牌发送邮件的代码

$mail = new PHPMailer();
$mail->isSMTP();
$mail->Timeout = 10;
$mail->Host = "smtp.office365.com"; // smtp.office365.com、outlook.office.com、smtp-mail.outlook.com到底用哪个?试了都没用
$mail->Port = 587;
$mail->SMTPSecure = "tls";
$mail->SMTPAuth = true;
$mail->AuthType = 'XOAUTH2';

// 省略邮件内容相关代码

$provider = new \Stevenmaguire\OAuth2\Client\Provider\Microsoft([
    'clientId'                  => "my_id...",
    'clientSecret'              => "my_secret...",
    'redirectUri'               => "https://example.com/get/get_oauth_token.php" // 这里需要配置吗?
]);

// 将OAuth提供者实例传递给PHPMailer
$mail->setOAuth(
    new OAuth([
        'provider' => $provider,
        'clientId' => "my_id...",
        'clientSecret' => "my_secret...",
        'refreshToken' => "my_refreshToken...",
        // 'oauthToken' => $token, // 这里是不是完全忽略了实际的access token?需要更新refresh token吗?
        'userName' => 'me@mycompany.onmicrosoft.com' // 应该是授权的用户邮箱?
    ])
);

$mail->send();
$mail->SmtpClose();

出现的错误

2022-09-22 17:49:08 SERVER -> CLIENT: 220 FR0P281CA0070.outlook.office365.com Microsoft ESMTP MAIL Service ready at Thu, 22 Sep 2022 17:49:07 +0000

2022-09-22 17:49:08 CLIENT -> SERVER: EHLO example.com

2022-09-22 17:49:08 SERVER -> CLIENT: 250-FR0P281CA0070.outlook.office365.com Hello [85.13.129.169]250-SIZE 157286400250-PIPELINING250-DSN250-ENHANCEDSTATUSCODES250-STARTTLS250-8BITMIME250-BINARYMIME250-CHUNKING250 SMTPUTF8

2022-09-22 17:49:08 CLIENT -> SERVER: STARTTLS

2022-09-22 17:49:08 SERVER -> CLIENT: 220 2.0.0 SMTP server ready

2022-09-22 17:49:08 CLIENT -> SERVER: EHLO example.com

2022-09-22 17:49:08 SERVER -> CLIENT: 250-FR0P281CA0070.outlook.office365.com Hello [85.13.129.169]250-SIZE 157286400250-PIPELINING250-DSN250-ENHANCEDSTATUSCODES250-AUTH LOGIN XOAUTH2250-8BITMIME250-BINARYMIME250-CHUNKING250 SMTPUTF8

Bad Request
/www/htdocs/w014af32/me/vendor/stevenmaguire/oauth2-microsoft/src/Provider/Microsoft.php(79)
    #0 /www/htdocs/w014af32/me/vendor/league/oauth2-client/src/Provider/AbstractProvider.php(628): Stevenmaguire\OAuth2\Client\Provider\Microsoft->checkResponse(Object(GuzzleHttp\Psr7\Response), Array)
    #1 /www/htdocs/w014af32/me/vendor/league/oauth2-client/src/Provider/AbstractProvider.php(537): League\OAuth2\Client\Provider\AbstractProvider->getParsedResponse(Object(GuzzleHttp\Psr7\Request))
    #2 /www/htdocs/w014af32/me/vendor/phpmailer/phpmailer/src/OAuth.php(115): League\OAuth2\Client\Provider\AbstractProvider->getAccessToken(Object(League\OAuth2\Client\Grant\RefreshToken), Array)
    #3 /www/htdocs/w014af32/me/vendor/phpmailer/phpmailer/src/OAuth.php(128): PHPMailer\PHPMailer\OAuth->getToken()
    #4 /www/htdocs/w014af32/me/vendor/phpmailer/phpmailer/src/SMTP.php(598): PHPMailer\PHPMailer\OAuth->getOauth64()
    #5 /www/htdocs/w014af32/me/vendor/phpmailer/phpmailer/src/PHPMailer.php(2190): PHPMailer\PHPMailer\SMTP->authenticate('', '', 'XOAUTH2', Object(PHPMailer\PHPMailer\OAuth))
    #6 /www/htdocs/w014af32/me/vendor/phpmailer/phpmailer/src/PHPMailer.php(2003): PHPMailer\PHPMailer\PHPMailer->smtpConnect(Array)
    #7 /www/htdocs/w014af32/me/vendor/phpmailer/phpmailer/src/PHPMailer.php(1662): PHPMailer\PHPMailer\PHPMailer->smtpSend('Date: Thu, 22 S...', 'test content\r\n')
    #8 /www/htdocs/w014af32/me/vendor/phpmailer/phpmailer/src/PHPMailer.php(1500): PHPMailer\PHPMailer\PHPMailer->postSend()
    #9 /www/htdocs/w014af32/me/includes/helpers/mail.php(182): PHPMailer\PHPMailer\PHPMailer->send()
    #10 /www/htdocs/w014af32/me/includes/helpers/mail.php(113): mailSendSingle(Object(PHPMailer\PHPMailer\PHPMailer), Array, true)
    #11 /www/htdocs/w014af32/me/get/test4.php(25): mailSend(Array)
    #12 {main}
    # Args: 
        checkResponse: [{},{"error":"invalid_client","error_description":"The client does not exist or is not enabled for consumers. If you are the application developer, configure a new application through the App Registrations in the Azure Portal at https:\/\/go.microsoft.com\/fwlink\/?linkid=2083908.","correlation_id":"4dc377bd-0d5d-4444-bdd4-82b862f86177"}]
        getParsedResponse: [{}]
        getAccessToken: [{},{"refresh_token":"my refreshToken..."}]
        authenticate: ["","","XOAUTH2",{}]
        smtpConnect: [{"ssl":{"verify_peer":false,"verify_peer_name":false,"allow_self_signed":true}}]
        smtpSend: ["Date: Thu, 22 Sep 2022 19:49:08 +0200\r\nTo: John Doe <me@example.com>\r\nFrom: John Doe <me@mycompany.onmicrosoft.com>\r\nReply-To: John Doe <me@mycompany.onmicrosoft.com>\r\nSubject: test mail\r\nMessage-ID: <AAtH5DrcPQ9Fn4PysOdjIt0OnDbByC4eaRYVnJh33M@example.com>\r\nX-Mailer: PHPMailer 6.6.4 (https:\/\/github.com\/PHPMailer\/PHPMailer)\r\nMIME-Version: 1.0\r\nContent-Type: text\/html; charset=utf-8\r\n\r\n","test content\r\n"]
        mailSendSingle: [{"Priority":null,"CharSet":"utf-8","ContentType":"text\/html","Encoding":"7bit","ErrorInfo":"","From":"me@mycompany.onmicrosoft.com","FromName":"John Doe","Sender":"me@mycompany.onmicrosoft.com","Subject":"test mail","Body":"test content","AltBody":"","Ical":"","WordWrap":0,"Mailer":"smtp","Sendmail":"\/usr\/sbin\/sendmail","UseSendmailOptions":true,"ConfirmReadingTo":"","Hostname":"","MessageID":"","MessageDate":"","Host":"smtp.office365.com","Port":"587","Helo":"","SMTPSecure":"tls","SMTPAutoTLS":true,"SMTPAuth":true,"SMTPOptions":{"ssl":{"verify_peer":false,"verify_peer_name":false,"allow_self_signed":true}},"Username":"","Password":"","AuthType":"XOAUTH2","Timeout":10,"dsn":"","SMTPDebug":2,"Debugoutput":"html","SMTPKeepAlive":false,"SingleTo":false,"do_verp":false,"AllowEmpty":false,"DKIM_selector":"","DKIM_identity":"","DKIM_passphrase":"","DKIM_domain":"","DKIM_copyHeaderFields":true,"DKIM_extraHeaders":[],"DKIM_private":"","DKIM_private_string":"","action_function":"","XMailer":""},{"from_mail":"me@mycompany.onmicrosoft.com","from_name":"John Doe","smtp_profile":3,"from_user":1,"to_mail":"me@example.com","to_name":"John Doe","to_type":"staff","to_id":3,"template":0,"debug":true,"testing":true,"subject":"test mail","type":"test","date":"2022-09-22 19:49:08","content":"test content","reply_to":"me@mycompany.onmicrosoft.com"},true]
        mailSend: [{"from_mail":"me@mycompany.onmicrosoft.com","from_name":"John Doe","smtp_profile":3,"from_user":1,"to_mail":"me@example.com","to_name":"John Doe","to_type":"staff","to_id":3,"template":0,"debug":true,"testing":true,"subject":"test mail","type":"test","date":"2022-09-22 19:49:08","content":"test content","reply_to":"me@mycompany.onmicrosoft.com"}]
2022-09-22 17:49:08 CLIENT -> SERVER: QUIT

2022-09-22 17:49:08 SERVER -> CLIENT: 221 2.0.0 Service closing transmission channel

疑问

令牌获取流程正常,推测问题出在Azure配置中。获取令牌的用户是全局管理员角色成员,应用所有者是另一个用户。请问如何解决?


解决方案

从错误信息里的invalid_client和描述“客户端不存在或未对消费者启用”,结合你的场景,按以下步骤排查:

  1. 确认应用程序类型与端点匹配
    你当前使用的是旧版Azure AD端点(login.windows.net),但如果应用注册为单租户类型,却使用common端点(允许所有租户用户登录)会导致验证失败:

    • 单租户应用:将授权和令牌端点中的common替换为你的租户ID,例如https://login.windows.net/你的租户ID/oauth2/authorize
    • 多租户应用:确保注册时选择了“任何组织目录中的账户”或“任何组织目录中的账户和个人Microsoft账户”
  2. 核对客户端ID与密钥
    确认发送邮件代码中的clientId和clientSecret完全匹配Azure门户中应用注册的“客户端ID”和“客户端密码”(注意密码是创建时生成的字符串,不是密码ID)。

  3. 更新API权限
    你当前使用的wl.basic等是旧版Live Connect权限,不适用于Office365 SMTP。需要添加Exchange Online的委托权限:

    • 进入应用注册的“API权限”页面,添加Microsoft Graph的Mail.Send权限
    • 由全局管理员点击“授予管理员同意”按钮完成权限授权
  4. 修正授权范围
    获取令牌时的scope应替换为https://outlook.office.com/Mail.Send或https://graph.microsoft.com/Mail.Send,删除原来的wl.basic等无效权限。

  5. 确认应用启用状态
    在Azure门户的应用注册页面,进入“管理”→“属性”,确保对应类型的应用开关已启用:

    • 桌面/移动应用:开启“启用公众客户端流”
    • Web应用:确保重定向URI配置完全正确(和代码中的redirectUri一致)
  6. 简化发送邮件代码的配置
    发送邮件时的redirectUri可以省略,PHPMailer通过refreshToken获取accessToken时不需要该参数。

另外,PHPMailer的SMTP主机用smtp.office365.com、端口587、TLS设置都是正确的,无需调整。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 14:45:34