Очередь писем - фоновая отправка, порции, повторы, чистка
Разбираемся с очередью писем: почему отправка не мгновенная, как подобрать размер порции под ограничения провайдера и что делать с зависшими записями.
Что нужно знать заранее
Вызов отправки письма кладёт запись в очередь, а не отдаёт письмо получателю сразу. Разбирает очередь фоновая задача, и между вызовом и почтовым ящиком проходит от секунд до нескольких минут.
Очередь спасает страницу от ожидания почтового сервера. Отправка сотни писем прямо в запросе покупателя растянула бы оформление заказа на десятки секунд и всё равно упёрлась бы в ограничения провайдера.
У любого почтового сервиса есть предел писем в минуту и в сутки. Превышение предела заканчивается отказами и временной блокировкой отправителя, поэтому размер порции подбирают под конкретный тариф.
Шаги
- Посмотреть текущее состояние очереди: сколько записей ждёт и как давно.
- Убедиться, что фоновая задача разбора очереди выполняется по расписанию.
- Подобрать размер порции отправки под ограничения почтового сервиса проекта.
- Разобраться с зависшими записями и понять, почему они не ушли получателю.
- Настроить чистку старых записей очереди, чтобы таблица не росла бесконечно.
Решение
Смотрим состояние очереди писем:
SELECT SUCCESS_EXEC, COUNT(*) AS cnt, MIN(DATE_INSERT) AS oldestFROM b_event GROUP BY SUCCESS_EXEC;-- признак успешной отправки делит очередь на отправленное и ожидающееРастущее число неотправленных записей означает, что очередь не разбирается. Чаще всего это выключенные агенты либо ошибка почтового сервера на каждой попытке отправки письма.
Проверяем, работает ли разбор очереди:
$rs = \CAgent::GetList(['ID' => 'DESC'], ['MODULE_ID' => 'main', 'ACTIVE' => 'Y']);while ($row = $rs->Fetch()) { printf("%-40s следующий запуск: %s\n", $row['NAME'], $row['NEXT_EXEC']);}// время следующего запуска в прошлом означает, что задания стоятОтправляем порциями со своей стороны:
foreach (array_chunk($recipients, 50) as $i => $chunk) { foreach ($chunk as $email) { \CEvent::Send('VENDOR_NEWS', SITE_ID, ['EMAIL' => $email], 'N'); } sleep(2); // пауза между порциями держит нас в пределах тарифа провайдера}Порция в полсотни писем с короткой паузой подходит большинству тарифов. Точные числа берут из документации почтового сервиса, а не подбирают по ощущениям после первой блокировки.
Разбираем зависшие записи очереди:
SELECT ID, EVENT_NAME, DATE_INSERT, LIDFROM b_event WHERE SUCCESS_EXEC = 'N' AND DATE_INSERT < NOW() - INTERVAL 1 DAY LIMIT 20;-- эти письма не ушли, и причина почти всегда одна на всю пачкуЧистим отправленные записи по расписанию:
$conn = \Bitrix\Main\Application::getConnection();$conn->queryExecute("DELETE FROM b_event WHERE SUCCESS_EXEC = 'Y' AND DATE_INSERT < DATE_SUB(NOW(), INTERVAL 90 DAY) LIMIT 5000");// удаляют только отправленное и только порциями, иначе таблица блокируется надолгоТаблица очереди на магазине с рассылками растёт быстрее большинства других. Чистка порциями по расписанию решает вопрос заранее, а разовая уборка на миллионах строк надолго занимает базу данных.
Типичные проблемы
Письма уходят с задержкой в несколько минут.
Это нормальная работа очереди: отправку выполняет фоновая задача по расписанию. Мгновенная отправка возможна, но она замедляет страницу и упирается в лимиты провайдера.
Очередь растёт, а письма никому не приходят.
Фоновые задания выключены или падают с ошибкой на каждой попытке отправки. Проверяют расписание заданий и журнал почтового сервера за то же время.
Провайдер заблокировал отправку после рассылки.
Письма уходили без пауз и превысили предел писем в минуту по тарифу. Отправку ведут порциями с паузой, подобранной под ограничения сервиса.
Таблица очереди занимает больше самого каталога.
Отправленные записи копятся годами и никогда не удаляются. Старые успешно отправленные записи чистят по расписанию небольшими порциями.
Часть писем уходит дважды одному получателю.
Запись очереди не помечена отправленной из-за обрыва, и задание берёт её повторно. Такие случаи ловят по журналу отправки и по признаку успешности записи.
Частые вопросы
Почему письмо не уходит мгновенно?
Вызов отправки кладёт запись в очередь, а разбирает её фоновая задача по расписанию. Так страница не ждёт ответа почтового сервера и не упирается в его ограничения.
Можно ли отправить письмо сразу, минуя очередь?
Можно, но такой вызов задерживает страницу на время ответа сервера. Мгновенную отправку оставляют для единичных служебных писем, а не для покупателей.
Какой размер порции выбрать?
Тот, что укладывается в ограничения тарифа почтового сервиса с запасом. Числа берут из документации сервиса, а не подбирают после первой блокировки.
Что делать с зависшими записями?
Найти общую причину по журналу почтового сервера, починить её и перезапустить отправку. Удалять записи имеет смысл только после того, как причина устранена.
Сколько хранить отправленные записи?
Обычно достаточно двух-трёх месяцев для разбора жалоб покупателей. Дальше записи чистят по расписанию, освобождая место и ускоряя выборки.
Смежное
- Отправка почты с сервера - оглавление подтемы
- Настройка отправки почты: локальная отправка и SMTP - чем именно уходит письмо
- Письма с сайта не доходят: разбор причин по убыванию частоты - разбор, когда писем нет вовсе
- Письма не в спам: подписи домена, обратный адрес, репутация - что влияет на доставляемость
- Рассылка с нуля: сегмент, письмо, отправка, отписка - массовая отправка модулем рассылок
- Агенты не выполняются: разбор причин - когда очередь никто не разбирает
- База растёт: журналы, статистика, старые данные и чистка - чистка остальных служебных таблиц
- Сервер и поиск - устройство площадки целиком