我正在使用 PHPMailer 通过 XOAUTH2 与 smtp.gmail.com 进行身份验证,以便发送电子邮件。但是,我收到身份验证错误且响应不充分:
2023-11-17 06:32:29 SERVER -> CLIENT: 250-smtp.gmail.com at your service, [2402:b280:a1f:ba65:ce96:e5ff:feee:f13e]250-SIZE 35882577250-8BITMIME250-AUTH LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH250-ENHANCEDSTATUSCODES250-PIPELINING250-CHUNKING250 SMTPUTF8
2023-11-17 06:32:29 CLIENT -> SERVER: AUTH XOAUTH2 dXNlcj1tdXJyYXlAZm9jdXMtY29tcHV0aW5nLmNvbS5hdQFhdXRoPUJlYXJlciB5YTI5LmEwQWZCX2J5QXAxU2twbzdJSXBGTVJLWVNPYlZqWXZMaVBCZkVXLUUweEtwOUVmUTNHTWhnV3d5UDUwM09VdGY2NVZkeW0xcHNsd05lR0JLZElwNUI4eFFISjJZdC00U1o5amQxWGtIUjBVZ0tMN29wZWt5NlJzZFFfcHRVSmU4RGU2X0dYbS1xN2lmcVFzV1VIRTI2ZHl5OUhKNWxudE1NQ2kybkhpd2FDZlEzeFY2Q1hLcmpMU0VXbnRKUEEwMTczAQE=
2023-11-17 06:32:30 SERVER -> CLIENT: 334 eyJzdGF0dXMiOiI0MDAiLCJzY2hlbWVzIjoiQmVhcmVyIiwic2NvcGUiOiJodHRwczov9vZ2xlLmNvbS8ifQ==
2023-11-17 06:32:30 SMTP ERROR: AUTH command failed: 334 eyJzdGF0dXMiOiI0MDAiLCJzY2hlbWVzIjoiQmVhcmVyIiwic2NvovL21haWwuZ29vZ2xlLmNvbS8ifQ==
SMTP Error: Could not authenticate.
2023-11-17 06:32:30 CLIENT -> SERVER: QUIT
2023-11-17 06:32:30 SERVER -> CLIENT: 535-5.7.8 Username and Password not accepted. Learn more at535 5.7.8 https://support.google.com/mail/?p=BadCredentials k6-20020a17090a404600b00277371fd346sm2482723pjg.30 - gsmtp
2023-11-17 06:32:30 SMTP ERROR: QUIT command failed: 535-5.7.8 Username and Password not accepted. Learn more at535 5.7.8 https://support.google.com/mail/?p=BadCredentials k6-20020a17090a404600b00277371fd346sm2482723pjg.30 - gsmtp
SMTP Error: Could not authenticate.
使用 XOAUTH2 时,我发送用户名和访问令牌,而不是密码。那么为什么这些消息显示有效的用户名和密码凭据。用户名和访问令牌是正确的,因此这些响应确实没有帮助。
我们能否从 Gmail 获取一些更好的消息或一些有用的信息来了解为什么此验证失败?
我正在使用的代码部分:
$mailer = new PHPMailer(true);
$mailer->SMTPDebug = SMTP::DEBUG_SERVER;
$mailer->isSMTP();
$mailer->Host = ini_get("SMTP");
$mailer->Port = ini_get("smtp_port");
$mailer->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
$mailer->SMTPAuth = true;
$mailer->Username = null;
$mailer->Password = null;
$mailer->AuthType = $smtp["authtype"]; // "XOAUTH2"
$oauth = new MyOAuthTokenProvider();
$oauth->setEmail($smtp["username"]);
$oauth->setAccessToken($smtp["accessToken"]);
$mailer->setOAuth($oauth);
$mailer->SMTPKeepAlive = true;
$mailer->From = $headers["From"];
$mailer->addReplyTo($headers["From"]);
$mailer->addAddress($recipient);
$mailer->isHTML(true);
$mailer->Subject = $headers["Subject"];
$mailer->Body = $body;
$mailer->send();
class MyOAuthTokenProvider implements OAuthTokenProvider {
protected $email;
protected $accessToken;
public function setEmail($value) {
$this->email = $value;
}
public function setAccessToken($value) {
$this->accessToken = $value;
}
/**
* @see \PHPMailer\PHPMailer\OAuth::getOauth64()
*/
public function getOauth64(): string
{
return base64_encode(
'user=' .
$this->email .
"\001auth=Bearer " .
$this->accessToken .
"\001\001"
);
}
}
这是我使用 PHP 进行 SMTP XOauth2 的示例。
它要求您拥有在启用了 Gmail 的 Google 云控制台上创建的已安装应用程序的客户端 ID 和客户端密钥。
您还需要一个刷新令牌。此代码不会创建初始刷新令牌。 我建议使用 oauth2 Playground 或类似 php 客户端库的东西来创建它。
//Import PHPMailer classes into the global namespace
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\OAuth;
//Alias the League Google OAuth2 provider class
// composer require league/oauth2-google
use League\OAuth2\Client\Provider\Google;
try{
$client = getClient();
print_r($client->getClientId());
print_r($client->getClientSecret());
print_r($client->getRefreshToken());
//Use league/oauth2-client as OAuth2 token provider
// Fill in authentication details here
// Either the gmail account owner, or the user that gave consent
$email = EMAIL_FROM;
$clientId = $client->getClientId();
$clientSecret = $client->getClientSecret();
$refreshToken = $client->getRefreshToken();
$send_to = EMAIL_TO;
//Create a new PHPMailer instance
$mail = new PHPMailer();
//Tell PHPMailer to use SMTP
$mail->isSMTP();
//Enable SMTP debugging
//SMTP::DEBUG_OFF = off (for production use)
//SMTP::DEBUG_CLIENT = client messages
//SMTP::DEBUG_SERVER = client and server messages
$mail->SMTPDebug = SMTP::DEBUG_SERVER;
//Set the hostname of the mail server
$mail->Host = 'smtp.gmail.com';
//Set the SMTP port number:
// - 465 for SMTP with implicit TLS, a.k.a. RFC8314 SMTPS or
// - 587 for SMTP+STARTTLS
$mail->Port = 465;
//Set the encryption mechanism to use:
// - SMTPS (implicit TLS on port 465) or
// - STARTTLS (explicit TLS on port 587)
$mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS;
//Whether to use SMTP authentication
$mail->SMTPAuth = true;
//Set AuthType to use XOAUTH2
$mail->AuthType = 'XOAUTH2';
//Obtained by configuring and running get_oauth_token.php
//after setting up an app in Google Developer Console.
//Create a new OAuth2 provider instance
$provider = new Google(
[
'clientId' => $clientId,
'clientSecret' => $clientSecret,
]
);
//Pass the OAuth provider instance to PHPMailer
$mail->setOAuth(
new OAuth(
[
'provider' => $provider,
'clientId' => $clientId,
'clientSecret' => $clientSecret,
'refreshToken' => $refreshToken,
'userName' => $email,
]
)
);
//Set who the message is to be sent from
//For gmail, this generally needs to be the same as the user you logged in as
$mail->setFrom($email, 'First Last');
//Set who the message is to be sent to
$mail->addAddress('[REDACTED]', 'John Doe');
//Set the subject line
$mail->Subject = 'PHPMailer GMail XOAUTH2 SMTP test';
//Read an HTML message body from an external file, convert referenced images to embedded,
//convert HTML into a basic plain-text alternative body
$mail->CharSet = PHPMailer::CHARSET_UTF8;
$mail->msgHTML(file_get_contents('test.html'), __DIR__);
//Replace the plain text body with one created manually
$mail->AltBody = 'This is a plain-text message body';
//Attach an image file
$mail->addAttachment('images/phpmailer_mini.png');
//send the message, check for errors
if (!$mail->send()) {
echo 'Mailer Error: ' . $mail->ErrorInfo;
} else {
echo 'Message sent!';
}
}
catch(Exception $e) {
// TODO(developer) - handle error appropriately
echo 'Message: ' .$e->getMessage();
}