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

PHP使用PHPMailer发送OTP验证邮件失败的原因排查

问题描述

我正在尝试给用户发送包含验证验证码(OTP)的邮件,确认SMTP配置完全正确(上周还成功用于发送带PDF附件的邮件),但当前发送OTP邮件失败,调试时未发现任何错误,请问还有哪些可能的原因?

附当前使用的PHP代码
<?php

use PHPMailer\PHPMailer\PHPMailer;

require_once(__DIR__ . '/sendEmails/vendor/phpmailer/phpmailer/src/Exception.php');
require_once(__DIR__ . '/sendEmails/vendor/phpmailer/phpmailer/src/PHPMailer.php');
require_once(__DIR__ . '/sendEmails/vendor/phpmailer/phpmailer/src/SMTP.php');


class VerificationCode
{
    public $smtpHost;
    public $sender;
    public $smtpPort;
    public $password;
    public $receiver;
    public $code;


    // some function to receive,send and port.

    public function _constructor($receiver) {
        $this->sender = "xxx@example.org";
        $this->password = "****";
        $this->smtpHost = "mail.example.com";
        $this->smtpPort = 587;

    }
    // function to send email().
    public function sendMail(){

        $mail= new PHPMailer();
        $mail->isSMTP();
        $mail->SMTPAuth = true;
        $mail->SMTPOptions = array(
            'ssl'=> array(
                'verify_peer'=>false,
                'verify_peer_name' => false,
                'allow_self_signed'=> true
            )
            );

            $mail->Host = $this->smtpHost;
            $mail->Port =$this->smtpPort;
            $mail->IsHTML(true);
            $mail->Username =$this->sender;
            $mail->Password= $this->password;
            $mail->Body=$this->getHTMLMessage();
            $mail->Subject = "Your verification code is {$this->code}";
            $mail->SetFrom($this->sender, "Verification Code");
            $mail->AddAddress($this->receiver);
            if($mail->send()) {
                echo "Mail Sent Successfully";
                exit;
            }
            echo "Failed to Send Mail";
    }

    // function to get html message from the email.
    public function getHTMLMessage() {
        $this->code=$this->getVerificationCode();
        $htmlMessage=<<<MSG
        <!DOCTYPE html>
        <html>
            <body>
                <h1>Your verification code is {$this->code}</h1>
                <p>Use this code to verify your account.</p>
            </body>
        </html>
        MSG;
        return $htmlMessage;
    }

    // get verificationCode.
    public function getVerificationCode() {
        return (int) substr(number_format(time() * rand(), 0,  '', ''), 0, 6);
    }

}

// instantiate VerificationCode and send email
$vc=new VerificationCode('gcira2023@outlook.com'); 
$vc->sendMail();

?>
可能的原因及代码问题分析
  • 构造函数语法错误:代码中构造函数写成了_constructor,PHP的正确构造函数名是__construct(两个下划线),这会导致类的smtpHost、sender、password等核心配置属性完全未初始化,直接引发SMTP连接失败,这是当前代码最致命的问题。
  • 反垃圾邮件系统拦截:OTP邮件内容简洁且包含验证码,极易被收件方或邮件服务商的反垃圾系统判定为垃圾邮件,直接进入垃圾箱或被拦截,即使SMTP发送成功,收件人也无法收到。
  • SMTP服务器临时限制:即使上周配置正常,邮件服务商可能临时调整了发送规则(如频率限制、单日发送量阈值),或发件IP被临时列入监控名单,导致发送失败。
  • PHPMailer错误信息未捕获:当前代码仅通过$mail->send()的布尔值判断结果,未启用异常捕获机制,无法获取SMTP连接、认证或发送过程中的具体错误详情。
  • 验证码生成逻辑潜在问题:getVerificationCode方法通过time() * rand()生成验证码,极端情况下可能生成不足6位的数字,导致邮件内容格式异常,触发邮件系统过滤规则。
  • 收件箱安全策略限制:收件邮箱(如outlook.com)可能开启了严格的安全策略,陌生发件人的邮件被直接拦截,或收件邮箱存储空间已满。
修复建议
  • 修正构造函数:将_constructor改为__construct,同时初始化receiver属性:
    public function __construct($receiver) {
        $this->sender = "xxx@example.org";
        $this->password = "****";
        $this->smtpHost = "mail.example.com";
        $this->smtpPort = 587;
        $this->receiver = $receiver;
    }
    
  • 启用PHPMailer异常捕获:修改sendMail方法,添加异常捕获以获取详细错误:
    public function sendMail(){
        try {
            $mail= new PHPMailer(true); // 传入true启用异常模式
            $mail->isSMTP();
            $mail->SMTPAuth = true;
            $mail->SMTPOptions = array(
                'ssl'=> array(
                    'verify_peer'=>false,
                    'verify_peer_name' => false,
                    'allow_self_signed'=> true
                )
            );
    
            $mail->Host = $this->smtpHost;
            $mail->Port =$this->smtpPort;
            $mail->IsHTML(true);
            $mail->Username =$this->sender;
            $mail->Password= $this->password;
            $mail->Body=$this->getHTMLMessage();
            $mail->Subject = "Your verification code is {$this->code}";
            $mail->SetFrom($this->sender, "Verification Code");
            $mail->AddAddress($this->receiver);
            $mail->send();
            echo "Mail Sent Successfully";
            exit;
        } catch (Exception $e) {
            echo "Failed to Send Mail: " . $mail->ErrorInfo;
        }
    }
    
  • 优化验证码生成逻辑:确保生成稳定的6位数字验证码:
    public function getVerificationCode() {
        return str_pad(mt_rand(100000, 999999), 6, '0', STR_PAD_LEFT);
    }
    
  • 排查邮件拦截情况:检查发件邮箱的退信记录、收件邮箱的垃圾箱;可更换收件邮箱测试,或联系邮件服务商确认是否存在发送限制。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 09:27:58