带有队列 550 错误的 Laravel 电子邮件(每秒电子邮件太多)
Posted
技术标签:
【中文标题】带有队列 550 错误的 Laravel 电子邮件(每秒电子邮件太多)【英文标题】:Laravel email with queue 550 error (too many emails per second) 【发布时间】:2016-05-20 03:43:33 【问题描述】:我们的电子邮件无法使用带有 Redis 队列的 Laravel 发送。
触发错误的代码是这样的:->onQueue('emails')
$job = (new SendNewEmail($sender, $recipients))->onQueue('emails');
$job_result = $this->dispatch($job);
结合这个在工作中:
use InteractsWithQueue;
我们的错误信息是:
Feb 09 17:15:57 laravel: message repeated 7947 times: [ production.ERROR: exception 'Swift_TransportException' with message 'Expected response code 354 but got code "550", with message "550 5.7.0 Requested action not taken: too many emails per second "' in /home/laravel/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php:383 Stack trace: #0 /home/laravel/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php(281):
我们的错误只发生在使用 Sendgrid 而不是 Mailtrap 时,它会欺骗电子邮件发送。我已经和 Sendgrid 谈过了,当我发生错误时,电子邮件从未接触过他们的服务器,而且他们的服务完全处于活动状态。所以,错误似乎就在我身上。
有什么想法吗?
【问题讨论】:
这是来自邮件服务器的响应码,所以如果你使用的是Sendgrid的服务器,错误必须来自他们 查看您尝试发送的电子邮件数量 (7947) 我认为您应该查看 SendGrid 的批量电子邮件选项。我们在以前的工作中遇到了同样的问题,我们最终使用 MailChimp 并使用他们的 API 来同步订阅者列表。我猜 SendGrid 可能会有相同的功能或类似的东西。 只有 2 封电子邮件。由于失败,它一直尝试重新发送 8000 次。 我正在尝试解决同样的问题。我想知道 Laravel 中是否可以启用某种速率限制,例如在 Node 中:dorelljames.com/web-development/… 这里有一些东西供我们探索:***.com/questions/30568069/… 【参考方案1】:似乎只有Mailtrap 发送此错误,因此请打开另一个帐户或升级到付费计划。
【讨论】:
或者只是延迟你的邮件超过 10 秒【参考方案2】:也许您应该确保它确实是通过 Sendgrid 而不是 mailtrap 发送的。他们的硬速率限制目前似乎是每秒 3k 请求,而免费计划中的 mailtrap 每秒请求 3 次 :)
【讨论】:
我可能弄错了——但 Sendgrid 不是用于发送邮件吗? Mailtrap 用于不发送邮件,而是为了测试目的而捕获它。所以这并不能解决那些尝试测试群发邮件的问题。【参考方案3】:仅用于调试! 如果您不希望收到超过 5 封电子邮件并且无法更改 mailtrap,请尝试:
foreach ($emails as $email)
...
Mail::send(... $email);
if(env('MAIL_HOST', false) == 'smtp.mailtrap.io')
sleep(1); //use usleep(500000) for half a second or less
使用sleep() 是一种非常糟糕的做法。理论上,这段代码应该只在测试环境或调试模式下执行。
【讨论】:
【参考方案4】:我终于想出了如何设置整个 Laravel 应用来根据配置限制邮件。
在AppServiceProvider
的boot()
函数中,
$throttleRate = config('mail.throttleToMessagesPerMin');
if ($throttleRate)
$throttlerPlugin = new \Swift_Plugins_ThrottlerPlugin($throttleRate, \Swift_Plugins_ThrottlerPlugin::MESSAGES_PER_MINUTE);
Mail::getSwiftMailer()->registerPlugin($throttlerPlugin);
在config/mail.php
中,添加这一行:
'throttleToMessagesPerMin' => env('MAIL_THROTTLE_TO_MESSAGES_PER_MIN', null), //https://mailtrap.io has a rate limit of 2 emails/sec per inbox, but consider being even more conservative.
在您的 .env
文件中,添加如下行:
MAIL_THROTTLE_TO_MESSAGES_PER_MIN=50
唯一的问题是,如果QUEUE_DRIVER=sync
,它似乎不会影响通过later()
函数发送的邮件。
【讨论】:
如果您需要更多粒度,也可以使用\Swift_Plugins_ThrottlerPlugin::MESSAGES_PER_SECOND
【参考方案5】:
我通过手动设置身份验证路由在 Laravel v5.8 上实现了这一点。路线位于文件routes\web.php
。以下是需要添加到该文件的路由:
Auth::routes();
Route::get('email/verify', 'Auth\VerificationController@show')->name('verification.notice');
Route::get('email/verify/id', 'Auth\VerificationController@verify')->name('verification.verify');
Route::group(['middleware' => 'throttle:1,1'], function()
Route::get('email/resend', 'Auth\VerificationController@resend')->name('verification.resend');
);
说明:
不要将任何参数传递给路由Auth::routes();
,以便手动配置身份验证路由。
使用中间件 throttle:1,1
将路由 email/resend
包裹在 Route::group
中(这两个数字代表最大重试次数和这些最大重试次数的分钟数)
我还在__construct
函数中删除了文件app\Http\Controllers\Auth\VerificationController.php
中的一行代码。
我删除了这个:
$this->middleware('throttle:6,1')->only('verify', 'resend');
【讨论】:
这个答案解决了测试 laravel 5.8 验证码的问题。【参考方案6】:你需要限制emails
队列的速率。
“官方”方式是设置Redis queue driver。但这既困难又耗时。
所以我编写了自定义队列工作者 mxl/laravel-queue-rate-limit,它使用 Illuminate\Cache\RateLimiter
来限制作业执行(与 Laravel 内部使用的 rate limit HTTP requests 相同)。
在config/queue.php
中指定emails
队列的速率限制(例如每秒2 封电子邮件):
'rateLimit' => [
'emails' => [
'allows' => 2,
'every' => 1
]
]
并为此队列运行工作者:
$ php artisan queue:work --queue emails
【讨论】:
【参考方案7】:我使用sleep(5)
等待五秒钟,然后再次使用邮件陷阱。
foreach ($this->suscriptores as $suscriptor)
\Mail::to($suscriptor->email)
->send(new BoletinMail($suscriptor, $sermones, $entradas));
sleep(5);
我在foreach
中使用了sleep(5)
。 foreach 遍历存储在数据库中的所有电子邮件,sleep(5)
将循环暂停五秒钟,然后继续处理下一封电子邮件。
【讨论】:
你把那个睡觉放在哪里了?【参考方案8】:我在使用邮件陷阱时遇到了这个问题。我在一秒钟内发送了 10 封邮件,它被视为垃圾邮件。我不得不在每项工作之间进行延迟。看看解决方案(它的 Laravel - 我有 system_jobs
表并使用 queue=database
)
创建一个静态函数来检查最后一个作业时间,然后添加到它self::DELAY_IN_SECONDS
- 您希望作业之间的秒数:
public static function addSecondsToQueue()
$job = SystemJobs::orderBy('available_at', 'desc')->first();
if($job)
$now = Carbon::now()->timestamp;
$jobTimestamp = $job->available_at + self::DELAY_IN_SECONDS;
$result = $jobTimestamp - $now;
return $result;
else
return 0;
然后用它来延迟发送消息(考虑到队列中的最后一个作业)
Mail::to($mail)->later(SystemJobs::addSecondsToQueue(), new SendMailable($params));
【讨论】:
以上是关于带有队列 550 错误的 Laravel 电子邮件(每秒电子邮件太多)的主要内容,如果未能解决你的问题,请参考以下文章