Пошта - зовнішня залежність: провайдер може лежати, обмежувати частоту, заблокувати акаунт за скарги. Для листів, від яких залежить бізнес (підтвердження, скидання пароля, рахунки), потрібен план на ці випадки.
1. Failover - резервні транспорти:
// config/mail.php
'mailers' => [
'failover' => [
'transport' => 'failover',
'mailers' => ['postmark', 'mailgun', 'sendmail'],
'retry_after' => 60,
],
],
MAIL_MAILER=failover
Якщо postmark повертає помилку, лист іде через mailgun. Транспорт, що впав, позначається недоступним на retry_after секунд - наступні листи одразу йдуть через резервний. Механізм побудований на FailoverTransport із Symfony Mailer.
2. Round robin - розподіл навантаження:
'roundrobin' => [
'transport' => 'roundrobin',
'mailers' => ['ses', 'postmark'],
],
Листи розподіляються між провайдерами по черзі, а недоступний пропускається.
Що варто врахувати з кількома провайдерами: кожен потребує налаштованих SPF, DKIM і домену відправника, інакше резервні листи потраплять у спам. Вебхуки про відмови й скарги (bounces, complaints) теж треба приймати від усіх.
3. Різні мейлери для різних листів:
Mail::mailer('postmark')->to($user)->send(new PasswordReset($token)); // транзакційні
Mail::mailer('ses')->to($subscribers)->queue(new Newsletter($issue)); // масові
Масова розсилка не повинна псувати репутацію домену чи вичерпувати ліміт, потрібний для транзакційних листів. Часто для розсилок використовують окремий піддомен.
4. Ліміти частоти. Провайдери обмежують кількість листів за секунду чи добу. Laravel не обмежує сам - це робиться на рівні черги:
- окрема черга
mailз фіксованою кількістю воркерів; - middleware завдань
RateLimitedчиRedis::throttle()для листів у черзі; $triesіbackoff, щоб тимчасові помилки (429, 5xx) повторювалися з затримкою.
5. Спостереження й налагодження:
- події
MessageSendingіMessageSent- для журналу надісланого чи блокування листів за умовою; - перегляд у браузері під час розробки: маршрут, що повертає mailable, рендерить його як сторінку;
- на staging - драйвер
logчи Mailpit/Mailtrap, а такожMail::alwaysTo()у середовищі, щоб тестові листи не потрапили справжнім клієнтам.
6. Тести: Mail::fake() і assertQueued перевіряють, що лист поставлено в чергу з правильними даними, а assertSeeInHtml - зміст листа.