Search by

skeeks / cms-communication-unisender

skeeks-semenov

Unisender Go mailing service driver for skeeks/cms-communication: sending through the API, delivery events by webhook

Package info

github.com/skeeks-cms/cms-communication-unisender

Homepage

Issues

Wiki

Type:yii2-extension

pkg:composer/skeeks/cms-communication-unisender

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

1.0.0 2026-10-30 12:18 UTC

This package is auto-updated.

Last update: 2026-10-30 12:23:33 UTC


README

Драйвер сервиса рассылок Unisender Go (https://go.unisender.ru) для skeeks/cms-communication. Письма кампании уходят через API Unisender Go по одному, каждое со своими метаданными; доставку, отказы, жалобы и отписки сервис сообщает вебхуком, и CRM записывает их к нужному письму. Всё общее (кампании, письмо, отписка, стоп-лист, события доставки, отчёт) — в cms-communication (README, разделы «Рассылки» и «События доставки»); здесь только протокол Unisender Go (сверено с https://godocs.unisender.ru/web-api-ref).

Через сервис пишем только своей базе с согласием на тему: Unisender Go запрещает базы без согласия, этого требует и 38-ФЗ. Холодные контакты — кампании «Ящики менеджеров».

Установка

composer require skeeks/cms-communication-unisender
php yii migrate

Пакет сам регистрирует драйвер unisender, канал кампании «Сервис рассылок (Unisender Go)», задачи comm.campaign.unisender и comm.unisender.apply (очередь communication), адрес вебхука POST /~unisender/<id подключения> и консольную команду unisender.

Как завести Unisender Go

  1. Зарегистрироваться на https://go.unisender.ru. Сервер аккаунта — в адресе личного кабинета: go1.unisender.ru или go2.unisender.ru.
  2. Настройки → Домены отправки → «+»: домен, с адресов которого пойдут письма, и поддомен ссылок. Лучше отдельный поддомен рассылок (так сделано для skeeks.com: news.skeeks.com, ссылки link.news.skeeks.com): жалобы и отказы рассылок не портят репутацию рабочей почты основного домена, а его SPF не трогается. Поддомен не должен быть занят записью CNAME (у skeeks.com mail — CNAME почты Яндекса, рядом с ним TXT не завести). Кабинет покажет DNS-записи, имя @ в них — сам поддомен:
    • SPF: TXT на поддомен v=spf1 include:spf.unisender.ru ~all (для самого домена — дописать include:spf.unisender.ru в существующую v=spf1);
    • DKIM: TXT с селектором из кабинета (у нас gokey._domainkey.news); ключ копировать целиком, без перепечатывания;
    • проверочная запись: TXT unisender-go-validate-hash=… на поддомен;
    • DMARC: CNAME _dmarc.<поддомен> из кабинета (без него поддомен берёт DMARC основного домена);
    • домен ссылок: три NS uns1/uns2/uns3.unisender.com. (или CNAME из кабинета). Он обязателен, даже если учёт переходов выключен: общий домен ссылок Unisender для аккаунта бывает запрещён, и тогда отправка отвечает «Custom backend domain or tracking domain required for sending». Активируется сам после того, как NS разойдутся: обычно за минуты–часы, по документации сервиса — до 48 часов. Через 30 минут — несколько часов нажать «Проверить» в кабинете: зелёные галочки — домен готов (DKIM-подпись включается в течение часа).
  3. Тариф: бесплатный отправляет до 100 писем в сутки и только на адреса своих подтверждённых доменов; на любые адреса — платный тариф.
  4. Написать в поддержку Unisender Go и попросить:
    • разрешить track_read = 0 и track_links = 0 (учёт открытий и переходов ведёт CRM, сервис не должен менять ссылки);
    • «динамическое отключение ссылки отписки» (skip_unsubscribe): тогда в письме только наша ссылка «Отписаться» и наш заголовок List-Unsubscribe. Сервис может попросить доп. соглашение. Аккаунту SkeekS поддержка 30.10.2026 сразу включила отключение учёта, а отключение отписки обещала после проверки писем — не раньше чем через 2 недели регулярных отправок (это ответ нашему аккаунту, у других условия могут отличаться). Пока не разрешили: в подключении выбрать «Нет» у «Учёт открытий и переходов у Unisender Go выключен», иначе письма не уйдут, и оставить «Нет» у «Своя ссылка отписки». Тогда наша ссылка «Отписаться» в рекламном письме уходит меткой сервиса {{UnsubscribeUrl}}: Unisender Go не добавляет свой блок в конец письма, ссылка ведёт на его страницу отписки, а CRM узнаёт об отписке по вебхуку. Для обычных писем (переписка, не рассылка) — настройка «Отписка в обычных письмах»: «Наша маленькая строка» (по умолчанию — серая «Отписаться от писем» с той же меткой), «Стандартный блок Unisender Go» или «Без отписки» — последнее только после разрешения поддержки, иначе письма не уйдут.
  5. Аккаунт → Безопасность → API-ключ (или ключ проекта в «Проектах»).

Подключение в CRM

«Настройки» → «Почтовые ящики» → «Добавить»:

  • «Адрес» — адрес отправителя на подтверждённом домене (например news@skeeks.com), «Имя отправителя» — как увидит клиент;
  • «Подключение к серверу» — «Сервис рассылок Unisender Go — только отправка»; «API-ключ» (хранится зашифрованным, в форму не возвращается, пустое поле при правке оставляет сохранённый), «Сервер API»;
  • «Ответы клиентов»: в рабочий ящик сотрудника, от чьего имени письмо, или на «Ответы направлять на» ящика (раздел «Дополнительно» — общий ящик, например info@skeeks.com);
  • «Писем в минуту» (по умолчанию 60) и «Писем в сутки» (0 — без ограничения);
  • «Доступ сотрудников»: кому можно отправлять с этого ящика.

«Проверить подключение» спрашивает system/info (аккаунт, отправлено за период по тарифу) и webhook/list (все страницы): засчитывается только вебхук https://…/~unisender/<id> именно этого подключения (и этого домена, когда проверка идёт из админки), с событиями доставки, отказов, жалоб и отписок.

Вебхук

Адрес — https://<сайт CRM>/~unisender/<id подключения>. Поставить его на боевом сайте CRM (ящик — адрес отправителя или id подключения):

php yii unisender/webhook news@skeeks.com

команда ставит события delivered, soft_bounced, hard_bounced, spam, unsubscribed, subscribed и блокировки, delivery_info = 1 (причины отказов), до 10 параллельных вызовов. Вручную в кабинете — те же события и «подробности доставки». Стенд вебхук не получит: статусы его писем — php yii unisender/events news@skeeks.com [часов] 1 (выгрузка событий через API).

Подпись: auth — MD5 тела, в котором значение auth заменено на API-ключ. Тело больше 4 МБ — 413: сначала по Content-Length, затем вход читается не дальше предела, сжатое тело распаковывается частями и тоже не больше 4 МБ; неверная подпись — 403. Принятый вызов записывается как есть (cms_comm_unisender_callback, один раз) и применяется задачей comm.unisender.apply: задача идёт порциями, пока есть вызовы, а повтор того же вызова будит её снова (если постановка задачи сорвалась). Не применённый вызов ждёт 5 минут и повторяется до 5 раз. Запуск, упавший вместе с процессом, задача повторяет (до 3 попыток), а агент comm.unisender.apply-all раз в 10 минут будит её для каждого подключения с необработанными вызовами — даже если новых вебхуков нет. После применения тело вызова очищается (в нём IP и устройство читателя), остаётся хэш против повторов. Откат миграции отказывается, пока есть не применённые вызовы (new или failed).

Событие относится к письму, если его job_id равен provider_ref письма (номера отправок уникальны в аккаунте сервиса). Письмо с неизвестным исходом отправки (provider_ref пуст) принимает событие только своей установки (sx_origin) и своего сайта (sx_site). sx_origin — случайный номер установки, записанный один раз в файл runtime/unisender-origin корня приложения (параметр unisenderOriginFile), а не в базу: у стенда с копией боевой базы свой номер. Событие чужой установки не трогает ни письма, ни стоп-листа.

Что делает драйвер

  • Каждое письмо — отдельный вызов email/send: получатели из To, CC и BCC с метаданными sx_message, sx_site, sx_origin, sx_campaign, sx_recipient, campaign_id (группировка в отчётах Unisender Go), видимые To и CC — заголовками, idempotence_key, файлы и картинки в тексте.
  • Шаблонизатор сервиса остаётся simple (с none сервис не подставляет свой заголовок Sender: «${_nameFrom}»). Чтобы он не тронул текст людей, {{ и }} в HTML уходят сущностями &#123;&#123; (читатель видит те же скобки), в тексте и теме — с невидимым пробелом нулевой ширины между скобками. Метка {{UnsubscribeUrl}} добавляется после этого.
  • Рекламное письмо (с темой) уходит только контактам с согласием, письмо кампании «Ящики менеджеров» — никогда. И наоборот: если ящик кампании сервиса после запуска переключили на другое подключение, её письма не уходят (канал и задача отправки проверяют это перед каждым письмом).
  • Ответы сервиса: адреса из failed_emails — событие письма (отписан, жаловался, недоступен → стоп-лист), в том числе при отказе всем получателям (ошибка 204), 429 — письмо ждёт в очереди, 5xx и обрыв связи — исход неизвестен, повторно не отправляется. «Отправлено» — только «сервис принял»; «Доставлено» — по событию вебхука.
  • Unisender Go даёт письму свой Message-ID: ответ клиента находит переписку по адресу и теме (MailIngestService).

Тесты

php tests/unisender.php — без сети и без базы сайта: запросы и ответы по документации, подпись вебхука, повторы, события, стоп-лист, канал кампании, выгрузка событий.