Перейти к содержанию

API подписки

Блок подписки отправляет на один публичный эндпоинт, и всё остальное тоже может: форма на другом сайте, скрипт, сервер, ретранслирующий подписки откуда-то, где Mailroom не работает. Эта страница — справочник по этому эндпоинту.

POST {route}/subscribe

С базовым маршрутом по умолчанию — https://www.example.com/newsletter/subscribe. Ключа API нет: эндпоинт публичный, как и блок подписки, который его использует.

Два способа отправки

Запрос Принимается, когда
JSON, Content-Type: application/json Всегда. Браузерная форма с другого сайта не может отправить этот тип содержимого без предварительного запроса, который браузер не разрешит, поэтому nonce не нужен. Именно это отправляет скрипт блока подписки и то, что должен отправлять скрипт или ретранслятор.
Отправка формы (application/x-www-form-urlencoded или multipart/form-data) Только с nonce сайта в поле nonce, что отправляет блок подписки без JavaScript.

Всё остальное отклоняется с 415. GET отклоняется с 405.

Поля

Поле Тип Что делает
email строка, обязательна Адрес.
name строка Его имя.
list строка Код списка. Пустой или код, не называющий список, означает список по умолчанию.
lists массив строк или одна строка через запятую Дополнительные коды списков для той же подписки. Каждый список сохраняет своё двойное подтверждение подписки, и одно письмо подтверждения покрывает их все. Коды, не называющие список, исключаются; если не осталось ни одного, используется список по умолчанию.
tags массив строк или одна строка через запятую Коды тегов, которые на него поставить.
consent логическое Обязательно и должно быть true, когда у сайта есть Consent Sentence. Считаются true, 1, "true", "on" и "yes".
language строка Двухбуквенный код языка для сохранения у него.
source строка Как он пришёл: form или api. Всё остальное игнорируется. См. ниже.
source_ref строка Ваша заметка о том, откуда он пришёл, например footer. До 190 символов.
pick_lists логическое Отправляется формой, которая предлагает списки флажками. С ним подписка, не называющая список, отклоняется, а не попадает в список по умолчанию.
website строка Ловушка для ботов. Должна быть пустой (см. ниже).

Ответы

JSON-запрос всегда получает JSON в ответ; отправка формы получает JSON, когда отправляет Accept: application/json, иначе — страницу в вашей теме с тем же предложением.

Статус Тело Когда
200 {"status": "subscribed", "message": "Thanks. You are on the list."} Он уже в списке (список, который не просит подтверждения).
202 {"status": "pending", "message": "We have sent you a confirmation email. Check your inbox and press the button in it to be added to the list."} Письмо подтверждения в пути. Он ни в чём не состоит, пока не нажмёт кнопку.
405 {"status": "error", "error": "method_not_allowed", ...} Это не POST. Несёт Allow: POST.
415 {"status": "error", "error": "unsupported_media_type", ...} Отправка формы без nonce или другой тип содержимого.
422 {"status": "error", "error": "invalid_email", ...} Адрес не является адресом.
422 {"status": "error", "error": "consent_required", ...} У сайта есть предложение согласия, а consent не был true.
422 {"status": "error", "error": "list_required", ...} pick_lists был отправлен без списка.
429 {"status": "error", "error": "rate_limited", "message": "...", "retry_after": 1800} Слишком много подписок с одного адреса посетителя. Несёт Retry-After.

В каждом теле ошибки также есть message, который можно показать посетителю как есть.

Новый адрес, уже находящийся в списке и исключённый получают одинаковый ответ, байт в байт, поэтому эндпоинт никогда не выдаёт, читает ли конкретный человек вашу почту. Исключённый адрес просто не записывается.

Ловушка — поле website. Запрос, в котором что-то есть, получает ответ 200, и ничего не записывается, поэтому бот ничего не узнаёт о том, какое поле его выдало. Не передавайте его или передавайте пустым.

Ограничение частоты

Каждый адрес посетителя может отправлять Signups Per Hour (rate_limits.subscribe, 10) раз в час; 0 выключает ограничение. Один вызов считается один раз, сколько бы списков он ни называл. Счётчик хранится в базе Mailroom под хешем адреса, а IPv6-адрес считается как его /64.

Как записывается источник

source у подписчика говорит, как он пришёл. Вызывающий может назвать его, form или api; всё остальное (admin, import и другие способы, которые пишет только сам сайт) игнорируется, и подписка читается так, будто источник не указан, с тем же ответом. Если он не указан:

  • отправка формы, нёсшая nonce, — form;
  • тело JSON, отправленное браузером со страницы вашего сайта (Sec-Fetch-Site: same-origin или Origin, называющий собственный хост сайта), — form, то есть собственный скрипт блока подписки;
  • любое другое тело JSON, например ретранслятор на другом сервере, — api.

Примеры

curl -s -X POST https://www.example.com/newsletter/subscribe \
  -H "Content-Type: application/json" \
  -d '{"email": "ada@example.com", "name": "Ada", "list": "newsletter", "consent": true, "source_ref": "launch-page"}'
{"status": "pending", "message": "We have sent you a confirmation email. Check your inbox and press the button in it to be added to the list."}

Несколько списков и тегов сразу:

{"email": "ada@example.com", "lists": ["newsletter", "events"], "tags": ["webinar"], "consent": true}

За прокси или ретранслятором

Адрес, который считается в ограничении частоты и сохраняется с согласием человека, — это REMOTE_ADDR соединения. Когда ваш сайт стоит за прокси или балансировщиком нагрузки либо другой сервер ретранслирует ему подписки, все запросы иначе приходили бы с одного адреса, и десять подписок в час были бы лимитом всего сайта.

Trusted Proxies (security.trusted_proxies, на вкладке Public Pages) перечисляет адреса или диапазоны CIDR этих серверов:

security:
  trusted_proxies:
    - 203.0.113.10
    - 10.0.0.0/8

Только запросу, чей REMOTE_ADDR есть в списке, верят в заголовке X-Forwarded-For. Mailroom читает заголовок справа, пропускает каждый доверенный шаг и берёт первый недоверенный адрес как адрес посетителя. Порт, который прокси записал на шаге (203.0.113.9:5678, [2001:db8::1]:443), отбрасывается. От всех остальных заголовок игнорируется, потому что его может отправить кто угодно.

Серверный ретранслятор

Скажем, www.example.com держит форму в подвале, а news.example.com держит Mailroom. Форма на www.example.com отправляет на свой сервер, который ретранслирует подписку как JSON, передавая адрес посетителя:

<?php
// На www.example.com, после чтения формы в подвале.
$payload = json_encode([
    'email'      => $email,
    'list'       => 'newsletter',
    'consent'    => $consentTicked,   // true, только если посетитель отметил флажок
    'source'     => 'form',           // форма, хотя отправляет её сервер
    'source_ref' => 'www-footer',
]);

$ch = curl_init('https://news.example.com/newsletter/subscribe');
curl_setopt_array($ch, [
    CURLOPT_POST           => true,
    CURLOPT_POSTFIELDS     => $payload,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 10,
    CURLOPT_HTTPHEADER     => [
        'Content-Type: application/json',
        'Accept: application/json',
        'X-Forwarded-For: ' . $_SERVER['REMOTE_ADDR'],
    ],
]);
$body   = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

$answer = json_decode((string) $body, true);
// 200 или 202: показать $answer['message']. 422 или 429: показать $answer['message'] как ошибку.

На news.example.com добавьте адрес сервера-ретранслятора в Trusted Proxies. Тогда каждый посетитель получает свои десять подписок в час, и его собственный адрес сохраняется с его согласием.

  • Обращайтесь к серверу Mailroom напрямую. Если запрос ретранслятора проходит через CDN или прокси, REMOTE_ADDR — это адрес того прокси, поэтому либо перечислите и эти адреса, либо отправляйте запрос прямо на origin.
  • Показывайте то же предложение согласия. Запись согласия хранит хеш собственного Consent Sentence Mailroom, поэтому форма ретранслятора должна показывать это предложение слово в слово.
  • Передавайте ответ дальше. message написан для посетителя, а 422 или 429 точно говорит, что ему сообщить.
  • Используйте этот эндпоинт, а не админский API. POST /api/v1/mailroom/subscribers — для администраторов: ему нужен ключ с mailroom.manage, и он записывает человека как добавленного сайтом.