События почтовой подсистемы Битрикс: OnBeforeMailSend, запись события и OnBeforeEventAdd
Где перехватывать логику
В «Главном модуле» исходящее письмо проходит несколько стадий: формируется запись о почтовом событии (тип, поля‑макросы, привязка к сайту и языку), подбирается шаблон, собираются заголовки и тело, затем пакет уходит транспорту. В зависимости от задачи удобнее цепляться либо к уже собранным параметрам отправки, либо к ORM‑событию добавления строки в таблице почтовых событий, либо к «классическому» событию до постановки в очередь.
OnBeforeMailSend: правка готового письма
Срабатывает, когда письмо уже сформировано из шаблона и ядро готовится к отправке. В обработчик передаётся \Bitrix\Main\Event; массив параметров берут так: $event->getParameter(0). Внутри — адресаты, тема, HTML‑тело, заголовки, идентификатор для трекинга, контекст доставки и прочие поля, которые дальше уйдут в почтовый транспорт.
Измените массив по месту и верните EventResult::SUCCESS с этим же массивом как данными результата — ядро подставит правленую версию. Для отладки на тестовом контуре достаточно логировать структуру через проектный логгер или AddMessage2Log, а не выводить print_r в ответ страницы.
use Bitrix\Main\EventManager;
use Bitrix\Main\Event;
use Bitrix\Main\EventResult;
EventManager::getInstance()->addEventHandler(
'main',
'OnBeforeMailSend',
static function (Event $event): EventResult {
/** @var array $mailParams */
$mailParams = $event->getParameter(0);
// Пример: дописать заголовок или изменить тему для выбранного типа.
// if (($mailParams['HEADER']['X-EVENT_NAME'] ?? '') === 'SALE_ORDER_DELIVERY') { … }
return new EventResult(EventResult::SUCCESS, $mailParams);
}
);OnBeforeAdd у почтового события (ORM)
Если нужно добавить или переопределить макрополя до шаблонизации, можно подписаться на событие сущности \Bitrix\Main\Mail\Internal\Event — точка входа в коде ядра названа OnBeforeAdd. В обработчике доступны поля будущей записи, в том числе массив C_FIELDS с подстановками для шаблона.
Важно: цепочка, которая использует CEvent::SendImmediate и обходит постановку записи в типичную очередь, может не заходить в этот обработчик. Для сценариев с немедленной отправкой закладывайте проверку на стенде или дублируйте логику на уровне OnBeforeEventAdd (см. ниже).
use Bitrix\Main\EventManager;
use Bitrix\Main\Mail\Internal\Event as MailEventEntity;
use Bitrix\Main\ORM\Event;
use Bitrix\Main\ORM\EventResult;
EventManager::getInstance()->addEventHandler(
'main',
MailEventEntity::class . '::OnBeforeAdd',
static function (Event $event) {
$fields = $event->getParameter('fields');
if (($fields['EVENT_NAME'] ?? '') !== 'SALE_ORDER_DELIVERY') {
return null;
}
$cFields = $fields['C_FIELDS'];
$cFields['MY_NEW_FIELD'] = 'значение для макроса в шаблоне';
$result = new EventResult();
$result->modifyFields(['C_FIELDS' => $cFields]);
return $result;
}
);Имена пространств имён (Entity vs ORM) в вашей сборке ядра могут отличаться; смысл — вернуть EventResult с изменёнными полями либо не трогать событие.
OnBeforeEventAdd: оба режима Send и SendImmediate
Отдельное событие OnBeforeEventAdd объявлено не в «документации D7» как отдельный модный класс, но вызывается и при обычной постановке, и при немедленной отправке. Сигнатура традиционна: по ссылке передаются имя типа события, $lid сайта, массив полей, идентификатор сообщения, файл и язык. Здесь удобно централизованно нормализовать поля для макросов или отфильтровать лишние отправки.
use Bitrix\Main\EventManager;
EventManager::getInstance()->addEventHandler(
'main',
'OnBeforeEventAdd',
'MyMailHooks::onBeforeEventAdd'
);
class MyMailHooks
{
public static function onBeforeEventAdd(
&$eventName,
&$lid,
&$fields,
&$messageId,
&$files,
&$languageId
): void {
// Например: добавить поле или заменить плейсхолдер до выбора шаблона.
}
}Как выбрать точку
- Нужно изменить уже сформированные заголовки или тело перед SMTP — чаще всего
OnBeforeMailSend. - Нужно изменить сохраняемые макрополя в записи события и вы уверены, что сценарий проходит через ORM —
Mail\Internal\Event::OnBeforeAddс учётом ограниченийSendImmediate. - Нужно покрыть и очередь, и немедленную отправку единообразно — начните с
OnBeforeEventAddи проверьте на своей версии ядра.
См. также
- Если почта не уходит с сайта — базовые проверки транспорта и конфигурации.
- Добавление своего поля в письмо о заказе — прикладной разбор для sale.
- В блоге Ciftix: отправка почты,
CEvent::Sendи вложения — соседний контур по классическому API.
Не хотите копаться сами?
Починю за 1-3 дня. Без предоплаты — оплата по результату.
15+ лет опыта с 1С-Битрикс · Без предоплаты · 7 дней гарантии