Транзакционная рассылка (для интеграторов)

Обновлено: Aug 31, 2026Раздел: Интеграции

Отправляйте по одному исходящему письму на получателя из интеграции FORM или CONTACT_FORM, используя SMTP этой интеграции (outboundMail). Вызов выполняется между серверами с X-API-Key и областью ``transactional.send``.

Это не SMTP-ретранслятор без сохранения состояния. Mailoo создаёт полный жизненный цикл отправки внутри интеграции: TransactionalSend, Message (OUTBOUND), опциональная синхронизация Subscriber, отслеживание открытий/кликов и опциональные вебхуки доставки. Подробнее об отличиях от экспорта SMTP-реквизитов см. outbound-smtp{.interpreted-text role="doc"}.

Связанные материалы: уровень SMTP --- outbound-smtp{.interpreted-text role="doc"}; токены отписки --- website-forms{.interpreted-text role="doc"}; OpenAPI --- https://api.mailoo.app/docs/v1.

Архитектура

  • Инициирование, а не ретрансляция: Ваш бэкенд вызывает Mailoo; Mailoo рендерит сообщение, сохраняет записи и отправляет через ``integration.config.outboundMail`` (тот же SMTP, что и для ответов из панели управления и приветственных писем).
  • Секреты: Используйте ``X-API-Key`` с ``transactional.send`` (или FULL) только с сервера или BFF --- никогда в браузерных сборках.
  • Идемпотентность: Каждый запрос требует ``idempotencyKey`` (макс. 256 символов, уникальный для интеграции). Первый успешный запрос возвращает 201; повторные --- 200 с idempotentReplay: true.
  • Подписчики: Mailoo создаёт или обновляет Subscriber для e-mail получателя. Если unsubscribedAt установлен, отправка пропускается (409, статус SKIPPED_UNSUBSCRIBED).
  • События доставки: Опциональные исходящие вебхуки (delivered, opened, clicked, unsubscribed, bounced) с HMAC-подписью и повторами --- см. Вебхуки доставки ниже.

Эндпоинт отправки

``POST {baseUrl}/api/v1/webhooks/transactional/{projectUid}/{integrationId}/send``

Заголовки: Content-Type: application/json, X-API-Key (область ``transactional.send`` или FULL)

Тело (JSON):

  • ``idempotencyKey`` (обязательно) --- стабильный ключ для этой логической отправки (например, daily-2026-06-20-user123)
  • ``to`` (обязательно) --- e-mail получателя
  • ``name`` (необязательно) --- отображаемое имя; используется для {{User.name}} / {{firstName}}
  • ``templateId`` (необязательно) --- id кампании (кампания панели управления на этой интеграции); используйте либо templateId, либо инлайн subject + text/html
  • ``vars`` (необязательно) --- объект строковых/числовых/булевых переменных Mustache (см. ниже)
  • ``subject``, ``text``, ``html`` (необязательно) --- инлайн-контент без templateId; для инлайн-отправки обязательны subject и хотя бы одно из text или html

Ответы:

  • 201 --- письмо отправлено (status: SENT, idempotentReplay: false)
  • 200 --- идемпотентный повтор предыдущей отправки
  • 409 --- получатель отписался (status: SKIPPED_UNSUBSCRIBED)
  • 502 --- ошибка SMTP-отправки (status: FAILED; Message и вебхук BOUNCED могут быть записаны)
  • 400 --- ошибка валидации
  • 403 --- у API-ключа отсутствует ``transactional.send``
  • 404 --- проект/интеграция не найдены или тип не FORM/CONTACT_FORM

Пример (инлайн):

curl -X POST "https://api.mailoo.app/api/v1/webhooks/transactional/{projectUid}/{integrationId}/send" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: mai_live_..." \
  -d '{
    "idempotencyKey": "daily-2026-06-20-user1",
    "to": "user@example.com",
    "name": "Jane Doe",
    "subject": "Hi {{firstName}}",
    "html": "<p>{{affirmationText}} <a href=\"{{writeUrl}}\">Write</a></p><p><a href=\"{{unsubLink}}\">Unsubscribe</a></p>",
    "vars": {
      "affirmationText": "You are enough.",
      "writeUrl": "https://app.example.com/write"
    }
  }'

Пример ответа (201):

{
  "success": true,
  "data": {
    "sendId": "clx...",
    "messageId": "clx...",
    "status": "SENT",
    "idempotentReplay": false
  }
}

Переменные Mustache

Шаблоны (templateId кампании или инлайн subject/text/html) рендерятся через Mustache перед SMTP-отправкой.

Встроенный контекст:

  • ``User.email``, ``User.name`` --- из to / name
  • ``firstName`` --- из vars.firstName или первый токен name
  • ``unsubLink`` --- URL для отписки в один клик (секрет подписи интеграции + API ``MAILOO_PUBLIC_APP_URL``)
  • ``affirmationText``, ``writeUrl``, ``streak`` --- из vars, когда указаны (часто используются в retention/nudge-потоках)

Дополнительные строковые/числовые/булевы ключи в vars включаются в контекст.

Отслеживание открытий и кликов

Если HTML-тело непустое, Mailoo внедряет:

  • Пиксель отслеживания открытий 1×1
  • Перезаписанные https:////) ссылки через редиректы отслеживания кликов

Публичные маршруты (без API-ключа):

  • ``GET /api/v1/public/transactional/open/{trackingToken}`` --- возвращает прозрачный GIF; фиксирует первое открытие
  • ``GET /api/v1/public/transactional/click/{trackingToken}?u={urlencodedTarget}`` --- фиксирует клик, 302 редирект на целевой URL

Установите ``MAILOO_PUBLIC_API_URL`` на хосте API, чтобы URL пикселей и кликов указывали на ваш публичный API. Установите ``MAILOO_PUBLIC_APP_URL``, когда ссылки отписки и приложения должны указывать на домен панели управления.

Вебхуки доставки

При настройке Mailoo отправляет JSON-события POST-запросом на ваш эндпоинт уведомлений.

Настройка (на уровне интеграции):

integration.config.deliveryWebhook.url и .secret --- задаются в панели управления (Вебхуки доставки на вкладке Setup интеграции) или через PATCH …/integrations/{id} с deliveryWebhook.

События: delivered (после успешного SMTP), opened, clicked, unsubscribed (после вебхука отписки), bounced (ошибка SMTP).

Формат тела (JSON):

{
  "event": "delivered",
  "integrationId": "...",
  "messageId": "...",
  "idempotencyKey": "...",
  "recipientEmail": "user@example.com",
  "timestamp": "2026-06-20T12:00:00.000Z",
  "metadata": {}
}

Подпись: Заголовок ``X-Mailoo-Signature: t={unixSeconds},v1={hex}``, где v1 --- HMAC-SHA256 строки "{timestamp}.{rawBody}" с использованием секрета вебхука. Заголовок ``X-Mailoo-Event`` дублирует имя перечисления (например, DELIVERED).

Повторы: Воркер очереди (интервал 10 с в процессе API) повторяет неудачные доставки до 8 раз с экспоненциальной задержкой (максимум 5 минут). Установите ``DISABLE_DELIVERY_WEBHOOK_WORKER=1`` только для тестов или при использовании отдельного процессора.

Предварительные требования

  • Интеграция FORM или CONTACT_FORM со статусом ACTIVE
  • Настроенный ``outboundMail`` (панель управления → Подключение и настройки → Исходящая почта)
  • ``MAIL_SMTP_ENCRYPTION_KEY`` на API при хранении зашифрованного SMTP-пароля или секрета отписки
  • API-ключ RESTRICTED или FULL с ``transactional.send``

Подпись отписки

Каждая интеграция FORM/CONTACT_FORM хранит зашифрованный HMAC-секрет отписки в integration.config. Mailoo автоматически генерирует {{unsubLink}} в транзакционных шаблонах. Владельцы могут ротировать секрет в панели управления (это инвалидирует ссылки в уже отправленных письмах). Внешние бэкенды, подписывающие собственные ссылки, должны один раз получить ротированный открытый текст или вызывать ``POST /api/v1/webhooks/unsubscribe`` с API-ключом.