Перейти к основному содержимому
Опубликовано: 

Отправка писем через Stream API

Stream API (Потоковое API) — специализированный интерфейс для отправки больших объёмов писем по одному в одном запросе. Подходит для систем, которые генерируют письма поштучно и не могут заранее сформировать полный список получателей.

Когда использовать Stream API

  • Ваша система формирует письма по одному (например, поштучная генерация из CRM).
  • Если вам требуется отправлять более 10 писем в секунду на постоянной основе.
  • Вы отправляете одновременно и транзакционные, и массовые письма потоком.
Альтернативы в Sendsay API
  • Для массовых рассылок с готовым списком получателей быстрее и удобнее использовать экспресс-выпуск (issue.send с users.list).

  • Для транзакционных писем, где не важна максимальная скорость, подойдёт персональный выпуск (issue.send с group: "personal"). Для него доступны почти все настройки Sendsay API issue.send (ленты новостей, расширенная персонализация и другие).

Требования для отправки

  • API-ключ.
  • Доступ к Stream API — для подключения .
  • Черновик письма или содержимое письма, передаваемое прямо в запросе.

Адрес API

Вызовы Stream API отправляются методом POST на:

https://trapi.sendsay.ru/tranz/api/v2/account/json/issue.send/personal

Где account — код вашего аккаунта.

Важно

Требования к соединению:

  • Транспорт: HTTP 1.0/1.1 over TLSv1.2.
  • Content-Type: application/json.
  • Максимальный размер запроса: 25 МБ.
  • Для лучшей пропускной способности используйте Keep-Alive.
  • Хост trapi.sendsay.ru имеет несколько IP-адресов — при недоступности одного переключайтесь на другой.

Авторизация

По API-ключу

В теле запроса:

{
"apikey": "ваш-api-ключ",
...
}

Или в HTTP-заголовке:

Authorization: sendsay apikey=url-кодированный-ключ

По JWT-токену

В теле запроса:

{
"apikey": "jwt:ваш-токен",
...
}

Или в HTTP-заголовке:

Authorization: sendsay apikey=jwt:url-кодированный-токен

Для настройки JWT .

Отправка одного письма

С черновиком

{
"apikey": "ваш-api-ключ",
"action": "issue.send",
"group": "personal",
"email": "test@test.com",
"uuid": "order-confirm-20260217-001",
"letter": {
"draft.id": "order_confirmation"
},
"extra": {
"anketa": {
"order_id": "A-12345",
"total": "4 500 ₽"
}
}
}

Без черновика

{
"apikey": "ваш-api-ключ",
"action": "issue.send",
"group": "personal",
"email": "test@test.com",
"uuid": "welcome-20260217-002",
"letter": {
"subject": "Добро пожаловать!",
"from.name": "Мой магазин",
"from.email": "info@myshop.ru",
"message": {
"html": "<h1>Добро пожаловать!</h1><p>Рады видеть вас.</p>",
"text": "Добро пожаловать! Рады видеть вас."
}
}
}

Параметры запроса

ПараметрОбязательныйОписание
actionВсегда issue.send
groupВсегда personal
emailАдрес получателя
uuidУникальный идентификатор письма (до 240 символов, A-Za-z0-9=_-). Если не указан — назначается автоматически. Используется для идентификации в статистике. В callback передаётся как gate.uniq. Хранится 30 дней
letter.draft.idID или алиас черновика
letter.subjectТема письма (обязательно, если нет черновика)
letter.from.emailАдрес отправителя (обязательно, если нет черновика)
letter.from.nameИмя отправителя
letter.reply.emailАдрес для ответов
letter.to.nameИмя получателя
letter.message.htmlHTML-версия
letter.message.textТекстовая версия
letter.message.ampAMP-версия
letter.attachesМассив прикреплённых файлов
extra.anketaДанные персонализации конкретного получателя. В Stream API индивидуальные данные передаются именно в extra.anketa (в отличие от основного API, где anketa подтягивается из базы автоматически)
labelМетка или массив меток (до 3 штук, до 32 байт) для группировки в статистике
dkim.idDKIM-ключ для подписи
customer.idВаш внутренний ID получателя (до 255 байт). В callback — customer.id
ttlВремя попыток доставки в секундах (по умолчанию — 4 дня)
relink1 — отслеживать клики, 0 — нет (по умолчанию — 0)
weak_draft1 — параметры запроса приоритетнее черновика
care_varsМассив обязательных переменных персонализации
ignore_stoplist1 — отправить, даже если адрес в стоп-листе (дополнительная функция, для подключения )
email.fakeПодменный адрес для статистики (реальный адрес не сохраняется в системе)
lbac.idID политики доступа LBAC
Важно

Должна быть заполнена хотя бы одна версия — HTML или text.

Ответ

Успешный ответ:

{
"uuid": "order-confirm-20260217-001"
}

Ответ с ошибкой:

{
"errors": [
{
"id": "wrong_email",
"explain": "invalid email format"
}
]
}

Персонализация — отличие от основного API

В Stream API индивидуальные данные получателя передаются в extra.anketa. Это ключевое отличие от Sendsay API, где anketa — зарезервированное имя, и данные контакта подтягиваются автоматически из базы.

{
"extra": {
"anketa": {
"name": "Анна",
"order_id": "A-12345",
"total": "4 500 ₽"
}
}
}

В шаблоне черновика обращение остаётся одинаковым:

[% anketa.name %],
[% anketa.order_id %]

В Stream API не работают функции шаблонизатора:

  • countup,
  • countdown,
  • draw_graph,
  • lenta_get,
  • geturl.

Прикреплённые файлы

{
"letter": {
"attaches": [
{
"name": "invoice.pdf",
"content": "JVBERi0xLjQK...",
"encoding": "base64"
},
{
"name": "readme.txt",
"content": "Текстовый файл в UTF-8"
}
]
}
}

Для двоичных файлов используйте encoding: "base64". Для текстовых файлов кодирование не обязательно — содержимое передаётся как есть.

Отправка нескольких писем (batch)

Если ваша система накапливает письма небольшими группами, можно отправить 50–100 писем за один HTTP-вызов.

Адрес:

POST https://trapi.sendsay.ru/tranz/api/v2/account/json.batch/issue.send/personal

Запрос

{
"apikey": "ваш-api-ключ",
"action": "batch",
"do": [
{
"action": "issue.send",
"group": "personal",
"email": "user1@test.com",
"uuid": "batch-001",
"letter": { "draft.id": "welcome" }
},
{
"action": "issue.send",
"group": "personal",
"email": "user2@test.com",
"uuid": "batch-002",
"letter": { "draft.id": "welcome" }
}
]
}

API-ключ указывается один раз на уровне всего запроса, а не в каждом задании.

Ответ

{
"result": [{ "uuid": "batch-001" }, { "uuid": "batch-002" }]
}

Ошибка одного задания не влияет на остальные — каждое обрабатывается независимо.

Отложенная отправка

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

Время можно передать в URL с адресом:

POST https://trapi.sendsay.ru/tranz/api/v2/account/json/issue.send/personal/later/2026-03-01T10:00

или в теле запроса:

{
"later.time": "2026-03-01 10:00",
...
}

Указывайте московское время, или используйте суффикс Z для UTC. Допустимые форматы:

  • YYYY-MM-DDThh:mm
  • YYYY-MM-DD hh:mm

Дополнительно можете указать секунды. Время приводится к ближайшему меньшему значению, кратному 5 минутам (например: 12:0312:00, 12:0912:05).

Важно

Черновик и API-ключ (или JWT-токен) должны быть валидны на момент отправки, а не на момент передачи письма.

Группировка писем в выпуски

Письма в Stream API автоматически группируются в выпуски для статистики:

  • С черновиком — группировка по номеру черновика + dkim.id. Название черновика = название выпуска.

  • Без черновика — группировка по меткам (label) + dkim.id. Метки через пробел = название выпуска.

  • Дополнительно учитываются: день, саблогин, наличие AMP-версии, номер LBAC.

    Важно

    Если вы одновременно отправляете через Stream API массовые и транзакционные письма, массовые могут замедлять транзакционные. Для настройки разделения .

Коды ошибок

Ошибки, возвращаемые сразу

КодОписание
cant_decodeНевалидный JSON или не объект
wrong_letterletter не является объектом
wrong_uuidUUID длиннее 255 символов или содержит недопустимые символы
wrong_apikeyПустой API-ключ
wrong_credentialsОшибка в заголовке Authorization
internal_writeВнутренние проблемы

Ошибки, возвращаемые после обработки

Код ESMTPОписание
5.0.0Адрес имеет постоянные ошибки доставки или в стоп-листе
6.6.5 wrong_emailОшибка в адресе получателя
6.6.5 wrong_letter.*Ошибка в параметрах письма
6.7.0Исчерпан месячный лимит писем
6.7.8 gate is disabledStream API не подключено
6.7.8 authorization failedНевалидный API-ключ
6.7.8 error/account/blockedАккаунт заблокирован
6.7.8 error/sender/unknownНеизвестный адрес отправителя
6.7.8 error/sender/prohibitedНедопустимый адрес отправителя
6.7.8 error/issue/blockedВыпуски заблокированы
6.7.8 error/issue/blocked_personalТранзакционные выпуски заблокированы
6.7.8 unknown_draftНеизвестный черновик

Получение статистики

Статистику по выпускам через Stream API можно посмотреть:

  • в разделе Статистика личного кабинета.
  • используя метод stat.uni Sendsay API.
  • через колбеки — Sendsay может отправлять уведомления о событиях доставки (доставлено, открыто, клик, ошибка и др.) на ваш URL по мере их возникновения.

Особенности отправки через Stream API

  • Скорость приёма запросов зависит от индивидуальных настроек аккаунта.
  • При успешной обработке HTTP-код ответа всегда 200. Ошибки API передаются в errors, а не в HTTP-статусах.
  • При получении кода 502, 503, 504 или таймаута — повторите запрос.
  • Ошибка rate_limit указывает на превышение лимита коннектов.
  • Назначайте uuid самостоятельно для надёжной идентификации писем в статистике. Если у вас нет возможности создать уникальный uuid, не указывайте его, и система назначит его автоматически.
  • relink по умолчанию 0. Измените эту настройку, если вам нужно отслеживание кликов.