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

PHPMailer在Cron Job中发送首封邮件后停止运行的问题

解决Cron执行PHPMailer循环发邮件仅第一封成功的问题

我之前也踩过类似的坑——浏览器里跑起来顺风顺水,一丢Cron里就直接“罢工”,大概率是CLI环境和Web环境的差异在搞鬼,给你几个排查和解决的方向:

1. 先抓出错误信息再说

CLI模式下默认可能不会显示错误,脚本出错直接静默终止,你根本不知道哪里出了问题。可以先给脚本加上错误输出配置:

error_reporting(E_ALL);
ini_set('display_errors', 1);
ini_set('log_errors', 1);
ini_set('error_log', '/path/to/your/error.log'); // 换成你有权限写入的路径

或者直接在Cron命令里把输出重定向到日志文件,方便后续排查:

/usr/bin/php /path/to/your/script.php >> /var/log/mail_script.log 2>&1

执行完Cron任务后去看日志,就能清楚第一封邮件之后到底是哪里报错导致脚本终止了。

2. 搞定工作目录和路径问题

Cron默认的工作目录是执行用户的根目录(比如/home/your_user/),而不是你脚本所在的目录。如果脚本里用了相对路径加载PHPMailer或者其他依赖文件,CLI环境下就会找不到。

解决办法很简单:

  • 在脚本开头强制切换到脚本所在目录:
chdir(__DIR__); // PHP 7+可用,旧版本用 dirname(__FILE__)
  • 所有文件引用都改用绝对路径,比如:
require __DIR__ . '/vendor/autoload.php'; // 假设用Composer加载PHPMailer

3. 每次循环都重置PHPMailer实例

如果循环里复用同一个PHPMailer对象,可能会残留上一次的配置、缓存或者未释放的资源,导致后续发送失败。建议每次循环都重新初始化一个实例:

// 把通用配置(比如SMTP服务器信息)放在循环外
$smtpHost = 'smtp.example.com';
$smtpUser = 'your@mail.com';
$smtpPass = 'your_password';

while ($row = $result->fetch_assoc()) {
    // 每次循环新建PHPMailer实例
    $mail = new PHPMailer\PHPMailer\PHPMailer(true);
    try {
        // 配置SMTP参数
        $mail->isSMTP();
        $mail->Host = $smtpHost;
        $mail->SMTPAuth = true;
        $mail->Username = $smtpUser;
        $mail->Password = $smtpPass;
        $mail->SMTPSecure = PHPMailer\PHPMailer\PHPMailer::ENCRYPTION_STARTTLS;
        $mail->Port = 587;

        // 设置收件人、邮件内容等
        $mail->setFrom('sender@example.com', 'Sender Name');
        $mail->addAddress($row['email'], $row['name']);
        $mail->Subject = 'Your Report';
        $mail->Body = "Hello {$row['name']}, here is your report content...";

        $mail->send();
        echo "Sent to {$row['email']} successfully\n";
    } catch (Exception $e) {
        echo "Failed to send to {$row['email']}: {$mail->ErrorInfo}\n";
    }
    // 销毁实例,释放资源
    unset($mail);
}

4. 检查CLI的PHP配置

Web服务器的PHP配置(php.ini)和CLI模式下的可能完全不一样,比如是否加载了openssl扩展(PHPMailer发SMTP邮件必须依赖这个),或者memory_limit设置过低。

你可以在终端执行以下命令检查:

# 查看openssl扩展是否启用
php -i | grep openssl
# 查看CLI的PHP版本
php -v

如果openssl没启用,需要修改CLI对应的php.ini(通常在/etc/php/x.x/cli/php.ini)开启扩展;如果PHP版本和Web环境差异过大,也可能存在兼容性问题。

5. 避免超时或资源耗尽

如果客户列表很长,CLI脚本可能因为超时或内存不足终止(不过第一封就停的话概率较低,但可以提前预防):

set_time_limit(0); // 设置脚本不限时运行
ini_set('memory_limit', '256M'); // 根据实际需求调整内存限制

按照上面的步骤排查,基本能定位到问题——我之前就是因为路径没处理对,Cron下找不到PHPMailer的依赖文件,导致第一封之后脚本直接挂了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 07:51:45