PHPMailer批量邮件发送故障:循环中邮件失效但数据库更新正常
批量处理邮件发送失效排查与修复
问题背景
原本实现了单条数据点击按钮查询后发送邮件的功能,现在改造成多选批量处理:循环更新选中数据状态(数据库更新正常),但将邮件代码移入循环后,邮件完全发不出去。尝试调整邮件代码位置、移除主查询都没用,怀疑SELECT查询有问题但无法验证,需要排查原因。
引入文件
include(dirname(__DIR__).'/db.php'); include(dirname(__DIR__).'/phpmailer/src/Exception.php'); include(dirname(__DIR__).'/phpmailer/src/PHPMailer.php'); include(dirname(__DIR__).'/phpmailer/src/SMTP.php'); use PHPMailer\PHPMailer\PHPMailer; use PHPMailer\PHPMailer\Exception;
原有嵌套代码
else if ($category=="pend") { if ($val==1){ foreach ($all_id as $value) { $query = mysqli_query($db,"SELECT * FROM tbl_person where app_id='$value' and app_status='2';"); while($row= mysqli_fetch_array($query)) { $email = $row["app_email"]; $name = $row["app_fname"]." " . $row["app_mname"].". ".$row["app_lname"]; } $update = "Update tbl_person set app_status=3 WHERE app_id='$value'"; $mail = new PHPMailer(true); $mail->isSMTP(); $mail->SMTPAuth = true; $mail->Host = 'smtp.office365.com'; $mail->Port = 587; $mail->SMTPSecure = 'tls'; $mail->SMTPAuth = true; $mail->Username = 'useremail'; //sample $mail->Password = 'emailpassword'; //sample $mail->SetFrom('useremail', 'username'); //sample $mail->addAddress($email, $name); $mail->IsHTML(true); $mail->Subject = 'Application Status'; $mail->Body = 'Message Body Here'; $mail->AltBody = 'Message Alt Body Here'; if (mysqli_query($db,$update)) { header('location:../application.php'); } } } else if ($val==2){ foreach ($all_id as $value) { $update = "Update tbl_person set app_status=4 WHERE app_id='$value'"; if (mysqli_query($db,$update)) { header('location:../application.php'); } } } else{ echo "Something went wrong"; } }
核心问题排查
- 循环被提前跳转中断:每次更新成功后直接调用
header跳转,循环只执行第一次就结束了,后面的邮件发送和数据更新都没机会执行。 - 邮件根本没触发发送:代码里只配置了PHPMailer的参数,漏掉了最关键的
$mail->send()调用,相当于只装了子弹没扣扳机。 - SELECT查询的冗余与风险:
app_id是主键的话,while循环完全多余;而且没处理查询失败的情况——如果查不到数据,$email和$name要么是空值,要么保留上一次循环的旧值,邮件自然发不出去。 - 无错误捕获机制:PHPMailer开启了异常模式,但没加
try/catch,就算邮件发送出错(比如SMTP连接失败、邮箱无效),也看不到任何报错信息,无法排查问题。 - SQL注入隐患:直接把
$value拼进SQL语句,不仅不安全,还可能因为特殊字符导致SQL语法错误。
修复后的代码
else if ($category=="pend") { if ($val==1){ $isAllSuccess = true; foreach ($all_id as $value) { // 用预编译语句查询用户信息,防注入+避免语法错误 $stmt = mysqli_prepare($db, "SELECT app_email, app_fname, app_mname, app_lname FROM tbl_person WHERE app_id=? AND app_status='2'"); mysqli_stmt_bind_param($stmt, "s", $value); mysqli_stmt_execute($stmt); $result = mysqli_stmt_get_result($stmt); // 确认查到有效数据再执行后续操作 if ($row = mysqli_fetch_assoc($result)) { $email = $row["app_email"]; $name = $row["app_fname"] . " " . $row["app_mname"] . ". " . $row["app_lname"]; // 更新数据状态 $updateStmt = mysqli_prepare($db, "UPDATE tbl_person SET app_status=3 WHERE app_id=?"); mysqli_stmt_bind_param($updateStmt, "s", $value); if (!mysqli_stmt_execute($updateStmt)) { $isAllSuccess = false; error_log("更新状态失败,ID: $value,错误: " . mysqli_error($db)); continue; } // 发送邮件并捕获异常 try { $mail = new PHPMailer(true); $mail->isSMTP(); $mail->SMTPAuth = true; $mail->Host = 'smtp.office365.com'; $mail->Port = 587; $mail->SMTPSecure = 'tls'; $mail->Username = 'useremail'; // 替换为实际发件邮箱 $mail->Password = 'emailpassword'; // 替换为实际密码 $mail->setFrom('useremail', 'username'); // 替换为实际发件人信息 $mail->addAddress($email, $name); $mail->isHTML(true); $mail->Subject = 'Application Status'; $mail->Body = 'Message Body Here'; $mail->AltBody = 'Message Alt Body Here'; // 关键:执行邮件发送 $mail->send(); } catch (Exception $e) { $isAllSuccess = false; error_log("邮件发送失败,ID: $value,错误信息: " . $mail->ErrorInfo); } } else { $isAllSuccess = false; error_log("未找到符合条件的数据,ID: $value"); } } // 所有操作完成后统一跳转 if ($isAllSuccess) { header('location:../application.php'); exit; } else { echo "部分操作失败,请查看服务器日志排查"; } } else if ($val==2){ $isAllSuccess = true; foreach ($all_id as $value) { $updateStmt = mysqli_prepare($db, "UPDATE tbl_person SET app_status=4 WHERE app_id=?"); mysqli_stmt_bind_param($updateStmt, "s", $value); if (!mysqli_stmt_execute($updateStmt)) { $isAllSuccess = false; error_log("更新状态失败,ID: $value,错误: " . mysqli_error($db)); break; } } if ($isAllSuccess) { header('location:../application.php'); exit; } else { echo "部分更新失败,请查看服务器日志"; } } else{ echo "参数错误"; } }
修复点说明
- 移除循环内跳转:等所有批量操作执行完毕后再统一跳转,确保每条数据都被处理。
- 添加
$mail->send():补上邮件发送的核心执行步骤。 - 异常捕获:用
try/catch捕获PHPMailer的错误,通过日志记录失败原因,方便后续排查。 - SQL预编译:避免SQL注入风险,同时解决特殊字符导致的SQL语法错误。
- 查询结果校验:确认SELECT查询到有效数据后再执行后续操作,避免空值导致的报错。
- 状态标记:用
isAllSuccess变量记录整体操作结果,给用户明确的反馈信息。
内容的提问来源于stack exchange,提问作者typicalguy
相关产品推荐
相关产品推荐

