База знаний GetMyBot

Email-рассылки

Подготовка, проверка, планирование и управление email-рассылкой, трекинг и режим приватности, входящие ответы и контракт вебхуков провайдера.

На этой странице

Email-рассылка отправляет одну опубликованную версию контента аудитории, давшей согласие, с вашего подтверждённого домена.

Что нужно до первой рассылки

Нужны две вещи: тариф с email-каналом и подтверждённый домен отправки. Проверять их стоит именно в таком порядке.

Тариф с email-каналом

Email относится к конструктору ботов, а в линейке конструктора четыре тарифа:

  • «Старт»: бесплатный, email в него не входит;
  • «Про», «Бизнес» и «Enterprise»: платные, email входит в каждый.

Проверяйте названия тарифов: «Старт» бесплатный, а младший платный тариф называется «Про».

Ни один тариф линейки «Коммуникации с клиентами» email не даёт: ни «Общение», ни «Поддержка», ни «Маркетинг», ни «Маркетинг Эксперт». Пункт «Кампании» у двух последних означает проактивные сообщения и попапы в виджете, писем он не включает. Бесплатное включение конструктора вместе с платным тарифом CE также не даёт email, поскольку это тариф «Старт».

На тарифе без email-канала закрыт весь email-раздел: домены отправки, входящие маршруты, рассылки и их статистика. Любой запрос к ним отвечает 402 и называет недостающую возможность (email). Тариф стоит проверить до правки DNS: без email-канала домен добавить не получится, и настройка SPF, DKIM и DMARC пройдёт впустую. См. Тарифы.

Подтверждённый домен отправки

Пока домен не подтверждён, письма не отправляются вообще. Как его подключить, описано в статье Email с вашего домена.

Когда оба условия выполнены, откройте раздел Email и перейдите по ссылке Email-рассылки.

Редактор

Редактор рассылки состоит из четырёх шагов.

Письмо и отправитель. Название рассылки (до 160 символов), домен отправки, имя отправителя, адрес для ответа, тема (до 255 символов) и прехедер (до 500 символов). Адрес для ответа указывается «голым», например hello@example.com, без отображаемого имени. Переводы строки в имени отправителя, адресе для ответа, теме и прехедере запрещены: через них возможна подмена заголовков письма.

Контент и предпросмотр. Выберите опубликованную версию email-контента или создайте её из шаблона. Рассылка сохраняет идентификатор документа вместе с точным номером версии, поэтому последующая публикация документа не изменит уже запланированную рассылку.

Аудитория и эксперимент. Либо все email-подписчики бота, либо один готовый сегмент. При желании подключите A/B-эксперимент: при планировании рассылка зафиксирует версию эксперимента и будет отчитываться по этому снимку.

Расписание и приватность. Время отправки, режим часового пояса, писем в минуту (от 1 до 10 000) и переключатель сбора открытий. Время отправки указывать необязательно: рассылка без него стартует сразу при запуске.

Режимов часового пояса два. По времени рассылки все получают письмо в один абсолютный момент, посчитанный в часовом поясе рассылки. По местному времени получателя у каждого на часах одно и то же время в его собственном поясе.

Список поясов фиксированный: Москва, Белград, Лондон, Берлин, Дубай, Алматы, Тбилиси, Ереван, Ташкент, Бангкок, Токио, Нью-Йорк, Лос-Анджелес, UTC.

Перевод часов обрабатывается явно:

  • редактор не принимает время отправки, которого в этот день не существует в часовом поясе рассылки, и пишет об этом под полем;
  • в режиме местного времени получатель, у которого это время на часах в тот день не наступает, попадает в проверку с кодом nonexistent_local_time, и запуск заблокирован, пока время не изменят;
  • если время на часах повторяется дважды, для всех берётся более ранний момент.

В режиме местного времени человек без пригодного часового пояса исключается из рассылки, поэтому письмо в произвольный час ему не уйдёт.

Проверка получателей до отправки

Кнопка Проверить получателей ничего не отправляет. Она собирает аудиторию по текущему черновику и правилам согласия и отвечает, сколько человек получит рассылку, сколько исключено и почему, а также какие в контенте ошибки и предупреждения. Коды в ответе совпадают с кодами в интерфейсе.

Адрес попадает в исключённые, если:

  • его подписка не в состоянии «подписан», причиной тогда указано само состояние: unsubscribed, bounced или complained;
  • адрес пуст или непригоден (invalid_email);
  • такой же нормализованный адрес уже есть в этой рассылке (duplicate);
  • включён режим местного времени, а у человека нет часового пояса (missing_timezone), он не распознан (invalid_timezone) либо такого местного времени в этот день не существует (nonexistent_local_time);
  • согласие было отозвано между подготовкой списка и попыткой отправки (no_consent).

Запуск блокируют именно ошибки:

  • domain_not_verified: домен отправки не подтверждён;
  • content_not_published: выбранной версии контента нет или она не опубликована;
  • audience_not_ready: выбранного сегмента нет или он ещё не пересчитан;
  • experiment_not_ready: связанный эксперимент не запущен либо его текущая версия распределяет не по подписчикам;
  • scheduled_in_past: время отправки уже прошло;
  • nonexistent_local_time: см. выше;
  • empty_audience: рассылку никто не получит;
  • все ошибки контента из Студии контента, привязанные к полю content_document_id и к проблемному блоку.

Предупреждения контента приходят там же, плюс одно собственное:

  • missing_plain_text: в контенте нет читаемого текста, только медиа и кнопки, поэтому текстовая часть письма окажется пустой.

Рассылку можно запустить только при нуле ошибок. Предупреждения запуск не блокируют.

Кнопка Отправить тестовое письмо отправляет контент рассылки на один уже подтверждённый и не отписавшийся email-контакт этого бота. Строки получателей рассылки при этом не затрагиваются, а произвольный адрес ввести нельзя, поэтому тест не может испортить запланированную отправку.

Запуск и управление

Запустить можно только рассылку в состоянии «Черновик». Запуск требует явного подтверждения и ревизии, которая сейчас на экране. При запуске платформа фиксирует версию контента, отправителя, аудиторию, расписание и версию эксперимента в неизменяемом снимке отправки. Для каждого подходящего адреса создаётся строка получателя.

После этого рассылку нельзя редактировать. Чтобы что-то изменить, нажмите Создать копию и запустите копию.

Статусы: Черновик, Запланирована, Отправляется, На паузе, Завершена, Отменена, Не удалась, В архиве. Из каких статусов доступны действия:

  • Поставить на паузу: из «Запланирована» или «Отправляется».
  • Продолжить: из «На паузе», обратно в «Запланирована».
  • Отменить: из «Черновик», «Запланирована», «Отправляется» или «На паузе». Тем, кому ещё не отправили, письмо не уйдёт.
  • В архив: из «Черновик», «Завершена», «Отменена» или «Не удалась».

Каждое действие управления тоже несёт ожидаемую ревизию, поэтому два оператора не могут незаметно перебить работу друг друга.

Сама отправка идёт с заданной скоростью писем в минуту, выполняется пачками с арендой задания и переживает перезапуск воркера. Получателя с временной ошибкой отправки повторяют с растущей задержкой: начиная с 15 секунд и не больше 15 минут. Если провайдер отправку принял, но её исход не подтверждён, получатель записывается со статусом «Статус неизвестен». Повтор в этом случае рисковал бы вторым письмом тому же человеку, поэтому его нет.

Трекинг, приватность и отписка

Для пикселя открытия, перехода и отписки используется подписанный токен вашей установки вида https://<ваш-хост>/e/t/<токен>. Токены подписаны HMAC, ограничены одним ботом, рассылкой и получателем и истекают через 90 дней после отправки. Ключ подписи выводится из секрета почтовых вебхуков установки, и без этого секрета рассылка не отправится вообще, так что письма с неотслеживаемыми ссылками не уходят.

  • Для необязательного отслеживания открытий используется GIF 1×1. Если выключить «Собирать статистику открытий», пиксель просто не добавляется, а доставка, переходы, жалобы и отписки продолжают считаться. Открытия всегда занижены, объяснение есть в статье Email с вашего домена.
  • Отслеживание переходов переписывает только кнопки-ссылки на https://. Токен перехода несёт адрес назначения, и этот адрес обязан быть https://-ссылкой с хостом и без встроенных учётных данных, поэтому перенаправить его в другое место нельзя.
  • Токены отписки не несут ни идентификатора ссылки, ни адреса перехода: по такому токену можно отписаться, но нельзя никуда перенаправить.

Недействительный, истёкший, чужой или неизвестный токен получает 404 без подробностей, поэтому по токену нельзя разведать существующие рассылки и получателей.

Отписка работает по RFC 8058 в один клик. GET показывает простую HTML-страницу подтверждения без JavaScript, а POST с единственным полем формы List-Unsubscribe=One-Click выполняет отписку. Повторная отписка тем же токеном считается успехом: почтовые клиенты предзагружают ссылки, а люди кликают дважды. Отказ записывается и в строку получателя, и в канонический учёт согласий одной транзакцией, поэтому ссылка не может отчитаться об успехе, оставив согласие активным.

Отчёт

В отчёте по рассылке отдельно показаны: Получатели, Исключены, Ожидают, Отправляются, Принято провайдером, Статус неизвестен, Доставлено, Открыто, Переходы, Возвраты, Жалобы, Отписки, Ошибки и Отменены. Переходы показываются по каждой ссылке, а получателей можно листать постранично со статусом и причиной исключения.

Атрибутированная выручка показывается отдельно по каждой модели атрибуции и каждой валюте и никогда не суммируется между ними: разные модели законно приписывают одну конверсию по-разному, а смешанная по валютам сумма не имеет смысла.

Ответы получателей

Входящий маршрут превращает адрес на подтверждённом домене в обращение в поддержку. Локальная часть адреса хранится только в виде необратимого хеша, поэтому сам адрес рядом с маршрутом не сохраняется.

Экрана для маршрутов в панели пока нет. Управляйте ими через API с токеном, у которого есть settings:read / settings:write:

curl -X POST "$BASE_URL/api/bots/$BOT_ID/email/inbound-routes" \
  -H "Authorization: Bearer $PAT" -H "Content-Type: application/json" \
  -d '{"domain":"mail.example.com","local_part":"support"}'

Локальная часть приводится к нижнему регистру и должна подходить под [a-z0-9][a-z0-9._+-]{0,62}. Домен уже должен быть подтверждён для этого бота, иначе ответ будет 422; повторный тот же адрес даст 409. Полный адрес возвращается один раз, при создании: в списке потом виден только домен, потому что локальная часть не хранится. Если в установке не настроен секрет почтовых вебхуков, ответ будет 503, и входящая почта выключена целиком.

Входящее письмо нормализуется до того, как попадёт в диалог:

  • отправитель сопоставляется с подписчиком по нормализованному адресу;
  • In-Reply-To и References продолжают существующую переписку, но только если она принадлежит тому же человеку;
  • цитируемая история вырезается из текста;
  • исходное письмо ограничено 8 МиБ, извлечённый текст 256 КиБ, тема 255 символами, а References 32 записями;
  • сохраняется не больше 5 вложений размером не больше 1 МиБ каждое, по контентному ключу; исполняемые вложения (.bat, .cmd, .com, .dll, .exe, .msi, .scr и MIME-типы исполняемых файлов) отклоняются;
  • письмо только в HTML сводится к тексту.

Письмо на неизвестный маршрут отклоняется с кодом 404. У этого есть цена, о которой лучше знать заранее: провайдер считает 404 неудачей доставки и будет повторять попытку часами, а потом отчитается о ней вам. Опечатка в адресе или маршрут, которого нет, оборачиваются часами повторов у провайдера.

Причина в том, как хранятся маршруты. Локальная часть лежит в виде хеша, посчитанного на секрете почтовых вебхуков установки, и пересчитать эти хеши при смене секрета нельзя, поэтому после ротации секрета ни один маршрут больше не находится. Ответ «принято» в такой ситуации сообщал бы провайдеру об успешной доставке, и входящая почта исчезала бы совсем тихо: ничего не повторялось бы и никто об этом не узнал. Отказ с 404 делает поломку видимой.

Практический вывод: если после смены секрета почтовых вебхуков вы видите повторы и жалобы провайдера на входящие, заведите входящие маршруты заново, старые уже не сработают.

Контракт провайдера

Если вы держите собственную установку или пишете адаптер к почтовому провайдеру, вот два публичных эндпоинта, с которыми он общается. Оба проверяют подпись HMAC-SHA256 по сырому телу запроса, в hex, в заголовке X-Signature, на настроенном секрете вебхуков почты. Запрос без подписи отклоняется с 401, и так же отклоняется любой запрос, если секрет не настроен: эндпоинт закрывается по умолчанию.

События доставки и вовлечения

POST /esp/{provider}/webhook, тело до 1 МиБ:

{
  "provider_id": "prv_00000000-0000-0000-0000-000000000000",
  "event": "delivered",
  "bounce_class": "hard",
  "url": "https://example.com/offer",
  "event_id": "evt_0000000001",
  "tag": "email-campaign:11111111-1111-1111-1111-111111111111:22222222-2222-2222-2222-222222222222"
}

Это собственный обобщённый контракт платформы, а не формат какого-то одного провайдера. Ваш адаптер переводит callback провайдера в него.

  • event принимает значения delivered, opened, clicked, bounced, complained, unsubscribed. Незнакомое значение сохраняется для разбора и ничего не меняет.
  • bounce_class равен hard или soft и имеет смысл только для bounced.
  • tag содержит стабильные метаданные, переданные при отправке, в виде email-campaign:<id рассылки>:<id подписчика>. Он позволяет найти получателя, если callback пришёл раньше, чем сохранился идентификатор провайдера.

Как события отображаются в состояния:

  • delivered: письмо и получатель рассылки переходят в «Доставлено»;
  • bounced с bounce_class: hard: письмо «Возврат», адрес исключается, получатель «Возврат»;
  • bounced с bounce_class: soft: записывается только событие. Мягкий возврат говорит о конкретной попытке, а не об адресе, поэтому он никого не исключает и не меняет состояние получателя;
  • complained: записывается жалоба, адрес закрывается навсегда;
  • unsubscribed: согласие отзывается, получатель «Отписан»;
  • opened и clicked: записываются как события, состояние не меняется.

Callback, пришедший не по порядку, не может откатить конечное состояние назад.

Идемпотентность строится на event_id, если провайдер его присылает, иначе на SHA-256 сырого тела. Проверка, эффекты и отметка о приёме пишутся одной транзакцией, сериализованной по паре «бот и ключ», поэтому два одновременных дубля одного события не применятся дважды.

Коды ответа подсказывают адаптеру, что делать:

  • 200: событие понято. Сюда же попадают намеренно проигнорированные события: дубль или неизвестный идентификатор письма, которое эта установка не отправляла. Повтор ничего не изменит.
  • 400: некорректное тело или отсутствует provider_id либо event.
  • 401: подпись неверна или отсутствует.
  • 413: тело больше лимита.
  • 500: временный сбой на нашей стороне. Повторять стоит только этот класс.

Входящая почта

POST /esp/{provider}/inbound, тело до 12 МиБ:

{
  "event_id": "in_0000000001",
  "raw_mime": "<base64 исходного MIME-письма>"
}

Раскодированный MIME не должен превышать 8 МиБ. Ответы:

  • 200 с {"created": true|false}: письмо принято; false означает дубль уже записанного event_id.
  • 404: адрес получателя не совпал ни с одним маршрутом. Повторять эту попытку стоит: маршрут может появиться, а безответная потеря входящей почты хуже лишних повторов. См. выше, «Письмо на неизвестный маршрут».
  • 400: конверт или MIME не разобрались.
  • 401: подпись не сошлась.
  • 413: тело запроса больше 12 МиБ.

Ни один из эндпоинтов не возвращает учётные данные провайдера, адреса получателей, которых не было в запросе, и локальную часть входящего маршрута. Ошибки трекинга и отписки отвечают 404, не сообщая, какая именно проверка не прошла.

Что делать, если

  1. Любой экран или запрос email отвечает 402: на вашем тарифе нет возможности email. Это не сбой настройки: домены отправки, входящие маршруты, рассылки и их статистика закрыты целиком, пока тариф не сменён на «Про», «Бизнес» или «Enterprise». Записи в DNS тут ни при чём.
  2. Ничего не отправляется, а на карточке домена предупреждение: домен отправки ещё не подтверждён. См. Email с вашего домена.
  3. «Рассылку пока нельзя запустить»: откройте проверку получателей и устраните все ошибки; одни предупреждения запуск не блокируют.
  4. Много получателей исключено по причине missing_timezone: рассылка идёт по местному времени, а у людей нет часового пояса. Переключитесь на время рассылки или заполните поле профиля.
  5. Время отправки не принимается или проверка отдаёт nonexistent_local_time: такого времени на часах в этот день не существует из-за перевода часов. Выберите другое время.
  6. Открытий подозрительно мало: такой результат ожидаем, точнее посчитать их нельзя. Сравнивайте рассылки по переходам.
  7. События провайдера не приходят: проверьте, что адаптер подписывает ровно сырое тело и что секрет вебхука совпадает; неподписанный callback получает 401.
  8. Провайдер жалуется на повторы входящих писем: адрес, на который пишут, не соответствует ни одному маршруту. Проверьте список маршрутов, а если недавно менялся секрет почтовых вебхуков, заведите маршруты заново.

Что дальше