Laravel批量发送邮件如何获取成功与失败邮箱ID列表?
批量发送邮件并获取成功/失败邮箱列表的解决方案
问题原因分析
你遇到的Mail::failures()和返回值为空的情况,通常有两个核心原因:
- 部分邮件驱动(比如
log驱动)不会返回真实的发送失败状态; - 批量发送时,部分SMTP服务器不会逐个返回单个邮箱的错误信息,仅返回整体发送结果,导致
failures()无法捕获单邮箱失败。
同时循环单条发送效率低,下面提供两种可行的替代方案:
方案一:小批量拆分发送(同步场景)
将100个邮箱拆分为小批次发送,每次发送后即时捕获失败邮箱,同步统计成功/失败列表,既比单条循环快,又能准确获取状态:
$subject = "Test Email"; $emailList = ['dhaval@test','yasin@yopmail.com', ...]; // 你的100个邮箱列表 $batchSize = 20; // 按需调整批次大小,避免触发服务器发送限制 $successEmails = []; $failedEmails = []; foreach (array_chunk($emailList, $batchSize) as $batch) { Mail::send([], [], function ($message) use ($batch, $subject) { $message->to($batch)->subject($subject); }); // 记录当前批次的失败邮箱 $currentFailures = Mail::failures(); $failedEmails = array_merge($failedEmails, $currentFailures); // 计算当前批次的成功邮箱(总批次减去失败列表) $currentSuccess = array_diff($batch, $currentFailures); $successEmails = array_merge($successEmails, $currentSuccess); // 重置失败列表,避免下一批次重复统计 Mail::clearFailures(); } // 输出结果 dd($successEmails, $failedEmails);
方案二:队列异步发送(推荐,适合大数量)
用Laravel队列异步处理邮件发送,既解决同步发送耗时问题,又能精准捕获每个邮箱的失败状态:
步骤1:创建邮件任务
php artisan make:job SendEmailToUser
步骤2:编写任务逻辑
namespace App\Jobs; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; use Illuminate\Support\Facades\Mail; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\DB; class SendEmailToUser implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; public $email; public $subject; // 任务重试次数(按需设置) public $tries = 3; public function __construct(string $email, string $subject) { $this->email = $email; $this->subject = $subject; } public function handle() { // 发送单个邮箱的邮件 Mail::send([], [], function ($message) { $message->to($this->email)->subject($this->subject); }); } // 任务失败时触发,记录失败邮箱 public function failed(\Throwable $exception) { // 方式1:记录到日志 Log::error("邮件发送失败:{$this->email},错误信息:{$exception->getMessage()}"); // 方式2:存入数据库(需提前创建email_failures表) DB::table('email_failures')->insert([ 'email' => $this->email, 'error_msg' => $exception->getMessage(), 'created_at' => now() ]); } }
步骤3:分发任务
$subject = "Test Email"; $emailList = ['dhaval@test','yasin@yopmail.com', ...]; foreach ($emailList as $email) { SendEmailToUser::dispatch($email, $subject); }
结果统计
- 成功邮箱:总邮箱列表减去数据库/日志中的失败邮箱
- 失败邮箱:直接从
email_failures表或日志中提取
额外注意事项
- 确保邮件驱动配置为
smtp而非log/array,否则无法捕获真实失败状态; - 部分SMTP服务商有发送频率限制,小批次发送时需调整
batchSize避免被限流; - 队列方案需要配置好队列驱动(比如Redis、数据库)并启动队列监听:
php artisan queue:work
内容的提问来源于stack exchange,提问作者Yasin Patel
相关产品推荐
相关产品推荐

