Новым пользователямБесплатные тарифы DNS и CDN для каждого нового аккаунта.Создать аккаунт

События и вебхуки

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

5 мин на чтение Обновлено 20 окт. 2026 г.

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

Статусы писем

У каждой копии для отдельного получателя один статус. Статус меняется только вперёд: например, доставленное письмо ещё может перейти в статус «отказ» или «жалоба», но никогда не вернётся в статус «в очереди».

СтатусМетка в консолиЗначение
queuedВ очередиПринято и ожидает доставки
deferredОтложеноПринимающий сервер вернул временную ошибку. Доставка повторяется в течение до 72 часов.
deliveredДоставленоПринимающий сервер принял письмо
bouncedОтказДоставка окончательно не удалась — во время доставки или по отчёту об отказе, полученному позже. См. типы отказов ниже.
complainedЖалобыПолучатель отметил письмо как спам
rejectedОтклоненоОтклонено до отправки, например потому что получатель в списке подавления, не разрешён в песочнице или содержимое было отклонено
failedОшибкаПисьмо не удалось доставить после 72 часов повторных попыток или не удалось поставить в очередь

Открытия, клики и отписки не являются статусами. Они записываются в письме (opened_at, clicked_at, unsubscribed_at) и отправляются как события вебхука. В журнале отправки у открытого письма есть дополнительная метка Открыто.

Типы отказов

ТипКогдаПоследствие
ЖёсткийПостоянный отказ 5xx, например неизвестный пользовательАдрес добавляется в глобальный список подавления
МягкийПереполненный ящик (x.2.2) или отказ по системным, сетевым причинам либо из-за политики (x.3.x–x.7.x, например блокировка по репутации IP)Адрес не добавляется в список подавления

Журнал отправки

На вкладке Журнал отправки потока перечислены письма за последние 30 дней с указанием времени, получателя, темы, категории, источника (API или SMTP) и статуса. Можно фильтровать по Получатель, Состояние, Источник, Категория и диапазону дат.

Нажмите на письмо, чтобы открыть Сведения о письме: статус, отправитель, тема, категория, теги, последний ответ принимающего сервера и список событий с кодом SMTP, ответом, типом отказа, MX-хостом и IP каждой попытки доставки.

Вкладка Обзор суммирует те же данные за 7 или 30 дней: отправлено, доля доставки, доля отказов, доля жалоб, открытия и клики.

Вебхуки

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

Настройка вебхука

  1. Откройте поток и перейдите на вкладку Webhook.
  2. В поле URL получателя введите URL https://, доступный из публичного интернета. Частные и локальные адреса не принимаются.
  3. В разделе События выберите нужные события. По умолчанию выбраны все события.
  4. Нажмите Сохранить. При первом сохранении URL один раз отображается Секрет подписи. Он начинается с whsec_. Сохраните его на своём сервере.
  5. Нажмите Отправить тест, чтобы отправить событие test и проверить, что ваш эндпоинт отвечает.

Чтобы получить новый секрет, нажмите Сбросить секрет подписи. Старый секрет сразу перестаёт действовать. Чтобы перестать получать события, очистите URL и сохраните.

События

СобытиеМетка в консолиКогда отправляется
deliveredДоставленоПринимающий сервер принял письмо
deferredЗадержка (tarpit)Попытка доставки временно не удалась. Отправляется один раз на каждую попытку.
bouncedОтказОкончательная неудача. data.bounce_type равно hard или soft.
complainedЖалобыПолучатель пожаловался на письмо как на спам
failedОшибкаДоставка прекращена через 72 часа
rejectedОтклонитьСервер отправки отклонил получателя
openedОткрытьПисьмо открыто впервые (требуется отслеживание открытий)
clickedКликиКаждый клик по отслеживаемой ссылке (требуется отслеживание кликов)
unsubscribedОтпискаПолучатель отписался

Получатели, отклонённые самим HTTP API, возвращаются в поле rejected ответа API и не порождают вебхук.

Формат запроса

Каждое событие отправляется как POST с телом JSON:

http
POST /your/webhook HTTP/1.1
Content-Type: application/json
User-Agent: Yeap-TM-Webhook/1
X-Yeap-Signature: t=1760955304,v1=5f2b9c...e81a

{
  "id": "evt_01JAQ40B2C3D4E5F6G7H8J9K0M",
  "type": "bounced",
  "stream_id": 12,
  "message_id": "01JAQ3Z9V8K4M2N6P7R5S1T0XW",
  "created_at": "2026-10-20T10:15:04+00:00",
  "data": {
    "rcpt": "alice@example.org",
    "smtp_code": 550,
    "smtp_response": "5.1.1 The email account that you tried to reach does not exist",
    "bounce_type": "hard",
    "mx": "mx.example.org"
  }
}

id уникален для каждого события: используйте его, чтобы отбрасывать дубликаты. Содержимое data зависит от события:

СобытиеПоля data
delivered, deferred, bounced, complained, failed, rejectedrcpt, а также при наличии smtp_code, smtp_response, bounce_type, mx, at
openedrcpt, ip, user_agent
clickedrcpt, url, ip, user_agent
unsubscribedrcpt, category, via
testmessage

Проверка подписи

Заголовок X-Yeap-Signature имеет вид t=<timestamp>,v1=<signature>. Подпись — это HMAC-SHA256 в шестнадцатеричном виде от <timestamp>.<raw request body>, где ключом служит полный секрет подписи (включая whsec_). Чтобы проверить запрос:

  1. Прочитайте необработанное тело точно в том виде, в каком оно получено, до разбора JSON.
  2. Вычислите HMAC от t + "." + body и сравните его с v1 с помощью сравнения за постоянное время.
  3. Отклоняйте запросы, метка времени которых старше 5 минут, чтобы блокировать повторное воспроизведение.

Python:

python
import hashlib, hmac, time

def verify(secret: str, header: str, body: bytes, tolerance: int = 300) -> bool:
    parts = dict(p.split("=", 1) for p in header.split(","))
    ts, sig = parts.get("t", ""), parts.get("v1", "")
    if not ts.isdigit() or abs(time.time() - int(ts)) > tolerance:
        return False
    expected = hmac.new(secret.encode(), ts.encode() + b"." + body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, sig)

Node.js:

javascript
const crypto = require('crypto');

function verify(secret, header, rawBody, tolerance = 300) {
  const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')));
  const ts = Number(parts.t);
  if (!ts || Math.abs(Date.now() / 1000 - ts) > tolerance) return false;
  const expected = crypto.createHmac('sha256', secret).update(`${parts.t}.${rawBody}`).digest('hex');
  const a = Buffer.from(expected);
  const b = Buffer.from(parts.v1 || '');
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

Ответы и повторные попытки

  • Отвечайте любым статусом 2xx в течение 10 секунд. Всё остальное считается неудачей.
  • Неудачные доставки повторяются с увеличивающимися интервалами: от 1 минуты до не более 4 часов между попытками. Повторные попытки прекращаются через 24 часа после события.
  • События могут приходить более одного раза или не по порядку. Используйте id события, чтобы пропускать дубликаты, а статус письма — чтобы определить актуальное состояние.

Таблица Последние доставки на вкладке Webhook показывает последние 100 доставок с событием, статусом (В очереди ожидает, Успешно успешно, Повтор повтор, Прекращено прекращено), количеством попыток, последней ошибкой и временем следующей попытки.

См. также

Была ли эта страница полезна?