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

PHPMailer封装函数后无法发送验证码邮件求助

问题排查:PHPMailer封装函数后无法发送Gmail验证码邮件

问题描述

使用PHPMailer发送验证码邮件,将发送逻辑封装到sendmail函数后,提交表单时邮件无法正常发送。已使用有效Gmail账号配置SMTP,但邮件仍发送失败,相关配置及完整代码如下:

核心SMTP配置

$mail->Username   = 'abc@gmail.com';                
$mail->Password   = 'secret'; 
$mail->setFrom('abc@gmail.com', 'Test Email');

完整代码

<?php  

use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception;

//Load Composer's autoloader
require 'vendor/autoload.php';

function sendmail($email,$v_code) {
  //Create an instance; passing `true` enables exceptions
  $mail = new PHPMailer(true);

  try {
    //Server settings
    $mail->SMTPDebug = SMTP::DEBUG_SERVER;                      //Enable verbose debug output
    $mail->isSMTP();                                            //Send using SMTP
    $mail->Host       = 'smtp.gmail.com';                     //Set the SMTP server to send through
    $mail->SMTPAuth   = true;                                   //Enable SMTP authentication
    $mail->Username   = 'abc@gmail.com';                     //SMTP username
    $mail->Password   = 'secret';                               //SMTP password
    $mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS;            //Enable implicit TLS encryption
    $mail->Port       = 465;                                    //TCP port to connect to; use 587 if you have set `SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS`

    //Recipients
    $mail->setFrom('abc@gmail.com', 'Test Email');
    $mail->addAddress($email);     //Add a recipient
   
    //Content
    $mail->isHTML(true);                                  //Set email format to HTML
    $mail->Subject = 'Email verification code';
    $mail->Body    =  "click the link to verify<a href=''>click here</a>";
        
    $mail->send();
    return true;
  }
  catch (Exception $e) {
    return false;
  }
}

if(isset($_POST['signup-submit'])) {
  $username = $_POST['username'];
  $email = $_POST['email'];
  $password = $_POST['password'];
  $cnfmpwd = $_POST['repeatpsw'];
    
  if (empty($username)) {  
    header("Location: ../signup.php?error=requiredusername");
    exit();
  }
  else if (!filter_var($email, FILTER_VALIDATE_EMAIL) && !preg_match("/^[a-zA-Z0-9]*$/", $username)) {
    header("Location: ../signup.php?error=invaliedusernameemail");
    exit();
  }
  else if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
    header("Location: ../signup.php?error=invaliedemail");
    exit();
  }
  else if (!preg_match("/^[a-zA-Z0-9]*$/", $username)) {
    header("Location: ../signup.php?error=invalidusername");
    exit();
  }
  else if (empty($email)){
    header("Location: ../signup.php?error=requiredemail");
    exit();
  }
  else if (empty($password)){
    header("Location: ../signup.php?error=requiredpassword");
    exit();
  }
  else if (empty($cnfmpwd)){
    header("Location: ../signup.php?error=requiredcnfmpwd");
    exit();
  }
  else if ($password !== $cnfmpwd) {
    header("Location: ../signup.php?error=pwddonotmatch");
    exit();
  }
  else {
    $check_user="SELECT * FROM users WHERE username ='$_POST[username]' OR email = '$_POST[email]'";
    $result=mysqli_query($conn,$check_user);
    
    if($result) {
      if(mysqli_num_rows($result)>0)
      {
        $result_fetch = mysqli_fetch_assoc($result);
        if($result_fetch['username']==$_POST['username']) {
          header("Location: ../signup.php?error=usernameexists");
          exit();
        }
        else {
          header("Location: ../signup.php?error=emailexists");
          exit();
        }
      }
      else {
        $password = password_hash($_POST['password'], PASSWORD_BCRYPT);
        $v_code = bin2hex(random_bytes(16));
        $query = "INSERT INTO `users`(`username`, `email`, `password`, `verification_code`, `v_user`) VALUES ('$username','$email','$password','$v_code','0')";
    
        if(mysqli_query($conn,$query) && sendmail($email,$v_code) ) { // data inserted successfully
          header("Location: ../signup_success.php?signup=success");
          exit();
        }
        else { // if data cannot be inserted
          header("Location: ../signup.php?unsuccesss=unsuccesss");
          exit();
        }
      }
    }
  }
  mysqli_close($conn);  
}
else {
  header("Location: ../signup.php");
  exit();
} 
?>

排查要点及解决方案

1. Gmail SMTP密码错误(最常见原因)

Gmail目前不支持使用普通账号密码进行SMTP验证,必须使用以下两种方式之一:

  • 应用专用密码:先开启账号的两步验证,再在Google账号设置中生成应用专用密码,替换代码中的'secret'。
  • 启用不太安全的应用访问:若未开启两步验证,可在Google账号安全设置中开启该选项(但Google已逐步淘汰此方式,优先推荐应用专用密码)。

2. 错误信息被丢弃,无法定位问题

当前sendmail函数的catch块仅返回false,丢失了PHPMailer抛出的具体错误信息。修改catch块保留错误信息:

catch (Exception $e) {
    // 测试环境可直接输出,生产环境可存入会话
    $_SESSION['mail_error'] = "邮件发送失败: {$mail->ErrorInfo}";
    return false;
}

之后在跳转后的页面读取$_SESSION['mail_error']即可查看具体错误原因。

3. 数据库连接未初始化,导致逻辑误判

代码中使用$conn执行数据库操作,但未看到$conn的初始化代码(如mysqli_connect)。若$conn未定义,mysqli_query($conn,$check_user)会直接失败,触发后续else分支,让你误以为是邮件发送失败,实际是数据库操作出错。

需提前完成数据库连接:

// 示例:添加数据库连接代码
$conn = mysqli_connect('localhost', 'db_user', 'db_password', 'db_name');
if (!$conn) {
    die("数据库连接失败: " . mysqli_connect_error());
}

4. SMTP配置的兼容性调整

部分服务器可能拦截465端口,可尝试切换为587端口+STARTTLS加密:

$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
$mail->Port       = 587;

5. 邮件内容优化(不影响发送,但需修正)

当前邮件Body中的验证链接是空的,需替换为包含$v_code的实际验证地址:

$mail->Body    =  "点击链接完成验证: <a href='https://yourdomain.com/verify.php?code={$v_code}'>点击这里</a>";

内容的提问来源于stack exchange,提问作者T.Z

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 10:57:02