Разработка модуля рассылок 1С-Битрикс
Штатный модуль рассылок в 1С-Битрикс (subscribe) существует давно, но в реальных проектах он быстро упирается в ограничения: нет гибкой сегментации, нет event-триггеров, сложно интегрировать с внешними SMTP-провайдерами. Когда бизнес перерастает стандарт — пишем собственный модуль.
Что не устраивает в базовом subscribe
Стандартный модуль хранит подписчиков в таблице b_subscribe_subscr_addr и шаблоны писем в b_subscribe_posting. Логика отправки — через агенты CAgent, которые запускаются синхронно при HTTP-запросах. При базе от 10 000 контактов это приводит к таймаутам и пропускам.
Дополнительно: нет встроенного трекинга открытий, нет очереди повторных отправок при ошибках SMTP, нет поддержки транзакционных писем с динамическим контентом через API.
Архитектура кастомного модуля
Модуль регистрируется стандартно через /bitrix/modules/vendor.mailer/install/index.php с классом vendor_mailer. Пространство имён — \Vendor\Mailer.
Ключевые компоненты:
-
SubscriberTable — ORM-таблица
b_vendor_mailer_subscriber(id, email, name, status, groups, created_at, unsubscribed_at) -
CampaignTable —
b_vendor_mailer_campaign(id, name, subject, template_id, status, scheduled_at, sent_count, open_count) -
QueueTable —
b_vendor_mailer_queue(id, campaign_id, subscriber_id, status, attempts, last_error, sent_at) -
EventTable —
b_vendor_mailer_event(id, subscriber_id, type, payload, created_at) — трекинг открытий и кликов
Таблицы создаются через \Bitrix\Main\ORM\Data\DataManager с полной поддержкой D7-ORM.
Очередь отправки
Синхронная отправка через CAgent — путь в никуда. Используем очередь:
// Постановка в очередь при старте кампании
public function enqueue(int $campaignId): void
{
$subscribers = SubscriberTable::getList([
'filter' => ['=STATUS' => 'active', '=GROUPS' => $this->campaign->getGroups()],
'select' => ['ID', 'EMAIL', 'NAME'],
]);
while ($row = $subscribers->fetch()) {
QueueTable::add([
'CAMPAIGN_ID' => $campaignId,
'SUBSCRIBER_ID' => $row['ID'],
'STATUS' => 'pending',
'ATTEMPTS' => 0,
]);
}
}
Обработчик очереди запускается агентом каждые 2 минуты, берёт пакет из 100 записей со статусом pending, отправляет через выбранный транспорт и обновляет статус на sent или failed.
Транспорты: SMTP и API-провайдеры
Абстракция транспорта реализована через интерфейс MailTransportInterface:
interface MailTransportInterface
{
public function send(Message $message): SendResult;
}
Конкретные реализации: SmtpTransport (через PHPMailer или native mail()), SendGridTransport (REST API v3), MailgunTransport, AmazonSesTransport. Транспорт выбирается в настройках модуля (b_option, пространство vendor.mailer).
При ошибке отправки статус переходит в failed, счётчик attempts увеличивается. При attempts >= 3 запись помечается как dead и не обрабатывается повторно.
Трекинг открытий и кликов
В письмо вставляется прозрачный 1×1 пиксель:
<img src="https://site.ru/mailer/track/open/?uid=UNIQUE_TOKEN" width="1" height="1">
При GET-запросе контроллер записывает событие в b_vendor_mailer_event и возвращает 1×1 GIF. Клики трекируются через редирект: все ссылки в письме заменяются на https://site.ru/mailer/track/click/?uid=TOKEN&url=ENCODED_URL.
Обработчик события:
EventTable::add([
'SUBSCRIBER_ID' => $subscriberId,
'CAMPAIGN_ID' => $campaignId,
'TYPE' => 'open', // или 'click'
'PAYLOAD' => json_encode(['url' => $url, 'ip' => $_SERVER['REMOTE_ADDR']]),
'CREATED_AT' => new \Bitrix\Main\Type\DateTime(),
]);
Сегментация подписчиков
Группы хранятся в b_vendor_mailer_group, связь с подписчиками — через b_vendor_mailer_subscriber_group. Сегментация поддерживает условия по полям профиля пользователя Битрикс (b_user) через JOIN.
Динамические сегменты строятся через конструктор фильтров в административном интерфейсе — тот же подход, что в CRM Битрикс: набор условий с операторами AND/OR, которые транслируются в ORM-фильтр при постановке в очередь.
Транзакционные письма
Для системных писем (подтверждение email, сброс пароля, уведомления о заказе) модуль предоставляет событийный API:
// Отправка транзакционного письма
\Vendor\Mailer\Transactional::send('order_confirmed', [
'USER_ID' => $userId,
'ORDER_ID' => $orderId,
'ORDER_SUM' => $orderSum,
'ITEMS' => $orderItems,
]);
Шаблоны транзакционных писем хранятся в b_vendor_mailer_template и редактируются через административный раздел с поддержкой переменных в формате {{ORDER_ID}}.
Административный интерфейс
Модуль добавляет разделы в /bitrix/admin/:
-
vendor_mailer_subscribers.php— список и управление подписчиками -
vendor_mailer_campaigns.php— кампании, статус, статистика -
vendor_mailer_templates.php— редактор шаблонов -
vendor_mailer_settings.php— настройки транспорта, DKIM, лимиты
Интерфейс построен на стандартных классах CAdminList, CAdminForm — полная совместимость с темой оформления Битрикс.
Отписка и GDPR
Ссылка отписки в каждом письме ведёт на https://site.ru/mailer/unsubscribe/?token=TOKEN. При переходе статус подписчика меняется на unsubscribed, заполняется поле unsubscribed_at. Повторная постановка в очередь для таких записей блокируется на уровне фильтра.
Для соответствия GDPR: экспорт данных подписчика по запросу (GET /mailer/export-personal/?token=TOKEN), полное удаление через SubscriberTable::delete() с каскадным удалением из всех связанных таблиц.
Сроки разработки
| Этап | Срок |
|---|---|
| Структура модуля, ORM-таблицы, инсталлятор | 2 дня |
| Очередь и агенты отправки | 2 дня |
| SMTP-транспорт + 1 API-провайдер | 1 день |
| Трекинг открытий и кликов | 1 день |
| Сегментация, группы | 1 день |
| Транзакционные письма | 1 день |
| Административный интерфейс | 2 дня |
| Отписка, GDPR, тестирование | 1 день |
Итого: 11 рабочих дней для базового варианта. Подключение дополнительных API-провайдеров (Mailchimp, UniSender) — +1 день каждый.







