Ответ
Прямая синхронная отправка почты из скрипта блокирует его выполнение и создает риск неудачи при проблемах с SMTP-сервером. В production-среде я использую паттерн очереди задач (queue).
Стандартное решение — отдельный worker-процесс:
- Основное приложение помещает задачу на отправку в очередь (например, Redis или RabbitMQ).
// Пример с Redis (используя библиотеку predis/predis)
$redis = new PredisClient();
$emailData = [
'to' => 'user@example.com',
'subject' => 'Ваш заказ подтвержден',
'template' => 'order_confirmed',
'data' => ['orderId' => 12345]
];
// Добавляем задачу в список 'emails'
$redis->lpush('emails', json_encode($emailData));
// Скрипт пользователя продолжает работу, не дожидаясь отправки
- Отдельный worker-скрипт (запущенный, например, через Supervisor) постоянно мониторит эту очередь.
// worker.php
while (true) {
$task = $redis->brpop('emails', 0); // Блокирующее ожидание задачи
$emailData = json_decode($task[1], true);
// Логика формирования и отправки письма
$mailer = new MyAppMailer();
try {
$mailer->send($emailData);
// Логируем успех
} catch (Exception $e) {
// Логируем ошибку, можно положить задачу в очередь для повторных попыток
$redis->lpush('emails_failed', $task[1]);
}
}
Почему это лучше прямого exec() или SwiftMailer?
- Надежность: Задачи не теряются при падении воркера, они остаются в очереди.
- Масштабируемость: Можно запустить несколько воркеров для обработки пиковой нагрузки.
- Контроль: Легко реализовать повторные попытки (retry), логирование и мониторинг.
- Разделение ответственности: Основное приложение не зависит от скорости или доступности почтового сервиса.