Если вы перепродаёте отправку — агентство, которое ведёт почту клиентов, или сервис со своим экраном «подключите домен», — ваш backend может управлять fmailer напрямую: создавать домены, получать DNS-записи, которые нужно опубликовать, выпускать SMTP-доступы и регистрировать вебхуки. Всё это из вашего продукта: ваши пользователи не видят эту панель и не встречают название fmailer.
Для этого нужен white-label токен — ключ уровня аккаунта, который выпускается в панели и работает с отдельным машинным API по адресу /api/wl/v1/.
White-label подключается на уровне аккаунта. Это не часть тарифа, и купить его нельзя — мы включаем его для вашего аккаунта по запросу. До этого на странице White-label в настройках аккаунта написано, как с нами связаться; после — там появляется список ваших токенов. Подключение действует на весь аккаунт, поэтому токен не привязан ни к одному из ваших доменов.
Ради этого всё и затевается, и это отдельная настройка, не связанная с токеном. По умолчанию записи, которые мы генерируем для домена, называют нас в трёх местах — ровно в тех, что ваш клиент копирует в свою DNS-панель и видит при каждой проверке зоны:
| Запись | Называет |
|---|---|
| SPF | v=spf1 a mx include:spf.fmailer.ru ~all |
| CNAME статистики | stats.<клиент> → stats.fmailer.ru |
| DMARC | rua=mailto:dmarc@reports.fmailer.ru |
Все три заменяются одним полем. В разделе Аккаунт → White-label укажите свой домен для DNS — домен, которым владеете вы, например mail.reseller.ru. После этого домены, созданные через API, получают include:spf.mail.reseller.ru, CNAME на stats.mail.reseller.ru и rua=mailto:dmarc@dmarc.mail.reseller.ru. В зоне клиента нет ни слова про fmailer.
Настройка относится к той витрине, на которой вы её задали, а не к аккаунту целиком. Если вы продаёте ещё и через другую нашу витрину, у неё свой домен для DNS и свой набор записей: хосты, на которые они должны указывать, там другие, поэтому одна зона не может быть верной сразу для обеих. Настройте каждую там, где продаёте.
То же поле пишется через API — но ключом от панели, а не white-label токеном:
curl -X PATCH https://api.fmailer.ru/api/whitelabel/settings/ \
-H "Authorization: Bearer $ВАШ_JWT_ИЗ_ПАНЕЛИ" \
-H "Content-Type: application/json" \
-d '{"dns_domain": "mail.reseller.ru"}'Так задумано: утёкший машинный ключ не должен уметь переписать DNS всех будущих клиентов, поэтому этот метод остался в панели рядом с выпуском и отзывом токенов.
Метки spf., stats., dmarc. и mx. фиксированы, от вас нужна только доменная часть. В своей зоне вы публикуете пять записей, один раз — не для каждого клиента:
| Тип | Имя | Указывает на | Что сломается без неё |
|---|---|---|---|
CNAME | spf.mail.reseller.ru | spf.fmailer.ru | SPF-политика, которую домены ваших клиентов подключают через include:. Все их письма перестанут проходить SPF. |
CNAME или A | stats.mail.reseller.ru | stats.fmailer.ru | Трекинг открытий и переходов. Ссылки трекинга и пиксели открытий в письмах клиентов перестанут резолвиться. |
MX | dmarc.mail.reseller.ru | reports.fmailer.ru (приоритет 10) | Ящик, куда доставляются сводные DMARC-отчёты по доменам клиентов. Отчёты никуда не придут, а вместе с ними пропадёт сигнал о сломанном DKIM-ключе или о цепочке SPF, которая перестала вас авторизовывать. |
TXT | *._report._dmarc.dmarc.mail.reseller.ru | v=DMARC1 | Разрешение по RFC 7489 §7.1 на отправку этих отчётов. Без него их молча не отправляют. |
CNAME или A | mx.mail.reseller.ru | mx.fmailer.ru | Куда доставляется почта для входящих маршрутов ваших клиентов. Нужна только тем клиентам, кто принимает письма. |
Строку с SPF стоит прочитать внимательно: по имени spf.mail.reseller.ru должна лежать политика, которая включает spf.fmailer.ru, и проще всего опубликовать её как CNAME — тогда она сама обновляется вместе с нашими отправляющими IP. Своя TXT-политика тоже подойдёт, если она нас авторизует. А вот value, которое API отдаёт для этой записи — v=spf1, — публиковать буквально нельзя: это маркер, с которым мы сверяемся, и сам по себе он не авторизует никого. С v=DMARC1 на wildcard наоборот: это и есть вся запись целиком.
Средняя пара — для отчётов DMARC. Сводные отчёты по доменам ваших клиентов адресуются в ящик в вашем домене, поэтому MX должен доходить до нас, а поскольку домен из отчёта принадлежит клиенту, а ящик — вам, RFC 7489 §7.1 требует, чтобы принимающая сторона сначала нашла разрешение. Это разрешение — один wildcard, а не запись на каждого клиента. Страница White-label резолвит все пять имён, показывает состояние каждого и подсказывает, чего не хватает: после публикации нажмите Проверить.
spf.mail.reseller.ru при этом не резолвится. Поэтому если вы её не опубликуете, у каждого клиента экран настройки станет зелёным, а каждое письмо будет проваливать SPF на стороне получателя. Кнопка Проверить на странице White-label — единственное, что это ловит. wl_ и 48 символов после него, и показывается ровно один раз: он хранится в виде хеша и восстановить его нельзя. Если потеряли — отзовите токен и выпустите новый. В списке потом видна только маска (wl_ab12cd34…), чтобы отличать токены друг от друга, и время последнего использования. Токены нельзя редактировать: чтобы изменить права или срок, выпустите новый и отзовите старый. Отзыв действует немедленно — интеграция, которая использует этот токен, сразу начнёт получать ошибки.
Передавайте секрет в заголовке в каждом запросе:
curl https://api.fmailer.ru/api/wl/v1/domains/ \
-H "Authorization: Bearer wl_ваш-токен" White-label токен работает только с /api/wl/v1/. Он не может прочитать ваш профиль, счёт или выпустить другой токен — остальной API не умеет его проверять и отвечает 401.
Ограничение: 120 запросов в минуту на токен. Лимит считается по токену, а не по аккаунту, поэтому разные интеграции не мешают друг другу. При превышении — 429.
Чтение и запись разделены: интеграция, которая только показывает состояние в вашем интерфейсе, может держать ключ, которым ничего нельзя создать или удалить.
| Право | Что разрешает |
|---|---|
domains:read | список и карточка домена, чтение DNS-записей |
domains:write | создание, удаление и перепроверка доменов |
smtp_tokens:read | список и карточка SMTP-доступа |
smtp_tokens:write | создание и удаление SMTP-доступов |
webhooks:read | список и карточка эндпоинта вебхука |
webhooks:write | создание, изменение и удаление эндпоинтов |
inbound:read | чтение хоста приёма, маршрутов и полученных писем |
inbound:write | настройка хоста приёма, управление маршрутами, удаление писем |
Если права не сужать, токен получает все восемь — обычный случай, когда один backend ведёт весь сценарий подключения. Запрос за пределами прав токена отклоняется с 403, в котором названо нужное право:
{
"detail": "This token is missing the \"domains:write\" scope"
} Базовый адрес — https://api.fmailer.ru/api/wl/v1/. Всё адресуется по uuid, включая фильтр ?domain=. Версия указана в пути с самого начала, поэтому будущая /v2/ не сломает вашу интеграцию.
| Метод | Путь | Право | Что делает |
|---|---|---|---|
GET | /domains/ | domains:read | список доменов аккаунта |
POST | /domains/ | domains:write | создать домен, тело {"domain": "example.ru"}; создаются ключи DKIM, а записи для публикации читаются отдельно, из /records/ |
GET | /domains/<uuid>/ | domains:read | карточка домена |
GET | /domains/<uuid>/records/ | domains:read | DNS-записи, которые нужно опубликовать; обычный массив, без страниц. Единственный источник этих записей |
POST | /domains/<uuid>/verify/ | domains:write | проверить DNS сразу, не дожидаясь регулярной проверки |
DELETE | /domains/<uuid>/ | domains:write | удалить домен; только домены, созданные через этот API, иначе 400 |
GET | /smtp-tokens/?domain=<uuid> | smtp_tokens:read | SMTP-доступы домена |
POST | /smtp-tokens/ | smtp_tokens:write | создать доступ: domain, username (локальная часть — @<domain> добавляем мы), необязательный note; домен должен быть уже подтверждён, иначе 400; пароль возвращается один раз, в этом ответе |
GET / DELETE | /smtp-tokens/<uuid>/ | чтение / запись | карточка или удаление доступа |
GET | /webhooks/?domain=<uuid> | webhooks:read | эндпоинты вебхуков домена |
POST | /webhooks/ | webhooks:write | зарегистрировать эндпоинт: url, enabled, events, description |
GET / PATCH / PUT / DELETE | /webhooks/<uuid>/ | чтение / запись | карточка, изменение или удаление эндпоинта |
GET / PUT | /domains/<uuid>/inbound/ | inbound:read / inbound:write | хост, на котором домен принимает почту, и MX-цель для него; PUT {"hostname": ""} выключает приём |
GET | /inbound-routes/?domain=<uuid> | inbound:read | маршруты приёма домена |
POST | /inbound-routes/ | inbound:write | создать маршрут: domain, pattern, endpoint, description |
GET / PATCH / PUT / DELETE | /inbound-routes/<uuid>/ | чтение / запись | карточка, изменение или удаление маршрута |
/domains/<uuid>/inbound/ висит на домене, но требует inbound:*, а не domains:*: этот метод меняет то, для каких адресов наш SMTP-сервер вообще примет почту, и токен, суженный до управления доменами, не должен получать это заодно. На этом API он нужен потому, что у вашего клиента нет панели: без него white-label домен мог бы иметь маршруты и не принять ни одного письма. Настраивайте его первым — до этого POST /inbound-routes/ отвечает 400. Маршруты, шаблоны адресов и тело inbound.received описаны в разделе Приём писем. DELETE /api/wl/v1/domains/<uuid>/ удаляет домен, только если он был создан через этот API. Если указать один из обычных доменов вашего аккаунта — тех, что вы добавили в панели, — придёт 400. Ошибка в вашем коде не может положить вашу собственную рабочую отправку. Домен, созданный через POST /api/wl/v1/domains/, попадает на отдельный white-label тариф, по которому никогда не выставляется счёт: ни счетов, ни напоминаний об оплате, ни выбора тарифа — ни вам, ни вашему клиенту не нужно платить за каждый такой домен. Лимиты отправки для них мы настраиваем индивидуально в рамках вашей white-label договорённости — напишите нам, если их нужно поднять.
White-label меняет кто обращается, но не то, что входит в тариф домена. Все остальные ограничения остаются: регистрация вебхука на домене, в тариф которого вебхуки не входят, по-прежнему даёт 403 — ровно как в панели. То же касается шаблонов, аналитики и выгрузок.
Помимо событий письма есть два события жизненного цикла домена. Подписка на них по желанию: добавьте их в массив events эндпоинта — через API выше или на экране Вебхуки в панели. Существующие эндпоинты не меняются.
| Событие | Когда приходит |
|---|---|
domain.verified | записи домена прошли проверку и он стал подтверждённым |
domain.unverified | подтверждение домена было снято |
Повторная проверка, которая ничего не изменила, событий не порождает — уже подтверждённый домен не шлёт вебхук при каждом обходе.
message_id, ни email — их нет вообще, а не null. Вместо них приходят domain и domain_id. Обработчик, который принимает оба вида событий, должен ветвиться по полю event. {
"event_id": "5d1f7ce0-6f0f-4d09-9f27-3fd06d6fa1a1",
"event": "domain.verified",
"domain": "mail.client.ru",
"domain_id": "0e0f3b6f-3d9e-4a8a-9c65-2b9a5b3f1f22",
"timestamp": "2026-08-03T09:41:07.512340+00:00",
"data": { "verified_at": "2026-08-03T09:41:07.480112+00:00" }
}domain.unverified приходит только тогда, когда подтверждение действительно сняли, а это действие сотрудника сервиса. Если нужно реагировать на поломку DNS, следите за полем dns_error_at домена. Порядок шагов — не пожелание: SMTP-доступ нельзя выпустить для домена, который ещё не подтверждён. Скрипт, который пытается вернуть клиенту логин и пароль тем же вызовом, что создаёт домен, всегда будет падать.
curl -X POST https://api.fmailer.ru/api/wl/v1/domains/ \
-H "Authorization: Bearer $WL_TOKEN" \
-H "Content-Type: application/json" \
-d '{"domain": "mail.client.ru"}' В ответе 201 приходит сам домен — его uuid, тариф, состояние подтверждения. DNS-записей в нём нет: сохраните uuid и запросите их следующим шагом.
{
"uuid": "0e0f3b6f-3d9e-4a8a-9c65-2b9a5b3f1f22",
"domain": "mail.client.ru",
"verified_at": null,
"last_check_at": null,
"dns_error_at": null,
"plan": {
"uuid": "c4a1e0d6-9b52-4f8e-83a1-7c5d0e2f9b41",
"name": "White label",
"price": "0.00",
"on_request": true,
"webhooks_enabled": true,
"inbound_enabled": true,
"max_inbound_routes": 25
},
"created_at": "2026-08-03T09:40:12.884210+00:00"
} Обычный массив, без обёртки со страницами. Показывайте записи в своём интерфейсе и опрашивайте этот метод, чтобы отображать состояние каждой: verified_at проставляется, когда запись сошлась, checked_at — когда её проверяли последний раз, а last_result объясняет, почему не сошлась.
curl https://api.fmailer.ru/api/wl/v1/domains/0e0f3b6f-3d9e-4a8a-9c65-2b9a5b3f1f22/records/ \
-H "Authorization: Bearer $WL_TOKEN"[
{
"uuid": "b81c6f4a-1e77-4d2e-9a55-6f0d1c3b7e90",
"domain": "0e0f3b6f-3d9e-4a8a-9c65-2b9a5b3f1f22",
"type": "TXT",
"name": "@",
"full_name": "mail.client.ru",
"value": "v=spf1 a mx include:spf.mail.reseller.ru ~all",
"match": "spf",
"required": true,
"verified_at": null,
"checked_at": null,
"last_result": null
},
{
"uuid": "3a0e9d21-55b8-4c07-8f13-9d2b6a4e1c58",
"domain": "0e0f3b6f-3d9e-4a8a-9c65-2b9a5b3f1f22",
"type": "TXT",
"name": "default._domainkey",
"full_name": "default._domainkey.mail.client.ru",
"value": "v=DKIM1; k=rsa; p=MIIBIjANBgkqhki...",
"match": "exact",
"required": true,
"verified_at": null,
"checked_at": null,
"last_result": null
}
] Экран настройки стоит строить вокруг поля match: оно говорит, как ответ DNS сверяется со значением value, и клиенту в этих случаях нужно давать разные инструкции.
match | Что сказать клиенту |
|---|---|
exact | Опубликовать значение дословно. Такая запись стоит на имени, куда больше никто не пишет — ключ DKIM, CNAME статистики. |
spf | Дописать в существующую, а не добавить рядом. RFC 7208 разрешает одну SPF-запись на имя, поэтому клиент, который уже откуда-то отправляет, должен вписать наш include: в свою. Мы сверяем по смыслу, так что порядок термов и чужие отправители значения не имеют. |
dmarc | То же самое для _dmarc: мы проверяем, что наш ящик rua есть среди перечисленных, а не совпадение строки. |
mx | MX для приёма, сверяется по тому, куда реально придёт письмо. Свой хост клиента с A-записью на наш адрес — тоже верно, и приоритет он выбирает сам. |
Интерфейс, который для всех строк говорит «опубликуйте ровно это», скажет клиенту с правильной зоной, что она сломана, — а именно такие обращения в поддержку это поле и позволяет предотвратить.
Когда пользователь добавил записи у своего DNS-провайдера, запросите проверку сразу, не дожидаясь регулярной:
curl -X POST https://api.fmailer.ru/api/wl/v1/domains/0e0f3b6f-3d9e-4a8a-9c65-2b9a5b3f1f22/verify/ \
-H "Authorization: Bearer $WL_TOKEN"Сначала подтвердите домен. Доступ выпускается только для домена, который уже прошёл проверку DNS, поэтому это действительно четвёртый шаг: пока verified_at не проставлен, метод отвечает 400.
curl -X POST https://api.fmailer.ru/api/wl/v1/smtp-tokens/ \
-H "Authorization: Bearer $WL_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"domain": "0e0f3b6f-3d9e-4a8a-9c65-2b9a5b3f1f22",
"username": "app",
"note": "приложение клиента"
}'{
"id": 4711,
"uuid": "7b1a4c2e-8f30-4f5b-9d61-0c4e2a7b8d33",
"domain": "0e0f3b6f-3d9e-4a8a-9c65-2b9a5b3f1f22",
"username": "app@mail.client.ru",
"note": "приложение клиента",
"_password": "пароль-показывается-один-раз"
}username — обязательное поле, и это локальная часть, а не адрес: @<domain> мы добавляем сами. Отправьте app — доступ будет входить как app@mail.client.ru; отправите app@mail.client.ru — получите домен дважды. Используйте буквы, цифры, подчёркивание и дефис, как в панели. note необязателен и нужен вам: по нему ваша поддержка понимает, какой интеграции клиента принадлежит доступ. Пароль выбирать не нужно — он генерируется.
_password возвращается в этом ответе и больше нигде — храните его как любой другой секрет. В списке и в карточке доступа поля с паролем нет вообще, ни в каком виде: если потеряли — удалите доступ и выпустите новый. Дальше пара логин/пароль используется с smtp.fmailer.ru точно так же, как описано в разделе Отправка через SMTP.
OPTIONS /api/wl/v1/smtp-tokens/, описывают модель, а не контракт создания, и расходятся с ним в трёх местах: domain помечен «только для чтения», хотя это обязательное поле запроса; password помечен обязательным, хотя вы его не передаёте; а перечисленные поля — это поля чтения. Ответ на создание — тот сокращённый объект выше, без enabled и created_at: они появляются, когда вы запрашиваете доступ методом GET. curl -X POST https://api.fmailer.ru/api/wl/v1/webhooks/ \
-H "Authorization: Bearer $WL_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"domain": "0e0f3b6f-3d9e-4a8a-9c65-2b9a5b3f1f22",
"url": "https://your-app.example.ru/hooks/mail",
"events": ["delivered", "bounced", "domain.verified"],
"description": "клиент 4711"
}'Подпись, повторы и правила доставки те же, что и у обычных вебхуков — схема подписи и расписание повторов описаны в разделе Вебхуки.
curl -X PUT https://api.fmailer.ru/api/wl/v1/domains/0e0f3b6f-3d9e-4a8a-9c65-2b9a5b3f1f22/inbound/ \
-H "Authorization: Bearer $WL_TOKEN" \
-H "Content-Type: application/json" \
-d '{"hostname": "inbound.mail.client.ru"}'mx_target в ответе — это значение, на которое клиент нацелит свою MX-запись. Для white-label домена это имя в вашем домене, поэтому никогда не собирайте эту строку сами. Созданная MX-запись появляется в /records/ этого домена рядом с остальными, и после этого можно создавать маршруты:
curl -X POST https://api.fmailer.ru/api/wl/v1/inbound-routes/ \
-H "Authorization: Bearer $WL_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"domain": "0e0f3b6f-3d9e-4a8a-9c65-2b9a5b3f1f22",
"pattern": "support",
"endpoint": "9f2c1b7e-4d38-4a10-8b6c-5e0a3d7f2c19"
}' Подошедшее письмо приходит на ваш эндпоинт событием inbound.received. Шаблоны адресов, метки после плюса и формат тела описаны в разделе Приём писем.