Email-розсилки на 1С-Бітрікс: кастомний модуль із чергами та трекінгом

Коли база підписників зростає, штатні інструменти 1С-Бітрікс перестають справлятися з розсилками: листи губляться, а аналітика відсутня. Ми розробляємо кастомні модулі розсилок з чергами, трекінгом і гнучкою сегментацією. Наша команда реалізує проєкт під ключ — від аудиту до впровадження та подальшої підтримки.

Email-розсилки на 1С-Бітрікс: кастомний модуль із чергами та трекінгом

Розробка модулівСередній~1-2 тижні
Часті запитання

Штатний модуль розсилок в 1С-Бітрікс перестає справлятися при базі від 10 000 контактів. Клієнти скаржаться на пропущені листи — стандартний subscribe стає вузьким горлечком. Без черги та трекінгу неможливо масштабувати email-маркетинг. Наша команда з 10-річним досвідом створює кастомні модулі підписки та розсилок під ключ: з чергами, трекінгом та гнучкою сегментацією. Орієнтовний термін розробки — від 2 тижнів. Зв'яжіться з нами, щоб обговорити ваш проєкт.

Чому стандартний модуль subscribe не підходить для великих розсилок?

Стандартний модуль зберігає підписників у таблиці b_subscribe_subscr_addr і шаблони листів у b_subscribe_posting. Логіка відправки — через агенти CAgent, які запускаються синхронно при HTTP-запитах. При базі від 10 000 контактів це призводить до таймаутів і пропусків. Додатково: немає вбудованого трекінгу відкриттів, немає черги повторних відправок при помилках SMTP, немає підтримки транзакційних листів з динамічним контентом через API. В одному з проєктів ми замінили штатний модуль на кастомний і скоротили витрати на email-маркетинг на 35% за рахунок відмови від дорогих сторонніх сервісів. Кастомний модуль обробляє в 3 рази більше листів за одиницю часу і в 5 разів знижує скарги на спам, забезпечуючи до 95% доставки.

Як кастомний модуль підвищує доставку?

Модуль реєструється стандартно через /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">
"}

Wait, the instruction says "Return ONLY the reformatted plain code text" but also "Return JSON: {"code": "<reformatted text with real 
>"}". The user explicitly asks for JSON. So I output JSON. The code is a single line, but we add a newline at the end? Actually the original had a trailing space and newline? The flattened line is: `<img src="https://site.ru/mailer/track/open/?uid=UNIQUE_TOKEN" width="1" height="1"> ` with a space at the end. But we must not alter characters other than adding newlines. So we keep the space? The instruction says "Do NOT alter any character other than adding 
 and leading indentation." So we keep the space. But we need to add newlines. Since it's a single line, we can just add a newline at the end? Or maybe we need to break it? Actually it's a single HTML tag, so no logical rows. So we just output the same line with a newline at the end. But careful: the original had a trailing space, we keep it. So the code string is: `<img src="https://site.ru/mailer/track/open/?uid=UNIQUE_TOKEN" width="1" height="1"> 
`? But the instruction says "real 
" in JSON, so we need to escape as \n. In JSON, we write "code": "<img ...> 
" but that 
 is an escape sequence. Actually in JSON, we need to represent newline as 
. So the JSON string will contain a backslash-n. So we output: {"code": "<img src="https://site.ru/mailer/track/open/?uid=UNIQUE_TOKEN" width="1" height="1"> 
"} but careful with quotes. Let me construct properly.

The original line: `<img src="https://site.ru/mailer/track/open/?uid=UNIQUE_TOKEN" width="1" height="1"> ` (with a space at the end). We add a newline after that space? Or before? Since it's a single line, we can just put a newline at the end. So the code becomes: `<img src="https://site.ru/mailer/track/open/?uid=UNIQUE_TOKEN" width="1" height="1"> 
` but that space is before newline. That is fine.

But wait, the instruction says "restore proper newlines inside a single code block that was flattened to one line". Since it's a single tag, there is no need for internal newlines. So we just add a newline at the end to represent the end of line. But the original might have had a newline? Actually the flattened line might have lost newlines. So we add a newline at the end.

Thus JSON: {"code": "<img src="https://site.ru/mailer/track/open/?uid=UNIQUE_TOKEN" width="1" height="1"> 
"} but we need to escape backslashes? No, only quotes and backslashes. The URL has no backslashes. So we escape double quotes inside the string. So the JSON string is: "<img src="https://site.ru/mailer/track/open/?uid=UNIQUE_TOKEN" width="1" height="1"> 
" but the 
 is an escape sequence, so in the actual JSON text we write backslash-n. So the output is:

{"code": "<img src="https://site.ru/mailer/track/open/?uid=UNIQUE_TOKEN" width="1" height="1"> 
"}

But wait, the original had a space after the >? Yes, there is a space. So we keep it. Also, we might want to remove the trailing space? No, we must not alter characters. So we keep it.

Thus final answer.<|end▁of▁thinking|>{"code": "<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() з каскадним видаленням з усіх пов'язаних таблиць.

Що входить у роботу?

  • Документація: опис архітектури, схема БД, інструкція з встановлення.
  • Вихідний код модуля з ліцензією.
  • Навчання: 2-годинний вебінар для адміністраторів.
  • Підтримка: 30 днів після запуску (виправлення багів, консультації).
  • Гарантія сумісності з версіями Бітрікс 20.0+ та PHP 8.1+.

Порівняння стандартного та кастомного модуля

Критерій Стандартний subscribe Кастомний модуль
Черга відправки Синхронна через CAgent Асинхронна, до 100 листів за тік
Сегментація Тільки за групами Динамічні фільтри AND/OR, JOIN з b_user
Трекінг відкриттів/кліків Відсутній Прозорий піксель + редирект
Транзакційні листи Немає Подієвий API, шаблони зі змінними
Інтеграція SMTP Тільки вбудований Абстракція транспорту, підключення будь-яких провайдерів
GDPR / відписка Базова відписка Посилання на відписку, експорт, видалення даних

Типові помилки при розробці модуля розсилок

  • Ігнорування черг — відправка в циклі призводить до зависання сайту. Завжди використовуйте асинхронну чергу.
  • Відсутність повторних спроб — якщо лист не пішов, потрібно повторити до 3 разів, інакше частину підписників втратите.
  • Немає трекінгу — неможливо оцінити ефективність кампанії. Вбудовуйте збір статистики з самого початку.
  • Жорстка прив'язка до одного SMTP — якщо провайдер падає, розсилка зупиняється. Використовуйте failover-транспорти.

Терміни та вартість

Етап Термін
Структура модуля, ORM-таблиці, інсталятор 2 дні
Черга та агенти відправки 2 дні
SMTP-транспорт + 1 API-провайдер 1 день
Трекінг відкриттів і кліків 1 день
Сегментація, групи 1 день
Транзакційні листи 1 день
Адміністративний інтерфейс 2 дні
Відписка, GDPR, тестування 1 день

Разом: від 11 робочих днів для базового варіанту. Підключення додаткових API-провайдерів (Mailchimp, UniSender) — +1 день кожен.

Вартість розробки розраховується індивідуально після аналізу ваших вимог. Замовте розробку модуля вже сьогодні. Отримайте консультацію — ми допоможемо підібрати оптимальне рішення.

Для глибокого розуміння ORM Бітрікс рекомендуємо вивчити офіційну документацію. Також корисно прочитати про SMTP-протокол та REST API.

Наші компетенції:

Останні роботи

  • Розробка сайту компанії B2B ADVANCE
    Розробка сайту компанії B2B ADVANCE
    1543
  • Розробка веб-сайту для компанії ФІКСПЕР
    Розробка веб-сайту для компанії ФІКСПЕР
    1060
  • Розробка віджета онлайн-запису для медичного центру
    Розробка віджета онлайн-запису для медичного центру
    837
  • Розробка на базі 1С Підприємство для компанії МИРСАНБЕЛ
    Розробка на базі 1С Підприємство для компанії МИРСАНБЕЛ
    928
  • Розробка сайту на CRM Бітрікс24 для компанії DOLBIMBY
    Розробка сайту на CRM Бітрікс24 для компанії DOLBIMBY
    865
  • Розробка на базі Бітрікс24 для компанії ТЕХНОТОРГКОМПЛЕКС
    Розробка на базі Бітрікс24 для компанії ТЕХНОТОРГКОМПЛЕКС
    1223