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

PHP Mailer发送邮件致网站崩溃,如何转为Cron Job运行?

解决网站发送邮件崩溃问题:改用Cron Job后台处理邮件发送

看起来你的网站崩溃是因为邮件发送过程阻塞了用户请求——PHP默认是同步执行的,发送邮件时要等SMTP服务器响应,这段时间网站进程被卡住,高并发下很容易崩溃。把邮件发送移到Cron Job后台运行是非常正确的思路,我一步步帮你改:


第一步:重构代码逻辑,引入邮件任务表

Cron Job是定时后台运行的脚本,没法直接接收用户的POST请求,所以我们需要先把"发送邮件"的请求变成数据库里的待处理任务,再让Cron脚本定时去读取并执行。

1. 创建邮件任务表

先在你的数据库里建一张表,用来存待发送的邮件:

CREATE TABLE pending_emails (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(255) NOT NULL,
    email VARCHAR(255) NOT NULL,
    subject VARCHAR(255) NOT NULL,
    body TEXT NOT NULL,
    status ENUM('pending', 'sent', 'failed') DEFAULT 'pending',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

2. 修改原前端提交代码(不再直接发邮件)

原来的代码是用户提交后直接发邮件,现在改成把任务插入到上面的表(同时修复了原代码的SQL注入漏洞):

<?php
define('DB_NAME', 'daniel_login');
define('DB_USER', 'daniel_login');
define('DB_PASSWORD', '#####');
define('DB_HOST', 'localhost');

$conn = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
if (!$conn) {
    die('Could not connect: ' . mysqli_connect_error());
}

if (isset($_POST['recovery'])) {
    $recovery = $_POST['recovery'];
    
    // 用预处理语句查询用户邮箱,避免SQL注入
    $stmt = $conn->prepare("SELECT email FROM members WHERE username = ?");
    $stmt->bind_param("s", $recovery);
    $stmt->execute();
    $result = $stmt->get_result();
    
    if ($row = $result->fetch_assoc()) {
        $user_email = $row['email'];
        $subject = "密码找回通知"; // 替换成你的邮件主题
        $body = "您好,点击下方链接重置密码:\n[你的重置链接]"; // 替换成实际邮件内容
        
        // 插入待发送任务到数据库
        $stmt = $conn->prepare("INSERT INTO pending_emails (username, email, subject, body) VALUES (?, ?, ?, ?)");
        $stmt->bind_param("ssss", $recovery, $user_email, $subject, $body);
        $stmt->execute();
        
        echo "找回邮件已安排发送,请查收邮箱";
    } else {
        echo "该用户名不存在";
    }
    $stmt->close();
}
$conn->close();
?>

第二步:写Cron Job专用的邮件发送脚本

创建一个独立的脚本,比如send_pending_emails.php,建议放在非Web根目录(防止被公开访问):

<?php
define('DB_NAME', 'daniel_login');
define('DB_USER', 'daniel_login');
define('DB_PASSWORD', '#####');
define('DB_HOST', 'localhost');

$conn = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
if (!$conn) {
    die('Could not connect: ' . mysqli_connect_error());
}

// 一次处理10封待发邮件,避免脚本超时
$stmt = $conn->prepare("SELECT * FROM pending_emails WHERE status = 'pending' LIMIT 10");
$stmt->execute();
$result = $stmt->get_result();

require 'PHPMailer-master/PHPMailerAutoload.php';

while ($row = $result->fetch_assoc()) {
    $mail = new PHPMailer();
    // 配置你的SMTP服务器信息(必填)
    $mail->isSMTP();
    $mail->Host = 'smtp.your-email-provider.com'; // 比如smtp.gmail.com
    $mail->SMTPAuth = true;
    $mail->Username = 'your-account@example.com';
    $mail->Password = 'your-email-password';
    $mail->SMTPSecure = 'tls';
    $mail->Port = 587;
    
    $mail->setFrom('your-account@example.com', '你的网站名称');
    $mail->addAddress($row['email'], $row['username']);
    $mail->Subject = $row['subject'];
    $mail->Body = $row['body'];
    
    // 发送后更新任务状态
    if ($mail->send()) {
        $update_stmt = $conn->prepare("UPDATE pending_emails SET status = 'sent' WHERE id = ?");
        $update_stmt->bind_param("i", $row['id']);
        $update_stmt->execute();
        $update_stmt->close();
    } else {
        $update_stmt = $conn->prepare("UPDATE pending_emails SET status = 'failed' WHERE id = ?");
        $update_stmt->bind_param("i", $row['id']);
        $update_stmt->execute();
        $update_stmt->close();
        // 记录错误日志,方便排查
        error_log("邮件发送失败(ID: {$row['id']}):" . $mail->ErrorInfo);
    }
}

$stmt->close();
$conn->close();
?>

第三步:配置Cron Job定时运行脚本

Cron是Linux服务器的定时任务工具,配置方法如下:

  1. 登录服务器终端,输入crontab -e编辑定时任务列表。
  2. 添加一行配置(替换成你的脚本实际路径),比如每5分钟运行一次:
*/5 * * * * php /home/your-user/send_pending_emails.php >> /var/log/email_cron.log 2>&1

参数解释:

  • */5 * * * *:表示每5分钟执行一次(可按需修改:* * * * *每分钟,0 * * * *每小时)
  • php /home/your-user/send_pending_emails.php:脚本的绝对路径
  • >> /var/log/email_cron.log 2>&1:将运行日志写入文件,方便后续排查问题
  1. 保存退出后,Cron会自动生效。

关键注意事项

  • 安全优先:原代码直接拼接用户输入到SQL的写法有严重注入风险,重构后的预处理语句一定要保留!
  • SMTP配置:必须在Cron脚本里填写正确的SMTP服务器信息,否则邮件无法发送。
  • 权限检查:确保脚本有执行权限,且PHP能访问到PHPMailer的文件。
  • 日志监控:定期查看/var/log/email_cron.log,如果有失败邮件可以及时排查。

内容的提问来源于stack exchange,提问作者Daniel Faulkner

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 03:14:45