/ Email API / справочник Swagger UIopenapi.yamlвойти

Email API MailerMail

Транзакционные и массовые письма из вашего кода плюс верификация адресов. Все запросы — JSON поверх HTTPS, ответы — JSON.

Базовый адрес всех методов:

https://mailermail.ru/api/v1

Контракт построен на привычной модели транзакционных Email API (from/to/subject/html/text/attachments) — миграция с типового провайдера сводится к смене хоста и токена. Машиночитаемая спецификация — openapi.yaml (OpenAPI 3.0), интерактивная версия — Swagger UI.

Проверка доступности

Метод GET /health не требует токена и отвечает {"ok":true} — удобно для мониторинга.

Health
curl https://mailermail.ru/api/v1/health
$body = file_get_contents(
  'https://mailermail.ru/api/v1/health'
);
Ответ200
{
  "ok": true,
  "ts": "2026-08-03T12:00:00+03:00"
}

Аутентификация

Все методы, кроме /health и /unsubscribe, требуют токен. Передайте его в одном из заголовков:

  • Api-Token: mm_live_…
  • Authorization: Bearer mm_live_…

Токены выпускаются в кабинете (Настройки → API). Каждый токен несёт scope:

  • verify — методы верификации (/verify, /verify/batch);
  • send — всё остальное (отправка, шаблоны, стоп-лист, логи).

Нет нужного scope → 403.

Sandbox-режим

Токены с префиксом mm_test_ — тестовые: /send и /batch проходят весь конвейер (валидацию, проверку стоп-листа, запись в лог с пометкой sandbox), но письма физически не отправляются. Ответ содержит "sandbox": true.

Заголовок токена
curl https://mailermail.ru/api/v1/stats \
  -H "Api-Token: mm_live_9f3k…"
$ch = curl_init('https://mailermail.ru/api/v1/stats');
curl_setopt_array($ch, [
  CURLOPT_HTTPHEADER => ['Api-Token: mm_live_9f3k…'],
  CURLOPT_RETURNTRANSFER => true,
]);
$res = json_decode(curl_exec($ch), true);

Ошибки

Успех — HTTP 2xx и "success": true. Ошибка — соответствующий код и тело {"success": false, "errors": ["…"]}. Массив errors содержит человекочитаемые сообщения.

КодЗначение
200Запрос обработан. Для /send частичные неудачи по получателям — в skipped/failed, код всё равно 200.
400Некорректное тело (не JSON-объект).
401Токен отсутствует, некорректен, неизвестен или отозван.
403У токена нет нужного scope.
404Ресурс не найден (эндпоинт, шаблон, сообщение).
409Конфликт Idempotency-Key: такой ключ уже выполняется или использован для другого метода.
413Тело или вложения превышают лимит.
422Ошибка валидации полей.
429Превышен лимит запросов. Заголовок Retry-After — секунд до сброса.
502Полный провал отправки (инфраструктура) — ретрай уместен.
503БД недоступна или часть API ещё не развёрнута.
Ответ422 Unprocessable
{
  "success": false,
  "errors": [
    "Field 'to' (non-empty array) is required."
  ]
}

Лимиты запросов

На каждый токен — 120 запросов в минуту. При превышении метод отвечает 429 с заголовком Retry-After (секунд до конца текущего минутного окна).

Отдельные лимиты содержимого:

  • /send — до 50 получателей, вложения ≤10 МБ суммарно, тело ≤15 МБ;
  • /batch — до 500 request'ов, до 1000 писем суммарно;
  • /verify/batch — до 100 адресов.
Ответ429 Too Many Requests
{
  "success": false,
  "errors": [
    "Rate limit exceeded: 120 requests/minute."
  ]
}

Идемпотентность

Методы /send и /batch принимают заголовок Idempotency-Key (произвольная строка ≤200 символов). Это защищает от двойной отправки при сетевых ретраях.

  • Повтор с тем же ключом в течение 24 часов возвращает первый сохранённый ответ с заголовком Idempotency-Replayed: true.
  • Если первый запрос ещё выполняется — параллельный дубль получает 409.
  • Ответы 5xx не кэшируются: ретрай с тем же ключом действительно повторит отправку.
Заголовок
curl -X POST https://mailermail.ru/api/v1/send \
  -H "Api-Token: mm_live_9f3k…" \
  -H "Idempotency-Key: order-4211-confirm" \
  -H "Content-Type: application/json" \
  -d '{ … }'
$headers = [
  'Api-Token: mm_live_9f3k…',
  'Idempotency-Key: order-4211-confirm',
  'Content-Type: application/json',
];

Отправка письма

POSThttps://mailermail.ru/api/v1/send

Синхронная транзакционная отправка: письмо уходит за секунды, у каждого получателя — свой Message-ID. Требует scope send. Домен отправителя должен быть подтверждён в аккаунте (иначе 422) — он же даёт DKIM-подпись.

Задайте subject + html и/или text, либо template_uuid (тогда тему и тело берёт шаблон — они взаимоисключимы). Переменные {{var}} подставляются из template_variables и to[].substitutions.

Поля тела

ПолеТипОбяз.Описание
fromobjectдаОтправитель: {email, name?}. Домен — verified.
toarrayдаПолучатели {email, name?, substitutions?}, ≤50.
reply_toobjectнетАдрес для ответа {email, name?}.
subjectstringТема, ≤255. Обязательна без template_uuid.
htmlstringHTML-тело. Нужно html и/или text.
textstringТекстовое тело. Если не задано — генерируется из HTML.
categorystringнетМетка для группировки в статистике, ≤255.
attachmentsarrayнет{content(base64), filename, type?, disposition?, content_id?}, ≤10 МБ суммарно.
template_uuidstringнетUUID шаблона (взаимоисключим с subject/html/text).
template_variablesobjectнетГлобальные переменные {{var}} (скаляры).
optionsobjectнетlist_unsubscribe (bool), unsubscribe_url (https).
Запрос
curl -X POST https://mailermail.ru/api/v1/send \
  -H "Api-Token: mm_live_9f3k…" \
  -H "Content-Type: application/json" \
  -d '{
    "from": {"email": "no-reply@shop.ru", "name": "Shop"},
    "to": [{"email": "ivan@example.ru"}],
    "subject": "Заказ №4211 собран",
    "html": "<h1>Спасибо за заказ!</h1>"
  }'
$ch = curl_init('https://mailermail.ru/api/v1/send');
curl_setopt_array($ch, [
  CURLOPT_POST => true,
  CURLOPT_HTTPHEADER => [
    'Api-Token: mm_live_9f3k…',
    'Content-Type: application/json',
  ],
  CURLOPT_POSTFIELDS => json_encode([
    'from' => ['email' => 'no-reply@shop.ru', 'name' => 'Shop'],
    'to'   => [['email' => 'ivan@example.ru']],
    'subject' => 'Заказ №4211 собран',
    'html' => '<h1>Спасибо за заказ!</h1>',
  ]),
  CURLOPT_RETURNTRANSFER => true,
]);
$res = json_decode(curl_exec($ch), true);
Ответ200
{
  "success": true,
  "message_ids": ["a1b2c3d4-…"]
}
Ответ200 частично
{
  "success": true,
  "message_ids": [],
  "skipped": [
    {"email": "old@dead.ru", "reason": "known_bounce"}
  ]
}

Массовая отправка

POSThttps://mailermail.ru/api/v1/batch

Постановка партии писем в очередь: message_ids выдаются сразу, реально отправляет фоновый воркер (латентность до ~5 минут). Объект base задаёт общие поля, поля каждого request их перекрывают. Вложения не поддерживаются — используйте /send.

HTTP всегда 200 (кроме структурных ошибок тела): пер-письмо статусы — в массиве responses[] в порядке requests.

Поля тела

ПолеТипОбяз.Описание
baseobjectнетОбщие поля письма (как в /send, без attachments).
requestsarrayдаМассив писем (поля /send), ≤500; суммарно ≤1000 писем.
options.send_atstringнетОтложить: YYYY-MM-DD HH:MM:SS UTC, окно ≤72 ч.
options.skip_unsubscribeboolнетОтключить List-Unsubscribe (в bulk он включён по умолчанию).
Запрос
curl -X POST https://mailermail.ru/api/v1/batch \
  -H "Api-Token: mm_live_9f3k…" \
  -H "Content-Type: application/json" \
  -d '{
    "base": {
      "from": {"email": "news@shop.ru"},
      "subject": "Скидки недели",
      "html": "<p>Привет, {{name}}!</p>"
    },
    "requests": [
      {"to": [{"email": "a@ex.ru", "substitutions": {"name": "Анна"}}]},
      {"to": [{"email": "b@ex.ru", "substitutions": {"name": "Борис"}}]}
    ]
  }'
$payload = [
  'base' => [
    'from' => ['email' => 'news@shop.ru'],
    'subject' => 'Скидки недели',
    'html' => '<p>Привет, {{name}}!</p>',
  ],
  'requests' => [
    ['to' => [['email' => 'a@ex.ru', 'substitutions' => ['name' => 'Анна']]]],
    ['to' => [['email' => 'b@ex.ru', 'substitutions' => ['name' => 'Борис']]]],
  ],
];
Ответ200
{
  "success": true,
  "responses": [
    {"success": true, "message_ids": ["…"]},
    {"success": true, "message_ids": ["…"]}
  ]
}

Верификация адресов

POSThttps://mailermail.ru/api/v1/verify
POSThttps://mailermail.ru/api/v1/verify/batch

Проверка адреса без отправки письма: синтаксис, MX/A домена, ролевые и одноразовые адреса, глобальный реестр недоставляемых, подсказка опечаток. Требует scope verify. Пакетом — до 100 адресов.

Поле тела

ПолеТипОбяз.Описание
emailstringдаОдин адрес (для /verify).
emailsarrayдаМассив адресов ≤100 (для /verify/batch).

Статусы результата

deliverableДомен принимает почту, признаков риска нет.
riskyРолевой/одноразовый адрес либо вероятная опечатка домена.
undeliverableСинтаксис неверен, домен мёртв или адрес в реестре отказов.
unknownДомен не удалось проверить (временно).
Запрос
curl -X POST https://mailermail.ru/api/v1/verify \
  -H "Api-Token: mm_live_9f3k…" \
  -H "Content-Type: application/json" \
  -d '{"email": "ivan@example.ru"}'
$payload = ['email' => 'ivan@example.ru'];
// POST на /api/v1/verify с заголовком Api-Token
Ответ200
{
  "success": true,
  "email": "ivan@example.ru",
  "status": "deliverable",
  "checks": {
    "syntax": true,
    "domain": "ok",
    "role": false,
    "disposable": false,
    "known_bounce": false,
    "did_you_mean": null
  }
}

Шаблоны

GET/templates
POST/templates
GETPATCHDELETE/templates/{uuid}

Хранимые шаблоны письма с переменными {{var}} в теме и теле. При отправке подставляются через template_uuid + template_variables/substitutions. Требует scope send. Лимит — 1000 шаблонов на аккаунт.

Поля создания / обновления

ПолеТипОбяз.Описание
namestringдаНазвание, ≤128. Обязательно при создании.
subjectstringнетТема (с {{var}}), ≤255.
htmlstringHTML-тело, ≤2 МБ. Нужно html и/или text.
textstringТекстовое тело, ≤2 МБ.
categorystringнетМетка по умолчанию, ≤255.

GET /templates принимает ?limit= (≤100) и ?offset=. GET /templates/{uuid} возвращает шаблон целиком (с html/text). PATCH обновляет любое подмножество полей; после патча обязано остаться хотя бы одно тело. DELETE удаляет.

Создание
curl -X POST https://mailermail.ru/api/v1/templates \
  -H "Api-Token: mm_live_9f3k…" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Подтверждение заказа",
    "subject": "Заказ №{{order}} принят",
    "html": "<p>{{name}}, спасибо!</p>"
  }'
$payload = [
  'name' => 'Подтверждение заказа',
  'subject' => 'Заказ №{{order}} принят',
  'html' => '<p>{{name}}, спасибо!</p>',
];
Ответ201
{
  "success": true,
  "template": {
    "uuid": "7c9e6a…",
    "name": "Подтверждение заказа",
    "subject": "Заказ №{{order}} принят",
    "category": ""
  }
}
Удаление
curl -X DELETE \
  https://mailermail.ru/api/v1/templates/7c9e6a… \
  -H "Api-Token: mm_live_9f3k…"
// DELETE /api/v1/templates/{uuid}
// с заголовком Api-Token

Стоп-лист (suppressions)

GET/suppressions
POSTDELETE/suppressions

Адреса, на которые сервис не отправит письмо. Пополняется автоматически (жёсткие отказы, жалобы, отписки) и вручную через API. Требует scope send.

  • GET /suppressions — список (?limit= ≤1000, ?offset=, ?reason=). С ?email= — точечная проверка одного адреса.
  • POST — добавить {emails:[…≤1000], reason?}.
  • DELETE — убрать (снять блокировку) {emails:[…≤1000]}.

Причины (reason)

manualДобавлен вручную (по умолчанию при POST).
hard_bounceЖёсткий отказ (ящик не существует).
complaintЖалоба на спам (FBL).
unsubscribedОтписка через List-Unsubscribe.
Добавление
curl -X POST https://mailermail.ru/api/v1/suppressions \
  -H "Api-Token: mm_live_9f3k…" \
  -H "Content-Type: application/json" \
  -d '{"emails": ["a@ex.ru", "b@ex.ru"], "reason": "manual"}'
$payload = [
  'emails' => ['a@ex.ru', 'b@ex.ru'],
  'reason' => 'manual',
];
Ответ200
{
  "success": true,
  "added": 2,
  "reason": "manual"
}
Ответ200 проверка ?email=
{
  "success": true,
  "email": "a@ex.ru",
  "suppressed": true,
  "reason": "hard_bounce"
}

Логи и статистика

GET/messages
GET/messages/{uuid}
GET/stats

Лог отправок хранится 30 дней. Требует scope send.

Фильтры GET /messages

ПолеТипОбяз.Описание
limit / offsetintнетПагинация (limit ≤200, по умолч. 50).
statusenumнетsent · sandbox · skipped · failed · queued.
categorystringнетФильтр по метке.
emailstringнетФильтр по получателю.
from / tostringнетYYYY-MM-DD или с временем.

GET /messages/{uuid} возвращает одно сообщение, а для писем из /batch — ещё и состояние очереди (попытки, время отправки). GET /stats?days=7|30 отдаёт агрегаты по статусам, дням и категориям + суммарный объём проверок и отправок.

Лог
curl "https://mailermail.ru/api/v1/messages?status=sent&limit=20" \
  -H "Api-Token: mm_live_9f3k…"
$url = 'https://mailermail.ru/api/v1/messages'
     . '?status=sent&limit=20';
// GET с заголовком Api-Token
Ответ200
{
  "success": true,
  "total": 128,
  "messages": [
    {
      "message_id": "a1b2c3-…",
      "to": "ivan@example.ru",
      "from": "no-reply@shop.ru",
      "subject": "Заказ №4211 собран",
      "status": "sent",
      "created_at": "2026-08-03 12:00:01"
    }
  ]
}
Статистика
curl "https://mailermail.ru/api/v1/stats?days=30" \
  -H "Api-Token: mm_live_9f3k…"
$url = 'https://mailermail.ru/api/v1/stats?days=30';

Отписка

GETPOSThttps://mailermail.ru/api/v1/unsubscribe

Публичный endpoint по стандарту RFC 8058 (One-Click). Токен не нужен — ссылку санкционирует HMAC-подпись. Его вызывают почтовые клиенты (кнопка «Отписаться» в Gmail/Yandex) и получатели.

Ссылка автоматически проставляется в заголовок List-Unsubscribe при массовой отправке (в /batch — по умолчанию; в /send — по options.list_unsubscribe). POST добавляет адрес в стоп-лист (reason=unsubscribed) и снимает подписку в кабинете; GET отдаёт человеку страницу подтверждения.

Самостоятельно формировать эти ссылки не нужно — сервис вставляет их сам.

Ответ200 One-Click POST
{
  "success": true,
  "unsubscribed": true
}