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

PHP Mailer大附件邮件发送耗时过长,寻求异步处理方案

解决方案:异步触发邮件发送,避免用户体验受影响

你的思路完全可行——先完成订单入库,再异步触发邮件发送,能彻底解决同步发送大附件导致的用户等待、中断后邮件丢失问题。以下是具体实现方案:

一、改造purchase.php:订单入库后触发异步任务

在订单成功插入数据库后,通过以下方式之一触发mailSend.php,无需等待邮件发送完成即可返回用户响应:

方式1:使用Shell命令后台执行(推荐)

利用exec或shell_exec让PHP脚本在后台运行,不阻塞当前请求:

// purchase.php 订单插入成功后
$orderId = $pdo->lastInsertId(); // 获取刚创建的订单ID

// 转义参数避免命令注入,&表示后台运行,输出重定向到/dev/null避免占用资源
$safeOrderId = escapeshellarg($orderId);
exec("php /absolute/path/to/mailSend.php $safeOrderId > /dev/null 2>&1 &");

// 立即给用户返回成功响应
echo json_encode(['status' => 'success', 'message' => '订单已提交,我们会尽快发送下载邮件']);
exit;

方式2:使用Curl发起异步HTTP请求

如果服务器禁用了Shell命令,可通过Curl发送一个超短超时的请求,无需等待响应:

// purchase.php 订单插入成功后
$orderId = $pdo->lastInsertId();

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://your-domain.com/mailSend.php?order_id=' . $orderId);
curl_setopt($ch, CURLOPT_TIMEOUT, 1); // 1秒超时,不等待邮件处理结果
curl_setopt($ch, CURLOPT_NOBODY, true); // 仅发送请求,不接收响应体
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_exec($ch);
curl_close($ch);

// 立即返回用户响应
echo json_encode(['status' => 'success', 'message' => '订单已提交,我们会尽快发送下载邮件']);
exit;

二、编写mailSend.php:处理邮件发送逻辑

该脚本负责从数据库拉取订单信息,初始化PHPMailer并发送带大附件的邮件,同时记录日志便于排查问题:

// mailSend.php
require 'PHPMailer/PHPMailer.php';
require 'PHPMailer/SMTP.php';
require 'PHPMailer/Exception.php';

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

// 权限验证:仅允许服务器内部请求,防止恶意调用
$allowedIps = ['127.0.0.1', $_SERVER['SERVER_ADDR']];
if (!in_array($_SERVER['REMOTE_ADDR'], $allowedIps)) {
    exit('Unauthorized');
}

// 获取订单ID并校验
$orderId = isset($_GET['order_id']) ? intval($_GET['order_id']) : 0;
if (!$orderId) {
    exit('Invalid order ID');
}

// 从数据库查询订单、用户、产品信息
$pdo = new PDO('mysql:host=localhost;dbname=your-db-name', 'db-user', 'db-pass');
$stmt = $pdo->prepare("
    SELECT u.email, p.name, p.attachment_path 
    FROM orders o 
    JOIN users u ON o.user_id = u.id 
    JOIN products p ON o.product_id = p.id 
    WHERE o.id = ?
");
$stmt->execute([$orderId]);
$orderData = $stmt->fetch(PDO::FETCH_ASSOC);

if (!$orderData) {
    file_put_contents('mail-logs.txt', date('Y-m-d H:i:s') . " - Order $orderId: 未找到订单数据\n", FILE_APPEND);
    exit('Order not found');
}

// 初始化PHPMailer并发送邮件
$mail = new PHPMailer(true);
try {
    // SMTP配置(根据你的邮件服务商调整)
    $mail->isSMTP();
    $mail->Host = 'smtp.your-mail-server.com';
    $mail->SMTPAuth = true;
    $mail->Username = 'your-smtp-email@example.com';
    $mail->Password = 'your-smtp-password';
    $mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS;
    $mail->Port = 465;

    // 邮件内容配置
    $mail->setFrom('noreply@your-domain.com', 'MusicMixes Store');
    $mail->addAddress($orderData['email']);
    $mail->isHTML(true);
    $mail->Subject = "你的MusicMixes购买完成!";
    $mail->Body    = "Hi {$orderData['email']}<br><br>感谢购买{$orderData['name']},你的下载附件已在邮件中。<br><br>祝好<br>MusicMixes团队";
    $mail->AltBody = "Hi {$orderData['email']}\n\n感谢购买{$orderData['name']},你的下载附件已在邮件中。\n\n祝好\nMusicMixes团队";

    // 处理50MB大附件:临时调高PHP内存限制
    ini_set('memory_limit', '128M');
    $mail->addAttachment($orderData['attachment_path'], 'Music.mp3');

    $mail->send();
    file_put_contents('mail-logs.txt', date('Y-m-d H:i:s') . " - Order $orderId: 邮件发送成功\n", FILE_APPEND);
} catch (Exception $e) {
    file_put_contents('mail-logs.txt', date('Y-m-d H:i:s') . " - Order $orderId: 邮件发送失败,错误信息:{$mail->ErrorInfo}\n", FILE_APPEND);
}

三、关键注意事项

  • 大附件适配:确保PHP配置的memory_limit(至少128M)、邮件服务器的附件大小限制(部分服务商默认25M,需提前调整)满足50MB文件需求。
  • 日志记录:务必保留邮件发送日志,方便后续排查用户未收到邮件的问题。
  • 任务可靠性:如果是高并发场景,可考虑引入消息队列(如Redis、RabbitMQ),将邮件任务加入队列后由独立进程消费,比Shell/Curl方式更稳定。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 12:40:34