如何用 OAuthTokenProvider 接口让 PHPMailer 接入非 League 的 OAuth2 库
如何用 OAuthTokenProvider 接口让 PHPMailer 接入非 League 的 OAuth2 库【免费下载链接】PHPMailerThe classic email sending library for PHP项目地址: https://gitcode.com/GitHub_Trending/ph/PHPMailer如果你的项目里 PHPMailer 要走 SMTP 的XOAUTH2认证但项目用的不是 League 的oauth2-client包——比如你用厂商 SDK 或另一个 OAuth2 客户端库来换 token——那么官方给出的做法是自己写一个实现OAuthTokenProvider接口的包装类再通过PHPMailer::setOAuth()传给 PHPMailer。内置的 OAuth 类只认 League 的 Provider而接口这一层把 token 来源解耦了changelog.md 也记录了这一点“Introduce interface for OAuth providers, making it easier to use OAuth libraries other than the League one”。完成后的效果PHPMailer 发送AUTH XOAUTH2时调用你实现类的getOauth64()取 token 串其余 SMTP 配置与 League 路径完全一致。官方示例 examples/azure_xoauth2.phps 中Option 1 演示 League 路径Option 2 就是本文的非 League 路径本文以它为主线。接入点OAuthTokenProvider 只要求一个方法OAuthTokenProvider 的定义很薄interface OAuthTokenProvider { /** * Generate a base64-encoded OAuth token ensuring that the access token has not expired. * The string to be base 64 encoded should be in the form: * useruser_email_address\001authBearer access_token\001\001 * * return string */ public function getOauth64(); }接口注释明确了两点约束返回的必须是base64 编码后的字符串被编码前的字符串格式固定为useruser_email_address\001authBearer access_token\001\001\001是控制字符不是字符串\001的字面拼写方式PHP 源码里写作\001即可注释同时要求实现方保证 access token 未过期“ensuring that the access token has not expired”也就是说 token 刷新逻辑在你的包装类里负责。PHPMailer 侧的消费点在 SMTP::authenticate()XOAUTH2分支调用$OAuth-getOauth64()然后发送AUTH XOAUTH2 返回值并等待服务器返回 235 应答如果此时 OAuth 实例为null即你没有调用过setOAuth认证直接失败。第一步写一个实现接口的包装类官方示例对包装类的构造参数只给了注释形式的说明/* Email, ClientId, ClientSecret, etc. */即按你自己 OAuth2 库需要传什么就传什么。骨架如下use PHPMailer\PHPMailer\OAuthTokenProvider; class MyOAuthTokenProvider implements OAuthTokenProvider { protected $email; protected $clientId; protected $clientSecret; public function __construct($email, $clientId, $clientSecret) { $this-email $email; $this-clientId $clientId; $this-clientSecret $clientSecret; } public function getOauth64() { // 1. 用你自己的 OAuth2 库换取一个未过期的 access token // 示例中没有给出具体调用需替换为你的库的取 token 逻辑 $accessToken TODO: 替换为你的 OAuth2 库获取 access token 的调用; // 2. 按接口要求的固定格式拼装再 base64 编码 return base64_encode( user . $this-email . \001authBearer . $accessToken . \001\001 ); } }其中第 2 步的字符串格式来自接口文档注释不要自行改动分隔符或authBearer前缀。仓库测试里有一个最小实现可作参考——test/OAuth/OAuthTest.php 中的DummyOauthProvider它的getOauth64()直接返回固定值oauth用于验证setOAuth()/getOAuth()能接受任意接口实现。第二步配置 PHPMailer 并调用 setOAuth以下代码块取自 examples/azure_xoauth2.phps 的 Option 2 及其公共部分。其中Host、Port、SMTPSecure的取值是示例中针对 Microsoft Office 365 服务器的配置换成其他邮件服务商时需按对应服务商调整示例注释给出了两种端口选择465 对应 SMTP with implicit TLSSMTPS587 对应 SMTPSTARTTLS。//Import PHPMailer classes into the global namespace use PHPMailer\PHPMailer\PHPMailer; use PHPMailer\PHPMailer\SMTP; //SMTP needs accurate times, and the PHP time zone MUST be set date_default_timezone_set(Etc/UTC); //Load dependencies from composer //If this causes an error, run composer install require vendor/autoload.php; //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.office365.com; //Set the SMTP port number: // - 465 for SMTP with implicit TLS, a.k.a. RFC8314 SMTPS or // - 587 for SMTPSTARTTLS $mail-Port 587; //Set the encryption mechanism to use $mail-SMTPSecure PHPMailer::ENCRYPTION_STARTTLS; //Whether to use SMTP authentication $mail-SMTPAuth true; //Set AuthType to use XOAUTH2 $mail-AuthType XOAUTH2; //Option 2: Another OAuth library as OAuth2 token provider //Set up the other oauth library as per its documentation //Then create the wrapper class that implementations OAuthTokenProvider $oauthTokenProvider new MyOAuthTokenProvider($email, $clientId, $clientSecret); //Pass the implementation of OAuthTokenProvider to PHPMailer $mail-setOAuth($oauthTokenProvider); //Set who the message is to be sent from //For Outlook, this generally needs to be the same as the user you logged in as $mail-setFrom($email, First Last); $mail-addAddress(someonesomeserver.com, John Doe); $mail-Subject PHPMailer Outlook XOAUTH2 SMTP test; $mail-AltBody This is a plain-text message body; //send the message, check for errors if (!$mail-send()) { echo Mailer Error: . $mail-ErrorInfo; } else { echo Message sent!; }几个需要留意的点setOAuth()的参数类型是OAuthTokenProvider见 src/PHPMailer.php所以 League 的内置OAuth类和你的自定义类走的是同一个入口两者互斥只传一个即可$mail-AuthType XOAUTH2是示例中显式设置的AuthType的可选值为 CRAM-MD5、LOGIN、PLAIN、XOAUTH2见 PHPMailer::$AuthType 的注释依赖加载方面示例通过require vendor/autoload.php引入 composer 依赖注释说明如果报错先执行composer install。如何验证接入是否生效官方给出的判断手段有两层SMTP 调试输出。示例把$mail-SMTPDebug设为SMTP::DEBUG_SERVER注释说明该级别会同时打印客户端与服务端消息。接入成功时你应该能在调试输出里看到发出的AUTH XOAUTH2 ...命令SMTP::authenticate() 要求服务器对此返回235应答否则返回 false。send() 的返回值与 ErrorInfo。示例的发送检查是$mail-send()返回 false 时打印$mail-ErrorInfo否则打印Message sent!。这是文档中给出的成功/失败判定的完整形式ErrorInfo里的文本随失败环节不同而变化不要把它比对成固定值。如果只想在不上真实邮箱服务的情况下验证“接口实现能被 PHPMailer 接受”仓库测试 test/OAuth/OAuthTest.php 演示了做法用setOAuth()传入任意OAuthTokenProvider实现后getOAuth()应返回同一实例。排查与限制认证方式不被服务器支持。authenticate()会先比对服务器 EHLO 通告的能力若请求的方式不在其中src/SMTP.php 设置的错误是The requested authentication method XOAUTH2 is not supported by the server措辞来自源码以实际输出为准。忘记 setOAuth。XOAUTH2分支里 OAuth 实例为null时直接返回 false源码注释写明 “The OAuth instance must be set up prior to requesting auth”即setOAuth()必须先于实际发送执行。未指定 AuthType 时的选择顺序。如果AuthType留空SMTP::authenticate()按 CRAM-MD5、LOGIN、PLAIN、XOAUTH2 的顺序挑服务器支持的方式见 src/SMTP.php可能并不会落到 XOAUTH2用非 League 库做 XOAUTH2 时按示例显式设置AuthType是更稳妥的写法。发件人身份。示例对 Outlook 的说明是setFrom()的邮箱“generally needs to be the same as the user you logged in as”。token 生命周期。接口注释把“确保 access token 未过期”的责任放在实现getOauth64()的一侧包装类内部要处理刷新这一点 League 内置的OAuth类是用hasExpired()检查完成的src/OAuth.php可作为你实现刷新逻辑时的行为参照。【免费下载链接】PHPMailerThe classic email sending library for PHP项目地址: https://gitcode.com/GitHub_Trending/ph/PHPMailer创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考