Markdown-листи - шаблони з готовими компонентами, які Laravel перетворює на адаптивний HTML з вбудованими стилями й одночасно на текстову версію:
php artisan make:mail OrderShipped --markdown=mail.orders.shipped
<x-mail::message>
# Замовлення відправлено
Ваше замовлення №{{ $order->number }} вже в дорозі.
<x-mail::button :url="$trackingUrl">
Відстежити посилку
</x-mail::button>
<x-mail::table>
| Товар | Кількість |
|:------|----------:|
@foreach ($order->items as $item)
| {{ $item->name }} | {{ $item->quantity }} |
@endforeach
</x-mail::table>
Дякуємо,<br>{{ config('app.name') }}
</x-mail::message>
Компоненти й CSS можна опублікувати (vendor:publish --tag=laravel-mail) і змінити під свій бренд. Головна перевага - не потрібно вручну писати табличну верстку, яку вимагають поштові клієнти.
Листи в черзі. Надсилання через SMTP чи API провайдера займає сотні мілісекунд і може впасти. Користувач не має на це чекати:
Mail::to($user)->queue(new OrderShipped($order));
Mail::to($user)->later(now()->addMinutes(10), new OrderShipped($order));
Або завжди в черзі - інтерфейс ShouldQueue на класі, і тоді навіть send() ставить лист у чергу.
SerializesModels у черзі зберігає лише ідентифікатор моделі, а воркер перечитує модель з бази перед надсиланням.
Навіщо afterCommit:
DB::transaction(function () use ($order) {
$order->update(['status' => 'shipped']);
Mail::to($order->customer)->queue(new OrderShipped($order));
// ... ще операції, які можуть впасти
});
Проблеми без нього:
- воркер може взяти завдання до коміту транзакції - модель ще не оновлена чи взагалі не існує, і лист міститиме старі дані або завдання впаде з
ModelNotFoundException; - якщо транзакція відкотилася, лист про «відправлене замовлення» все одно піде.
Mail::to($order->customer)->queue((new OrderShipped($order))->afterCommit());
Тепер лист ставиться в чергу лише після успішного коміту, а при відкаті - не ставиться взагалі. Глобально це вмикає after_commit => true у конфігурації підключення черги.
Обробка збоїв: невдалі листи потрапляють у failed_jobs; можна задати $tries і backoff на класі листа, як у звичайного завдання.
Докладніше в документації: Пошта: листи в черзі й транзакції