Рассылки изнутри - два модуля, выпуск, очередь
Разбираем рассылки по слоям: в платформе живут два разных механизма с одним и тем же словом «рассылка». Смотрим, из чего собран выпуск, кто двигает очередь и что отменяет отписка.
Механика
Модулей рассылки в платформе ровно два, и они не связаны между собой ничем, кроме почтового сервера. Старая «Подписка, рассылки» лежит в разделе сервисов, современный «Email-маркетинг» - в разделе маркетинга.
Сущности у них разные вплоть до названий. Подписка оперирует рубриками, подписчиками и выпусками, а Email-маркетинг - контактами, сегментами, кампаниями и письмами. Рубрика и сегмент похожи только на словах: на рубрику подписываются сами, сегмент вычисляется отбором перед каждой отправкой.
Хранилища адресов у модулей тоже разные и между собой не синхронизируются. Один и тот же адрес заводится отдельной записью в подписчиках рубрик и отдельной записью в списке адресов маркетинга. Правка одной записи вторую не трогает никогда.
Форм подписки на публичной части тоже две, и названия у них обманчиво близкие. Старая пара - это форма подписки и страница управления своим адресом, а у Email-маркетинга собственный компонент подписки, который пишет адрес в список адресов. Именно на этой паре ломается большинство настроек.
Выпуск старого модуля собирается из четырёх частей: рубрики, темы, тела письма и адреса отправителя. Адресатами становятся подписчики рубрики с подтверждённой подпиской, а адрес отправителя по умолчанию приходит из настроек модуля. Автоматический выпуск добавляет к этому PHP-шаблон и расписание генерации.
Рассылка Email-маркетинга собрана иначе: шаблон письма, сегмент получателей и кампания, внутри которой она живёт. Сегмент объединяет динамические списки из коннекторов и статические наборы адресов, причём динамика пересчитывается перед каждой отправкой заново.
При запуске выпуск не отправляется целиком и сразу: он переходит в состояние отправки и дальше разбирается порциями. Кнопка запуска меняет только состояние записи, а письма формирует фоновая задача, о существовании которой интерфейс ничего не говорит.
Очередь двигают агенты, а у больших объёмов - задание по расписанию сервера. Агенты на хитах зависят от посещаемости, поэтому на малопосещаемом сайте рассылка растягивается на дни. Перевод агентов на расписание сервера снимает эту привязку к трафику.
Подписчик и адресат - разные вещи, и согласие у них хранится в разных местах. У подписки согласие - это признак подтверждения у записи подписчика, а у Email-маркетинга роль стоп-признака играет чёрный список поверх всех рассылок сразу.
Отписка тоже двухуровневая, и уровни легко перепутать. Снятие привязки к конкретной рассылке оставляет адрес в базе и в остальных рассылках, а чёрный список исключает его отовсюду. Отписка в одном модуле писем второго модуля не отменяет.
Триггерное письмо уходит не мгновенно даже при верной настройке цепочки. Проверка условий ежедневная, минимальный срок отсчитывается днями, а ретроспективу включает отдельный флаг обработки старых данных. Достижение цели прерывает цепочку на любом шаге.
Шаги
- Определить модуль по разделу админки и по имени компонента формы подписки на сайте.
- Найти адрес в обоих хранилищах: в подписчиках рубрик и в списке адресов маркетинга.
- Разобрать один выпуск на части: адресаты, тело письма, адрес отправителя и текущее состояние.
- Проверить, кто двигает очередь: агенты на хитах или задание по расписанию сервера.
- Проследить отписку до конца и понять, какие именно письма она отменила.
Код
Смотрим, какие модули рассылки вообще установлены:
printf("subscribe=%d sender=%d\n", (int)IsModuleInstalled('subscribe'), // «Подписка, рассылки», раздел сервисов (int)IsModuleInstalled('sender')); // «Email-маркетинг», раздел маркетинга// sender отсутствует в редакциях «Старт» и «Стандарт»: там остаётся только подпискаОба модуля спокойно живут на одном сайте одновременно и друг о друге не знают. Проверка установки отвечает на первый вопрос разбора: какой механизм вообще доступен на этом проекте.
Читаем рубрики старого модуля:
\Bitrix\Main\Loader::includeModule('subscribe');$res = \CRubric::GetList(['SORT' => 'ASC'], ['ACTIVE' => 'Y']);while ($rubric = $res->Fetch()) { printf("%-4d %-28s подписчиков=%d\n", $rubric['ID'], $rubric['NAME'], $rubric['COUNT_ALL'] ?? 0);}// сообщение «Не найдено рубрик для подписки» в форме означает, что этот список пустРубрика - это тема, на которую человек подписывается осознанно и сам. Пустой список рубрик превращает форму подписки в сообщение об ошибке, хотя сам компонент установлен и настроен верно.
Находим адрес среди подписчиков рубрик:
$row = \CSubscription::GetByEmail($email)->Fetch();printf("активна=%s подтверждена=%s\n", $row['ACTIVE'] ?? '-', $row['CONFIRMED'] ?? '-');// адрес без признака подтверждения числится в базе, а выпуски мимо него проходятНаходим тот же адрес в списке адресов маркетинга:
\Bitrix\Main\Loader::includeModule('sender');$contact = \Bitrix\Sender\ContactTable::getList([ 'select' => ['ID', 'CODE', 'BLACKLISTED'], 'filter' => ['=CODE' => $email],])->fetch();// CODE хранит сам адрес; запись в подписчиках рубрик - это совершенно другая строкаДва запроса выше обращаются к разным таблицам разных модулей. Адрес, найденный одним из них и не найденный вторым, объясняет половину жалоб вида «подписался, а писем нет».
Сравниваем две формы подписки:
// форма старого модуля: адрес уходит в подписчиков выбранных рубрик$APPLICATION->IncludeComponent('bitrix:subscribe.form', '', ['SHOW_HIDDEN' => 'N']);
// форма Email-маркетинга: адрес уходит в список адресов маркетинга$APPLICATION->IncludeComponent('bitrix:sender.subscribe', '', []);// имена компонентов почти совпадают, а пишут они в разные хранилищаИмя компонента в шаблоне сайта отвечает на вопрос о модуле точнее любых догадок. С него начинают разбор, когда подписка внешне работает, а ожидаемых писем и обработчиков нет.
Разбираем состав одного выпуска подписки:
Выпуск = рубрика + тема + тело письма + адрес отправителя рубрика - адресаты: подписчики рубрики с подтверждённой подпиской тело - HTML или текст с подстановками вида #NAME# «От кого» - берётся из настроек модуля подписки, если не задан у выпуска расписание - только у автоматической рубрики: дни недели либо числа месяца# без расписания автоматический выпуск не сформируется вообще никогдаРасписание - обязательная часть автоматической рассылки, а не украшение. Рубрика без расписания выглядит полностью настроенной и при этом не порождает ни одного выпуска.
Ищем события нужного модуля в его коде:
grep -rn 'ExecuteModuleEventEx\|GetModuleEvents' /home/bitrix/www/bitrix/modules/subscribe/ | headgrep -rn 'Event::send\|new Event(' /home/bitrix/www/bitrix/modules/sender/lib/ | head# имена событий у модулей свои: обработчик подписки на рассылку маркетинга не сработает# идентификатор модуля в вызове - первый аргумент, его и указывают при регистрацииОбработчик, повешенный на чужой модуль, не даёт ни ошибки, ни записи в журнале. Он просто молчит, и разбор такой жалобы начинается с вопроса, каким компонентом собрана форма подписки на сайте.
Смотрим ход разбора очереди Email-маркетинга:
$rows = \Bitrix\Sender\PostingTable::getList([ 'select' => ['ID', 'STATUS', 'COUNT_SEND_ALL', 'COUNT_SEND_NONE'], 'order' => ['ID' => 'DESC'], 'limit' => 5,])->fetchAll();// растущее COUNT_SEND_ALL - это и есть ход отправки, а замершее означает стоящую очередьОтписываем адрес от конкретных рассылок:
$result = \Bitrix\Sender\Subscription::unsubscribe([ 'EMAIL' => $email, 'UNSUBSCRIBE_LIST' => [$mailingId], // отписка от перечисленных рассылок]);// снятие привязки к рассылке и признак чёрного списка - это два разных уровня отказаОтписка от одной рассылки оставляет адрес во всех остальных. Полный отказ от писем даёт только чёрный список, и в подписчиках рубрик старого модуля он при этом ничего не меняет.
Ограничения
Модуль Email-маркетинга недоступен в редакциях «Старт» и «Стандарт» вместе с триггерными рассылками. На таких проектах рассылки собирают старой подпиской, и сегментов там не появится никакими настройками.
Часть возможностей появилась только в свежих сборках платформы. Лимит отправителя доступен с версии 23.900.500, копирование сегмента - с 22.200.0, а опция ежедневной отправки в коробочном портале отсутствует вовсе.
Динамическое содержимое письма собирается только почтовыми компонентами и только в периодических рассылках. Добавить их в шаблон может лишь группа с операцией ограниченной модификации шаблонов, иначе нужных блоков в редакторе не видно.
Триггер срабатывает не мгновенно: проверка идёт ежедневно, а минимальный срок отсчитывается сутками от даты настройки. Ретроспективу событий включает отдельный флаг обработки старых данных, без него учитываются только новые события.
Отслеживание прочтений держится на невидимой картинке внутри письма. Почтовые службы проксируют и кэшируют картинки по-своему, поэтому доля прочтений на крупных доменах занижена и с долей переходов не сходится.
Типичные проблемы
Обработчик события подписки не срабатывает вообще.
Форма на сайте принадлежит одному модулю рассылок, а обработчик повешен на события второго. Событие чужого модуля молчит без ошибки, и понять это по журналу невозможно.
Форма подписки пишет «Не найдено рубрик для подписки».
Рубрики есть только у старого модуля подписки, и активных рубрик в нём не заведено. Сегменты Email-маркетинга этот компонент не видит и подставить в форму не может.
Событие перед отправкой выпуска ничего не меняет в письме.
Событие относится к выпускам старого модуля подписки, а не к рассылкам маркетинга. При создании выпуска из кода оно к тому же требует явного признака прямой отправки.
Отписавшийся получатель продолжает получать письма.
Отписка сняла привязку к одной рассылке, а остальные рассылки остались при своих адресатах. Полный отказ от писем даёт только чёрный список поверх всех рассылок сразу.
Процент прочтений в точности равен проценту переходов.
Невидимую картинку отслеживания не грузят почтовые службы, проксирующие изображения писем. Засчитываются только те открытия, за которыми последовал переход по ссылке.
Автоматическая рассылка настроена, а выпуски не формируются.
У рубрики не задано расписание генерации либо на сайте не выполняются агенты. Расписание требует хотя бы одного параметра: дней недели или чисел месяца.
Частые вопросы
Чем модуль подписки отличается от Email-маркетинга?
Это два независимых модуля с разными разделами админки, компонентами и хранилищами адресов. Подписка работает рубриками и выпусками, маркетинг - сегментами, кампаниями и письмами.
Почему не срабатывает событие подписки на рассылку?
Обычно событие повешено на модуль подписки, а форма на сайте принадлежит Email-маркетингу. Такой обработчик молчит без ошибки, потому что событие возбуждает другой модуль.
Как отписать адрес от всех рассылок сразу?
Признаком чёрного списка у контакта: он исключает адрес из всех рассылок маркетинга. Отписка от одной рассылки снимает только её привязку и остальных не касается.
Почему триггерное письмо приходит через сутки?
Условия триггера проверяются ежедневно, а минимальный срок отсчитывается днями от настройки. Мгновенной реакции на событие от триггерной цепочки ждать не стоит.
В каких редакциях есть Email-маркетинг?
В редакциях «Старт» и «Стандарт» модуля нет вместе с триггерными рассылками. Там остаётся старая подписка с рубриками, подписчиками и выпусками.
Смежное
- Email-маркетинг - оглавление подтемы
- Маркетинг и SEO - карта модулей маркетинга целиком
- Подписка на новости: рубрики, форма, автоматический выпуск - настройка старого модуля по шагам
- Рассылка с нуля: сегмент, письмо, отправка, отписка - сборка рассылки в Email-маркетинге
- Триггерные письма: событие, цепочка, цель и отписка - настройка цепочки по событию
- Рассылка не отправляется: разбор причин - когда письма не уходят вовсе
- Очередь писем: фоновая отправка, порции, повторы, чистка - почтовая очередь ядра под рассылками
- Агенты изнутри: расписание, хиты, cron, блокировка - кто двигает очередь отправки
- Своё письмо с сайта: тип события, шаблон, поля - одиночное письмо вместо рассылки
- Модули и решения - устройство модулей платформы