带有队列 550 错误的 Laravel 电子邮件(每秒电子邮件过多)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35304197/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 13:12:37  来源:igfitidea点击:

Laravel email with queue 550 error (too many emails per second)

phplaravelsmtpswiftmailerlaravel-forge

提问by tim peterson

Our emails are failing to send using Laravel with a Redis Queue.

我们的电子邮件无法使用带有 Redis 队列的 Laravel 发送。

The code that triggers the error is this: ->onQueue('emails')

触发错误的代码是这样的: ->onQueue('emails')

$job = (new SendNewEmail($sender, $recipients))->onQueue('emails');
$job_result = $this->dispatch($job);

In combination with this in the job:

结合工作中的这一点:

use InteractsWithQueue;

Our error message is:

我们的错误信息是:

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): 

Our error only happens using Sendgrid and not Mailtrap, which spoofs emailing sending. I've talked with Sendgrid and the emails never touched their servers and their service was fully active when my error occurred. So, the error appears to be on my end.

我们的错误只发生在使用 Sendgrid 而不是 Mailtrap 时,后者会欺骗电子邮件发送。我和 Sendgrid 谈过,电子邮件从未触及他们的服务器,当我的错误发生时,他们的服务完全处于活动状态。所以,错误似乎就在我的身边。

Any thoughts?

有什么想法吗?

回答by Dorian

Seems like only Mailtrapsends this error, so either open another account or upgrade to a paid plan.

似乎只有Mailtrap 会发送此错误,因此要么开设另一个帐户,要么升级到付费计划。

回答by Ryan

I finally figured out how to set up the entire Laravel app to throttle mail based on a config.

我终于想出了如何设置整个 Laravel 应用程序以根据配置限制邮件。

In the boot()function of AppServiceProvider,

在 的boot()函数中AppServiceProvider

$throttleRate = config('mail.throttleToMessagesPerMin');
if ($throttleRate) {
    $throttlerPlugin = new \Swift_Plugins_ThrottlerPlugin($throttleRate, \Swift_Plugins_ThrottlerPlugin::MESSAGES_PER_MINUTE);
    Mail::getSwiftMailer()->registerPlugin($throttlerPlugin);
}

In config/mail.php, add this line:

在 中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.

In your .envfiles, add a line like:

在您的.env文件中,添加如下一行:

MAIL_THROTTLE_TO_MESSAGES_PER_MIN=50

The only problem is that it doesn't seem to affect mail sent via the later()function if QUEUE_DRIVER=sync.

唯一的问题是它似乎不会影响通过later()if 函数发送的邮件QUEUE_DRIVER=sync

回答by d.raev

For debugging only!
If you don't expect more then 5 emails and don't have the option to change mailtrap, try:

仅供调试!
如果您不希望收到超过 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
    }
}

Using sleep()is a really bad practice. In theory this code should only execute in test environment or in debug mode.

使用sleep()是一种非常糟糕的做法。理论上,这段代码应该只在测试环境或调试模式下执行。

回答by Bachet

Maybe you should make sure it was really sent via Sendgrid and not mailtrap. Their hard rate limit seems currently to be 3k requests per second against 3 requests per second for mailtrap on free plan :)

也许您应该确保它确实是通过 Sendgrid 而不是 mailtrap 发送的。他们的硬速率限制目前似乎是每秒 3k 个请求,而免费计划中的 mailtrap 则是每秒 3 个请求:)

回答by Jesus Flores

I achieved this on Laravel v5.8 by setting the Authentication routes manually. The routes are located on the file routes\web.php. Below are the routes that needs to be added to that file:

我通过手动设置身份验证路由在 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');
});

Explanation:

解释:

  • Do not pass any parameter to the route Auth::routes();to let configure the authentication routes manually.
  • Wrap the route email/resendinside a Route::groupwith the middleware throttle:1,1(the two numbers represents the max retry attempts and the time in minutes for those max retries)
  • 不要向路由传递任何参数以Auth::routes();手动配置身份验证路由。
  • 使用中间件将路由包裹email/resend在 a 中(这两个数字代表最大重试次数和这些最大重试次数的时间(以分钟为单位))Route::groupthrottle:1,1

I also removed a line of code in the file app\Http\Controllers\Auth\VerificationController.phpin the __constructfunction.

我还删除了函数中文件app\Http\Controllers\Auth\VerificationController.php中的一行代码__construct

I removed this:

我删除了这个:

$this->middleware('throttle:6,1')->only('verify', 'resend');

回答by Gjaa

I used sleep(5)to wait five seconds before using mailtrap again.

我曾经sleep(5)在再次使用 mailtrap 之前等待五秒钟。

foreach ($this->suscriptores as $suscriptor)  {
    \Mail::to($suscriptor->email)
           ->send(new BoletinMail($suscriptor, $sermones, $entradas));
    sleep(5);
}

I used the sleep(5)inside a foreach. The foreach traverses all emails stored in the database and the sleep(5)halts the loop for five seconds before continue with the next email.

我用了sleep(5)里面的一个foreach. foreach 遍历存储在数据库中的所有电子邮件,并sleep(5)在继续下一封电子邮件之前停止循环五秒钟。

回答by Adam Kozlowski

I had this problem when working with mail trap. I was sending 10 mails in one second and it was treated as spam. I had to make delay between each job. Take look at solution (its Laravel - I have system_jobstable and use queue=database)

我在使用邮件陷阱时遇到了这个问题。我在一秒钟内发送了 10 封邮件,它被视为垃圾邮件。我不得不在每项工作之间进行延迟。看看解决方案(它的 Laravel - 我有system_jobs桌子并使用queue=database

Make a static function to check last job time, then add to it self::DELAY_IN_SECONDS- how many seconds you want to have between jobs:

制作一个静态函数来检查上次作业时间,然后添加到它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;
        }

    }

Then use it to make sending messages with delay (taking in to consideration last job in queue)

然后使用它来延迟发送消息(考虑队列中的最后一个作业)

Mail::to($mail)->later(SystemJobs::addSecondsToQueue(), new SendMailable($params));

回答by mixel

You need to rate limit emailsqueue.

你需要限速emails队列。

The "official" way is to setup Redis queue driver. But it's hard and time consuming.

“官方”方法是设置Redis 队列驱动程序。但这既困难又耗时。

So I wrote custom queue worker mxl/laravel-queue-rate-limitthat uses Illuminate\Cache\RateLimiterto rate limit job execution (the same one that used internally by Laravel to rate limit HTTP requests).

所以我编写了自定义队列工作器mxl/laravel-queue-rate-limit用于Illuminate\Cache\RateLimiter限制作业执行的速率(与 Laravel 内部用于限制 HTTP 请求速率的相同)。

In config/queue.phpspecify rate limit for emailsqueue (for example 2 emails per second):

config/queue.php指定速率限制emails队列(例如每秒2名的电子邮件):

'rateLimit' => [
    'emails' => [
        'allows' => 2,
        'every' => 1
    ]
]

And run worker for this queue:

并为此队列运行工作程序:

$ php artisan queue:work --queue emails