簡體   English   中英

帶有隊列 550 錯誤的 Laravel 電子郵件(每秒電子郵件過多)

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

我們的電子郵件無法使用帶有 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 談過,電子郵件從未觸及他們的服務器,當我的錯誤發生時,他們的服務完全處於活動狀態。 所以,錯誤似乎就在我的身邊。

有什么想法嗎?

似乎只有Mailtrap 會發送此錯誤,因此要么開設另一個帳戶,要么升級到付費計划。

我終於想出了如何設置整個 Laravel 應用程序以根據配置限制郵件。

AppServiceProviderboot()函數中,

$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()函數發送的郵件。

僅供調試!
如果您不希望收到超過 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()是一種非常糟糕的做法。 理論上,這段代碼應該只在測試環境或調試模式下執行。

也許您應該確保它確實是通過 Sendgrid 而不是 mailtrap 發送的。 他們的硬速率限制目前似乎是每秒 3k 個請求,而免費計划中的 mailtrap 則是每秒 3 個請求:)

我通過手動設置身份驗證路由在 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(); 讓我們手動配置身份驗證路由。
  • 將路由email/resend包裹在Route::group ,中間件throttle:1,1 (這兩個數字代表最大重試次數和這些最大重試次數的時間(以分鍾為單位))

我還在__construct函數中刪除了文件app\\Http\\Controllers\\Auth\\VerificationController.php中的一行代碼。

我刪除了這個:

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

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

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

我在foreach使用了sleep(5) foreach 遍歷存儲在數據庫中的所有電子郵件, sleep(5)在繼續下一封電子郵件之前停止循環五秒鍾。

您需要對emails隊列進行速率限制。

“官方”方法是設置Redis 隊列驅動程序 但這既困難又費時。

因此,我編寫了自定義隊列工作器mxl/laravel-queue-rate-limit ,它使用Illuminate\\Cache\\RateLimiter來限制作業執行的速率(與 Laravel 內部用於限制 HTTP 請求速率的相同)。

config/queue.php指定emails隊列的速率限制(例如每秒 2 封電子郵件):

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

並為此隊列運行工作程序:

$ php artisan queue:work --queue emails

我在使用郵件陷阱時遇到了這個問題。 我在一秒鍾內發送了 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));

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM