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

使用PHPMailer+OAuth2连接Gmail发送邮件失败求助

使用OAuth2连接Gmail发送邮件失败,已获取access_token但SMTP连接直接断开

SMTP交互日志

2024-05-24 14:25:45 SERVER -> CLIENT: 220 smtp.gmail.com ESMTP xxxxxx.114 - gsmtp
2024-05-24 14:25:45 CLIENT -> SERVER: EHLO services.*.it
2024-05-24 14:25:45 SERVER -> CLIENT: 250-smtp.gmail.com at your service, [46.16.95.34]250-SIZE 35882577250-8BITMIME250-STARTTLS250-ENHANCEDSTATUSCODES250-PIPELINING250-CHUNKING250 SMTPUTF8
2024-05-24 14:25:45 CLIENT -> SERVER: STARTTLS
2024-05-24 14:25:45 SERVER -> CLIENT: 220 2.0.0 Ready to start TLS
2024-05-24 14:25:45 CLIENT -> SERVER: EHLO services.*.it
2024-05-24 14:25:45 SERVER -> CLIENT: 250-smtp.gmail.com at your service, [xx.xx.xx.xx]250-SIZE 35882577250-8BITMIME250-AUTH LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH250-ENHANCEDSTATUSCODES250-PIPELINING250-CHUNKING250 SMTPUTF8
2024-05-24 14:25:45 CLIENT -> SERVER: QUIT
2024-05-24 14:25:45 SERVER -> CLIENT: 221 2.0.0 closing connection xxxxxx.114 - gsmtp

代码实现

<?php

use Google\Client as Google_Client;
use Google_Service_Gmail;
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
use PHPMailer\PHPMailer\OAuth;
use League\OAuth2\Client\Provider\Google;

$clientId = 'xxxx'; 
$clientSecret = 'xxx'; 

$serviceAccountPath = __DIR__ . DIRECTORY_SEPARATOR . 'config-email-noreply.json';

try {
    $client = new Google_Client();
    $client->setAuthConfig($serviceAccountPath);
    $client->addScope(Google_Service_Gmail::MAIL_GOOGLE_COM);
    $client->refreshTokenWithAssertion();
    $tokenArray = $client->getAccessToken();
    $accessToken = $tokenArray['access_token'];
    $mail = new PHPMailer(true);
    $mail->SMTPDebug = 2;
    $mail->setOAuth(new OAuth([
        'provider' => new Google([
            'clientId' => $clientId,
            'clientSecret' => $clientSecret,
        ]),
        'clientId' => $client->getClientId(),
        'clientSecret' => $client->getClientSecret(),
        'refreshToken' => null,
        'accessToken' => $accessToken,
        'userName' => 'noreply@xxx.it',
    ]));

    $mail->isSMTP();
    $mail->Host = 'smtp.gmail.com';
    $mail->SMTPAuth = true;
    $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
    $mail->Port = 587;

    $mail->AuthType = 'XOAUTH2';
    $mail->oauthUserEmail = 'noreply@xxx.it';
    $mail->oauthClientId = $client->getClientId();
    $mail->oauthClientSecret = $client->getClientSecret();
    $mail->oauthRefreshToken = null; 

    $mail->setFrom('noreply@xx.it', 'No-reply');
    $mail->addAddress('xxx@xxx.it', 'Recipient Name');
    $mail->Subject = 'Test email using OAuth2';
    $mail->Body = 'This is a test email sent using OAuth2 and PHPMailer.';


    $mail->send();
    echo 'Message has been sent';
} catch (Exception $e) {
    echo 'Error: ' . $e->getMessage();
}

Composer依赖配置

{
    "require": {
        "phpmailer/phpmailer": "^6.9",
        "league/oauth2-google": "^3.0",
        "google/apiclient": "^2.14"
    }
}

问题说明

PHP版本为8,已成功获取到access_token,但PHPMailer在SMTP握手完成后直接发送QUIT命令断开连接,无法完成邮件发送。

排查与解决要点

  • 服务账号权限配置
    确认服务账号已在Google Workspace中启用域范围委派,并授予https://mail.google.com/或https://www.googleapis.com/auth/gmail.send权限;检查noreply@xxx.it邮箱已被正确授权给服务账号,允许其代表该邮箱发送邮件。

  • PHPMailer OAuth配置冲突
    代码中同时使用setOAuth()方法和单独设置oauth*属性会导致配置冲突,保留其中一种方式即可,推荐使用setOAuth();另外注意setOAuth()中的userName与setFrom()中的邮箱地址需完全一致(当前代码中两者域名不一致)。

  • Token有效性验证
    打印$tokenArray确认token包含expires_in字段且未过期;验证token的权限范围是否包含mail.google.com。

  • SMTP AuthType确认
    确保$mail->AuthType = 'XOAUTH2';设置正确,且在setOAuth()之后配置(或通过setOAuth()自动设置)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 14:58:09