Розробка модуля розсилок для 1С-Бітрікс
Вбудований модуль розсилок у 1С-Бітрікс (subscribe) існує давно, але у реальних проектах він швидко упирається в обмеження: відсутня гнучка сегментація, немає подій-триггерів, складно інтегрувати з зовнішніми 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 або вбудовану функцію 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 день для кожного.







