Настройка и локальное тестирование:
Вся конфигурация живёт в config/mail.php и подтягивается из .env. Для разработки удобнее всего Mailpit: он прикидывается SMTP-сервером, перехватывает все письма и показывает их в браузере на localhost:8025. В Sail он идёт из коробки, в Herd Pro есть свой встроенный перехватчик почты.
Код: Выделить всё
MAIL_MAILER=smtp
MAIL_HOST=127.0.0.1
MAIL_PORT=1025
MAIL_FROM_ADDRESS="noreply@myblog.ru"
MAIL_FROM_NAME="${APP_NAME}"
Письма через Mailable:
Каждое письмо в Laravel оформляется отдельным классом. Создадим письмо автору статьи о новом комментарии, сразу с markdown-шаблоном:
Код: Выделить всё
php artisan make:mail CommentPosted --markdown=mail.comment-posted
Код: Выделить всё
class CommentPosted extends Mailable
{
use Queueable, SerializesModels;
public function __construct(public Comment $comment) {}
public function envelope(): Envelope
{
return new Envelope(subject: 'Новый комментарий к вашей статье');
}
public function content(): Content
{
return new Content(markdown: 'mail.comment-posted');
}
}
Отправка из контроллера или слушателя события выглядит так: Mail::to($comment->post->author)->send(new CommentPosted($comment)).
Уведомления:
Notification решает другую задачу: одно событие нужно доставить в несколько каналов. Письмо, запись в базе для колокольчика в шапке сайта, Telegram через сторонний пакет. Генерируем класс командой php artisan make:notification и описываем каналы:
Код: Выделить всё
class NewCommentNotification extends Notification implements ShouldQueue
{
use Queueable;
public function __construct(private Comment $comment) {}
public function via(object $notifiable): array
{
return ['mail', 'database'];
}
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->subject('Новый комментарий')
->line('К вашей статье оставили комментарий.')
->action('Читать', url('/posts/'.$this->comment->post_id));
}
public function toArray(object $notifiable): array
{
return ['comment_id' => $this->comment->id];
}
}
Заметьте, уведомление реализует ShouldQueue. Отправка по SMTP занимает одну-две секунды, и держать пользователя на этом запросе незачем. Механика та же, что в главе про очереди: задача падает в очередь, воркер разгребает. Mailable тоже умеет ShouldQueue, тогда обычный send() сам поставит письмо в очередь.
Типичные грабли:
Самые частые проблемы здесь не в коде. Если письма с ShouldQueue не уходят, первым делом проверьте, запущен ли воркер: без него задания копятся в таблице jobs и молча лежат там вечно. Дальше хостинг: на большинстве российских VPS (Timeweb, REG.RU и другие) исходящий порт 25 закрыт от спамеров, поэтому подключайтесь к SMTP через 465 или 587. Для 465 в свежих версиях Laravel ставится MAIL_SCHEME=smtps, в старых MAIL_ENCRYPTION=ssl.
Про спам: настройте на домене записи SPF и DKIM, иначе даже честные письма поедут в спам-папку. Провайдеры SMTP обычно дают готовые значения для DNS. И не забудьте поменять MAIL_FROM_ADDRESS, дефолтный hello@example.com многие серверы режут на входе.
Последняя ловушка тоньше. SerializesModels кладёт в очередь не модель, а её id, и достаёт запись заново в момент отправки. Если комментарий успели удалить, воркер упадёт с ModelNotFoundException. Для таких писем либо передавайте простые значения вместо модели, либо обрабатывайте ситуацию в методе failed().
Итог:
Mailable для писем, Notification для нескольких каналов сразу, Mailpit для локальной проверки, очереди для скорости, SPF и DKIM для доставляемости. В следующей главе соберём из всего пройденного REST API: отдадим данные не в Blade, а в JSON, и прикрутим аутентификацию по токенам.