Документация для разработчиков

Транзакционные письма

Одиночные письма конкретному получателю: подтверждения заказов, коды входа, уведомления, чеки.

Транзакционное письмо не требует адресной базы и уходит сразу. От массовой рассылки оно отличается ещё и тем, что не нуждается в ссылке отписки — такие письма считаются служебными.

Перед первой отправкой нужно подтвердить домен. Домен из from_email должен быть добавлен и проверен в разделе Аккаунт → Домены: без настроенных DKIM и SPF письма не уйдут, а /transactional/log и /transactional/stats вернут code: 34.

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

Числовой status и его текстовое имя statusname показывают последнее известное событие письма:

5SentОтправлено с наших серверов
3DeliveredПринято почтовым сервером получателя
7OpenedПисьмо открыли
6ClickedКликнули по ссылке
4BouncedВозврат, причина в errormessage
9ComplainedПолучатель пожаловался на спам
8UnsubscribedПолучатель отписался

Свой идентификатор письма

Если не передать message_id, DashaMail сгенерирует его сам и вернёт в поле transaction_id. Удобнее задавать свой — тогда вы сможете сопоставить письмо со своей записью в базе, не сохраняя чужой идентификатор.

Отправить письмо #

POST /transactional/messages

Ставит письмо в очередь отправки и сразу возвращает его идентификатор. Фактическая доставка происходит асинхронно — следите за ней через проверку статуса или webhooks.

Нужны как минимум три вещи: получатель, отправитель (from_email либо заголовок From внутри headers) и текст письма (message либо plain_text).

В to можно перечислить несколько адресов через запятую. Тогда каждому уйдёт отдельное письмо, а в message_id можно передать столько же идентификаторов, тоже через запятую.

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

ПараметрТипОписание
to обязательныйstringАдрес получателя. Допустима форма Иван Петров <ivan@example.com>. Несколько адресов перечисляются через запятую.
from_email обязательныйstringАдрес отправителя на подтверждённом домене. Можно не передавать, если заголовок From задан внутри headers.
message обязательныйstringHTML-версия письма. Можно не передавать, если задан plain_text.
from_namestringИмя отправителя. Без него в поле «От кого» подставится сам адрес.
subjectstringТема письма.
plain_textstringТекстовая версия письма.
message_idstringВаш идентификатор письма. Если не задан, генерируется автоматически и возвращается в ответе.
ccstringКопия. Несколько адресов — через запятую.
bccstringСкрытая копия.
headersJSON-строкаПроизвольные заголовки письма объектом — например {"Reply-To":"support@example.ru"}. Заданный здесь From заменяет from_email.
attachmentsJSON-строкаМассив вложений: [{"name":"чек.pdf","filebody":"<base64>"}]. Файлы .php и .exe запрещены, суммарный размер ограничен тарифом.
inlineJSON-строкаВстроенные в вёрстку изображения: [{"cid":"logo","mime_type":"image/png","filename":"logo.png","body":"<base64>"}]. В HTML на них ссылаются как <img src="cid:logo">. Допустимы только image/jpeg, image/png, image/gif.
delivery_timetimestampUnix-время отложенной отправки. Без него письмо уходит немедленно.
domainstringДомен отправки, если в аккаунте их несколько.
stat_domainstringДомен для ссылок отслеживания.
maxdelivertimeintegerСколько секунд пытаться доставить письмо, прежде чем признать возвратом.
maxattemptsintegerМаксимальное число попыток доставки.
ignore_delivery_policyфлагИгнорировать ограничения политики доставки аккаунта.
smarthoststringПромежуточный SMTP-сервер для отправки.
debugintegerУровень отладочного логирования.

Что возвращается

Идентификатор письма — по нему проверяется статус доставки.

Возможные ошибки

HTTPcodeКогда возникает
422 3 Нет получателя, отправителя или текста письма
422 6 Некорректный адрес получателя или отправителя
422 52 Адрес в from_email не подтверждён как отправитель
402 35 Недостаточно средств, функция недоступна на тарифе или аккаунт заблокирован за спам
500 33 Недопустимый формат вложения
413 26 Превышен лимит на размер вложений
500 40 Некорректная структура headers
curl -X POST 'https://api.dashamail.com/v2/transactional/messages' \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
  "to": "ivan@example.com",
  "from_email": "noreply@example.ru",
  "from_name": "Интернет-магазин Ромашка",
  "subject": "Заказ №1024 оплачен",
  "message": "<p>Спасибо за заказ! Мы уже собираем его.</p>",
  "plain_text": "Спасибо за заказ! Мы уже собираем его.",
  "message_id": "order-1024-paid"
}'
<?php
$ch = curl_init('https://api.dashamail.com/v2/transactional/messages');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'POST',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer YOUR_API_KEY',
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS     => json_encode([
            'to' => 'ivan@example.com',
            'from_email' => 'noreply@example.ru',
            'from_name' => 'Интернет-магазин Ромашка',
            'subject' => 'Заказ №1024 оплачен',
            'message' => '<p>Спасибо за заказ! Мы уже собираем его.</p>',
            'plain_text' => 'Спасибо за заказ! Мы уже собираем его.',
            'message_id' => 'order-1024-paid',
        ], JSON_UNESCAPED_UNICODE),
]);

$response = json_decode(curl_exec($ch), true);
$status   = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($status >= 400) {
    throw new RuntimeException($response['error']['message']);
}
print_r($response['response']['data']);
import requests

response = requests.post(
    'https://api.dashamail.com/v2/transactional/messages',
    headers={'Authorization': 'Bearer YOUR_API_KEY'},
    json={
        'to': 'ivan@example.com',
        'from_email': 'noreply@example.ru',
        'from_name': 'Интернет-магазин Ромашка',
        'subject': 'Заказ №1024 оплачен',
        'message': '<p>Спасибо за заказ! Мы уже собираем его.</p>',
        'plain_text': 'Спасибо за заказ! Мы уже собираем его.',
        'message_id': 'order-1024-paid',
    },
)

response.raise_for_status()
print(response.json()['response']['data'])
const response = await fetch('https://api.dashamail.com/v2/transactional/messages', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
  "to": "ivan@example.com",
  "from_email": "noreply@example.ru",
  "from_name": "Интернет-магазин Ромашка",
  "subject": "Заказ №1024 оплачен",
  "message": "<p>Спасибо за заказ! Мы уже собираем его.</p>",
  "plain_text": "Спасибо за заказ! Мы уже собираем его.",
  "message_id": "order-1024-paid"
}),
});

const payload = await response.json();
if (!response.ok) throw new Error(payload.error.message);
console.log(payload.response.data);
Ответ HTTP 201
{
  "response": {
    "msg": {
      "err_code": 0,
      "text": "OK",
      "type": "message"
    },
    "data": {
      "transaction_id": "order-1024-paid"
    }
  }
}

Статус письма #

GET /transactional/messages/{transaction_id}

Возвращает текущий статус письма и historию его событий. Данные появляются через несколько секунд после отправки.

Поиск по конкретному письму доступен за последние шесть месяцев. За более старыми данными обращайтесь к журналу.

Параметры пути

ПараметрТипОписание
transaction_id обязательныйstringИдентификатор письма из ответа на отправку.

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

ПараметрТипОписание
transaction_id обязательныйstringИдентификатор письма — продублируйте значение из пути в строке запроса.

Что возвращается

data — последнее состояние письма, log — последовательность событий. Даты событий лежат в полях datesent, dateopened, dateclicked, datebounced и подобных.

Возможные ошибки

HTTPcodeКогда возникает
422 3 Не передан transaction_id
500 34 В аккаунте не настроен домен отправки
402 35 Функция недоступна на текущем тарифе
404 4 Письма с таким идентификатором не найдено
curl -X GET 'https://api.dashamail.com/v2/transactional/messages/order-1024-paid?transaction_id=order-1024-paid' \
  -H 'Authorization: Bearer YOUR_API_KEY'
<?php
$ch = curl_init('https://api.dashamail.com/v2/transactional/messages/order-1024-paid?transaction_id=order-1024-paid');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'GET',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer YOUR_API_KEY',
    ],
]);

$response = json_decode(curl_exec($ch), true);
$status   = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($status >= 400) {
    throw new RuntimeException($response['error']['message']);
}
print_r($response['response']['data']);
import requests

response = requests.get(
    'https://api.dashamail.com/v2/transactional/messages/order-1024-paid?transaction_id=order-1024-paid',
    headers={'Authorization': 'Bearer YOUR_API_KEY'},
)

response.raise_for_status()
print(response.json()['response']['data'])
const response = await fetch('https://api.dashamail.com/v2/transactional/messages/order-1024-paid?transaction_id=order-1024-paid', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
  },
});

const payload = await response.json();
if (!response.ok) throw new Error(payload.error.message);
console.log(payload.response.data);
Ответ HTTP 200
{
  "response": {
    "msg": {
      "err_code": 0,
      "text": "OK",
      "type": "message"
    },
    "data": {
      "data": {
        "to": "ivan@example.com",
        "status": 3,
        "statusname": "Delivered",
        "date": "2026-04-12T10:15:03Z",
        "datesent": "2026-04-12T10:15:01Z",
        "delivery_info": "Доставлено: 10:15:03 250 2.0.0 OK",
        "statuschangedate": "2026-04-12T10:15:03Z"
      }
    }
  }
}

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

GET /transactional/log

События транзакционных писем аккаунта с фильтрами. Основной инструмент для разбора инцидентов: «почему клиент не получил письмо».

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

ПараметрТипОписание
startintegerпо умолчанию: 0Смещение.
limitintegerпо умолчанию: 500Размер страницы.
sortstringпо умолчанию: DESCНаправление сортировки по времени события.
Допустимые значения: ASC, DESC
message_idstringСобытия одного письма.
campaign_idstringСобытия одной кампании.
event_typestringТипы событий через запятую либо all.
Допустимые значения: SENT, DELIVERED, OPENED, CLICKED, BOUNCED, COMPLAINED, UNSUBSCRIBED, all
emailsstringАдреса получателей через запятую.
fromdatetimeНачало периода.
todatetimeКонец периода.
urlstringФильтр по ссылке для событий клика.

Возможные ошибки

HTTPcodeКогда возникает
500 34 В аккаунте не настроен домен отправки
402 35 Функция недоступна на текущем тарифе
404 4 Событий по фильтру нет
curl -X GET 'https://api.dashamail.com/v2/transactional/log?event_type=BOUNCED&limit=2' \
  -H 'Authorization: Bearer YOUR_API_KEY'
<?php
$ch = curl_init('https://api.dashamail.com/v2/transactional/log?event_type=BOUNCED&limit=2');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'GET',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer YOUR_API_KEY',
    ],
]);

$response = json_decode(curl_exec($ch), true);
$status   = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($status >= 400) {
    throw new RuntimeException($response['error']['message']);
}
print_r($response['response']['data']);
import requests

response = requests.get(
    'https://api.dashamail.com/v2/transactional/log?event_type=BOUNCED&limit=2',
    headers={'Authorization': 'Bearer YOUR_API_KEY'},
)

response.raise_for_status()
print(response.json()['response']['data'])
const response = await fetch('https://api.dashamail.com/v2/transactional/log?event_type=BOUNCED&limit=2', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
  },
});

const payload = await response.json();
if (!response.ok) throw new Error(payload.error.message);
console.log(payload.response.data);
Ответ HTTP 200
{
  "response": {
    "msg": {
      "err_code": 0,
      "text": "OK",
      "type": "message"
    },
    "data": [
      {
        "event_time": "2026-04-12 10:15:40",
        "event_type": "BOUNCED",
        "email": "nobody@example.com",
        "message_id": "order-1025-paid",
        "bounce_code": "5.1.1",
        "bounce_reason": "Bad destination mailbox address"
      },
      {
        "event_time": "2026-04-12 09:02:11",
        "event_type": "BOUNCED",
        "email": "old@example.com",
        "message_id": "order-1019-paid",
        "bounce_code": "5.2.2",
        "bounce_reason": "Mailbox full"
      }
    ]
  }
}

Статистика отправок #

GET /transactional/stats

Агрегированные показатели транзакционных писем за период, разложенные по временным интервалам. Годится для построения графиков доставляемости.

Ширина интервала подбирается по периоду автоматически: пять минут для 1h, час для 24h, сутки для 7d и 30d.

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

ПараметрТипОписание
periodstringпо умолчанию: 1hПериод отчёта. Значение custom включает start_date и finish_date.
Допустимые значения: 1h, 24h, 7d, 30d, custom
start_datedatetimeНачало периода при period=custom.
finish_datedatetimeКонец периода при period=custom.
groupbystringШаг группировки при period=custom.
Допустимые значения: hour, day, week, month
campaign_idstringТолько письма указанной кампании.
domainstringТолько письма с указанного домена отправки.
startintegerпо умолчанию: 0Смещение.
limitintegerРазмер страницы.

Возможные ошибки

HTTPcodeКогда возникает
402 35 Функция недоступна на текущем тарифе
404 4 Данных за период нет
curl -X GET 'https://api.dashamail.com/v2/transactional/stats?period=24h' \
  -H 'Authorization: Bearer YOUR_API_KEY'
<?php
$ch = curl_init('https://api.dashamail.com/v2/transactional/stats?period=24h');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'GET',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer YOUR_API_KEY',
    ],
]);

$response = json_decode(curl_exec($ch), true);
$status   = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($status >= 400) {
    throw new RuntimeException($response['error']['message']);
}
print_r($response['response']['data']);
import requests

response = requests.get(
    'https://api.dashamail.com/v2/transactional/stats?period=24h',
    headers={'Authorization': 'Bearer YOUR_API_KEY'},
)

response.raise_for_status()
print(response.json()['response']['data'])
const response = await fetch('https://api.dashamail.com/v2/transactional/stats?period=24h', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
  },
});

const payload = await response.json();
if (!response.ok) throw new Error(payload.error.message);
console.log(payload.response.data);
Ответ HTTP 200
{
  "response": {
    "msg": {
      "err_code": 0,
      "text": "OK",
      "type": "message"
    },
    "data": [
      {
        "time": "2026-04-12 09:00",
        "sent": 412,
        "delivered": 401,
        "opened": 188,
        "clicked": 42,
        "bounced": 9,
        "complained": 0
      },
      {
        "time": "2026-04-12 10:00",
        "sent": 388,
        "delivered": 380,
        "opened": 165,
        "clicked": 37,
        "bounced": 6,
        "complained": 1
      }
    ]
  }
}

DashaMail хранит и защищает ваши данные на территории Российской Федерации

Подробнее...