Email Spam Tester

API проверки писем на спам,
папки и домена

Отправьте нам одно реальное сообщение или укажите только домен. Все ответы приходят в JSON.

Без ключа и учетной записи.

Запрос

# reserve a single-use address

$ curl -sX POST '.../api/v1/inbox?lang=en'

# send your message to that address, then

$ curl -s '.../api/v1/tests/k7m2x9qplw4tz8vn3b6c/status'

# read the report

$ curl -s '.../api/v1/tests/k7m2x9qplw4tz8vn3b6c'

Ответ

200 OK

{
  "address": "test-k7m2x9qplw4tz8vn3b6c@t.email-spam-tester.com",
  "slug": "k7m2x9qplw4tz8vn3b6c",
  "expires_at": "2026-10-31T13:00:00Z"
}

200 OK

{
  "analysis_status": "checks_ready",
  "ai_status": "running",
  "checks_done": 42,
  "checks_total": 42
}

200 OK

{
  "score_ours": 86.4,
  "score_compat": 9.2,
  "subscores": {"auth": 100.0, "infra_spam": 78.1, "content": 92.0},
  "complete": true,
  "checks": [{"id": "auth.dmarc", "status": "warn"}],
  "fixes": [{"id": "dmarc-enforce", "gain_ours": 4.0}]
}

Запрос

# create a test

$ curl -sX POST '.../api/v1/placement' \ -d '{"public_results_accepted":true}'

# put the marker in the subject, send once to all, then

$ curl -s '.../api/v1/placement/wR3kP9xLq2vT8mZc'

Ответ

201 Created

{
  "marker": "est-3f9a1c7e2b4d6a80c5e1f2d3",
  "status": "waiting",
  "results": [{"provider": "gmail", "placement": "pending"}],
  "fleet": {"status": "observing", "results": [
    {"provider": "yahoo", "placement": "pending"},
    {"provider": "outlook", "placement": "pending"}
  ]}
}

200 OK

{
  "status": "complete",
  "results": [{"provider": "gmail", "placement": "primary"}],
  "fleet": {"status": "finished", "results": [
    {"provider": "yahoo", "placement": "inbox"},
    {"provider": "outlook", "placement": "spam"}
  ]}
}

Запрос

# no email needed, one GET

$ curl -s '.../api/v1/infra/check?domain=example.com'

# compare with your last run

$ curl -s '.../api/v1/infra/check?domain=example.com&diff=true' \ | jq '.diff'

Ответ

200 OK

{
  "domain": "example.com",
  "ok": false,
  "status": "fail",
  "score": 78,
  "coverage": {"answered": 7, "total": 8},
  "sections": {"ptr": {"status": "fail", "core": true}}
}

200 OK

{
  "changed": true,
  "worsened": true,
  "status_from": "pass",
  "score_from": 100,
  "changes": [{"path": "dkim.key.mail.sha256", "kind": "removed",
               "severity": "critical", "effect": "worsened"}]
}
На этой странице

Тест письма

Мы полностью проверяем одно реальное сообщение: содержимое, подпись, заголовки и отправивший его сервер. Вы получаете оценку, список исправлений и результаты всех проверок, на которых они основаны.

Быстрый старт

Три вызова. Без ключа, учётной записи и регистрации. Два запроса и одно письмо. Третий вызов нужен только потому, что анализ занимает несколько секунд.

  1. Зарезервируйте адрес

    Отправьте POST-запрос к конечной точке входящих сообщений. В ответ вы получите адрес, который принимает ровно одно сообщение и истекает через час, а также slug, к которому привязано всё остальное.

    Запрос

    # 1. reserve a single-use address
    curl -sX POST 'https://email-spam-tester.com/api/v1/inbox?lang=en'

    Ответ

    {
      "address": "test-<slug>@t.email-spam-tester.com",
      "slug": "<slug>",
      "expires_at": "2026-01-01T12:00:00Z"
    }
  2. Отправьте на него настоящее сообщение

    По SMTP, с платформы, которая будет отправлять рассылку. Половина проверок анализирует заголовки, добавляемые вашей платформой отправки, поэтому составленное вручную сообщение измеряет не то, что нужно.

    Запрос

    # 2. send your message to that address, from your own platform
    To: test-<slug>@t.email-spam-tester.com
  3. Опрашивайте статус, затем прочитайте отчёт

    Конечная точка статуса возвращает несколько сотен байт и сообщает, стоит ли уже загружать полный отчёт. Сам отчёт занимает несколько тысяч строк.

    Запрос

    # 3. poll
    curl -s 'https://email-spam-tester.com/api/v1/tests/<slug>/status'

    Ответ

    {
      "slug": "<slug>",
      "analysis_status": "checks_ready",
      "ai_status": "running",
      "checks_done": 42,
      "checks_total": 42
    }

    Запрос

    # 4. read the report once analysis_status is checks_ready
    curl -s 'https://email-spam-tester.com/api/v1/tests/<slug>'

    Ответ

    {
      "report_url": "https://email-spam-tester.com/t/<slug>",
      "score_ours": 86.4,
      "score_compat": 9.2,
      "subscores": {"auth": 100.0, "infra_spam": 78.1, "content": 92.0, "compliance": 75.0},
      "complete": true,
      "checks": [
        {
          "id": "auth.dmarc",
          "status": "warn",
          "title": "DMARC result",
          "summary": "DMARC passes, but the policy is p=none.",
          "weight_ours": -4.0,
          "evidence": {"policy": "none", "aligned": "dkim"},
          "citations": {"standards": [{"title": "RFC 9989 §4.7", "quote": "..."}]}
        }
      ],
      "fixes": [
        {"id": "dmarc-enforce", "gain_ours": 4.0, "gain_compat": 0.0,
         "fix": {"title": "Move DMARC to quarantine", "severity": "medium"}}
      ]
    }

Зарезервируйте адрес, отправьте сообщение, которое вы собирались отправить своему списку рассылки, и прочитайте отчёт. Всё, что показано на странице, есть в JSON, включая оценку, все 42 проверки с подтверждающими данными и раздел стандарта, на котором основан каждый результат.

Первые 100 000 отчётов бесплатны, без ключа и без учётной записи. Если вы подключаете агент, а не скрипт, сервер MCP подходит лучше, чем опрос.

Конечные точки

Базовый адрес https://email-spam-tester.com. Все ответы возвращаются в формате JSON.

POST/api/v1/inbox

Резервирует одноразовый адрес. Оба параметра необязательны.

langЯзык, на котором будут написаны план исправлений и результаты отдельных проверок, в виде кода ISO. Он определяется сейчас, потому что сообщение приходит по SMTP через несколько минут и не содержит указаний на то, кто его ожидает. Для неизвестного кода используется английский язык.
utm_source, utm_medium, utm_campaignПередаются в нашу аналитику. Полезно, если вы оцениваете собственную интеграцию.

GET/api/v1/tests/{slug}/status

Не требует значительных ресурсов при опросе. Возвращает два поля состояния и сведения о ходе проверок, и ничего больше.

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

GET/api/v1/tests/{slug}

Полный отчёт. Возвращает 202, пока адрес зарезервирован и ещё ничего не поступило, и 200 после поступления сообщения.

GET/api/v1/tests/{slug}/message

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

Исходное сообщение удаляется по собственному сроку хранения, раньше отчета. После этого эта конечная точка возвращает причину вместо исходного сообщения.

PUT/api/v1/tests/{slug}/locale

Изменяет язык резервирования, которое еще не было использовано. Для агента, который узнает, на каком языке читает его пользователь, уже после запроса адреса. Запрос отклоняется после поступления сообщения, потому что к тому времени анализ уже выполняется.

Попадание во входящиеБета

Отправьте одно сообщение на список тестовых адресов и посмотрите, куда оно попало в Gmail, Outlook, Yahoo и у других провайдеров: во «Входящие», «Промоакции» или «Спам».

Быстрый старт

  1. Создайте тест

    Отправьте POST-запрос к конечной точке placement. В ответ вы получите маркер и тестовые почтовые ящики.

    Запрос

    # 1. create a test
    curl -sX POST 'https://email-spam-tester.com/api/v1/placement' \
      -H 'Content-Type: application/json' \
      -d '{"public_results_accepted":true}'

    Ответ

    {
      "slug": "<slug>",
      "marker": "est-3f9a1c7e2b4d6a80c5e1f2d3",
      "status": "waiting",
      "deadline": "2026-10-31T12:30:00Z",
      "poll_after_seconds": 60,
      "results": [
        {"address": "<seed>", "provider": "gmail", "kind": "Gmail",
         "placement": "pending", "observed_at": null}
      ],
      "fleet": {
        "status": "observing",
        "results": [
          {"address": "<mailbox>", "provider": "yahoo", "available": true,
           "placement": "pending", "coverage": "pending"}
        ]
      }
    }
  2. Отправьте одно сообщение в каждый ящик

    Поместите маркер в тему и отправьте сообщение со своей обычной платформы сразу на все адреса.

    Запрос

    # 2. one message to every address, with the marker in the subject
    Subject: October invoice est-3f9a1c7e2b4d6a80c5e1f2d3
    To: <seed>, <mailbox>, ...
  3. Опрашивайте данные о папках

    Для каждого адреса заполняются данные о провайдере и папке. Выполняйте опрос, пока статус не перестанет быть waiting.

    Запрос

    # 3. poll for the folders
    curl -s 'https://email-spam-tester.com/api/v1/placement/<slug>'

    Ответ

    {
      "status": "complete",
      "received": 2,
      "total": 2,
      "results": [
        {"address": "<seed>", "provider": "gmail", "kind": "Gmail",
         "placement": "primary", "observed_at": "2026-10-31T12:04:11Z"},
        {"address": "<seed>", "provider": "gmail", "kind": "Google Workspace",
         "placement": "promotions", "observed_at": "2026-10-31T12:04:11Z"}
      ],
      "fleet": {
        "status": "finished",
        "results": [
          {"address": "<mailbox>", "provider": "yahoo", "available": true,
           "placement": "inbox", "coverage": "ok"},
          {"address": "<mailbox>", "provider": "outlook", "available": true,
           "placement": "spam", "coverage": "ok"}
        ]
      }
    }

Конечные точки

An optional test using public GMass seed inboxes and available project test mailboxes, alone or alongside the email score. Explain to the sender that GMass receives their email and publishes its subject, sender name and placement before creating a test. Use all test mailboxes for non-confidential test messages only.

GET /api/v1/placement/availability

Returns providers: the provider identifiers of currently healthy, admitted project mailboxes. No addresses or credentials are exposed. This read does not create a test or contact GMass. Actual recipients are allocated at creation and may differ as availability or capacity changes.

POST /api/v1/placement

Send JSON {"public_results_accepted":true}. Returns HTTP 201 with slug, marker, results (the seed addresses), deadline and expires_at. Limit: 20 tests per IP per UTC day.

For one-send combined testing, first reserve an email score address and include its score_slug in the placement creation JSON. Repeated creation for that score returns the same placement test. Send the marked email to the score address, every returned seed and every available fleet.results address; keep the main /t/<score_slug> report link. Creating a link after the score address was used or expired returns HTTP 409.

GET /api/v1/placement/by-score/{score_slug}

Read and refresh the placement run attached to the main email test. The response has the same format and polling limits as the standalone endpoint below. HTTP 404 means placement was not included or its stored results have been removed.

GET /api/v1/placement/{slug}

Use poll_after_seconds (normally 60 seconds) while the page is open. Upstream errors trigger a shared cooldown. Add the marker to the subject and send through the sender's normal platform to every seed. Observations are saved for 30 days. Collection ends after 30 minutes or when all seeds have results.

status: waiting, complete or timed_out. Each result has an address, provider, kind, placement and observed_at. Placement is primary, promotions, inbox, updates, social, forums, spam, unknown, pending or not_observed. Missing results do not mean Spam; Promotions is an inbox category. provider_error indicates an upstream outage without discarding saved observations. HTTP 404 means unknown, 410 expired, 429 quota exhausted, and 503 no test inboxes available at creation.

The optional fleet object contains independently collected project mailbox results, with status observing, settling or finished. Refresh every 30 seconds until it finishes, even when Gmail has completed. Each fleet result includes address, provider, available, placement, category and coverage. Exclude unavailable addresses from new sends; retain their saved observations. Category data may be unavailable even when the physical folder is known.

If GMass is unavailable at creation but project mailboxes can be allocated, provider is fleet and the top-level seed results are empty. Use fleet.results; do not interpret an empty Gmail list as successful delivery. Existing runs never gain new recipient addresses silently.

Проверка инфраструктуры

Один GET-запрос проверяет почтовую конфигурацию домена без отправки чего-либо, сохраняет результат и сообщает, что изменилось с момента вашего последнего запуска. Ключ не требуется. В cron приведённая ниже строка завершается с ненулевым кодом, если домен неисправен или его конфигурация существенно изменилась.

Быстрый старт

  1. Выполните один GET-запрос

    Передайте домен. ip добавляет ваши адреса отправки, а selector задает селекторы DKIM для чтения.

    Запрос

    curl -s 'https://email-spam-tester.com/api/v1/infra/check?domain=example.com&selector=mail&diff=true'
  2. Прочитайте результат

    ok служит ответом для скрипта, а sections показывает, какая часть завершилась с ошибкой.

    Ответ

    {
      "id": "ir_01JB8Y4T2M6K9QZ7H3V5N1XWDA",
      "domain": "example.com",
      "checked_at": "2026-10-31T12:00:00Z",
      "ok": false,
      "status": "fail",
      "score": 78,
      "coverage": {"answered": 7, "total": 8},
      "ips": [{"ip": "203.0.113.5", "sources": ["mx", "spf"], "managed": false}],
      "sections": {
        "dkim": {"status": "pass", "core": true, "findings": [], "data": {}},
        "ptr": {"status": "fail", "core": true, "findings": [], "data": {}}
      },
      "not_checked": [
        {"check": "dkim_signature", "reason": "needs_a_message"},
        {"check": "alignment", "reason": "needs_a_message"}
      ],
      "diff": {
        "baseline": {"id": "ir_01JB2...", "checked_at": "2026-10-24T12:00:00Z"},
        "first_run": false,
        "changed": true,
        "worsened": true,
        "status_from": "pass",
        "score_from": 100,
        "changes": [
          {"path": "dkim.key.mail.sha256", "section": "dkim", "kind": "removed",
           "severity": "critical", "effect": "worsened", "from": "9f2c...", "to": null}
        ],
        "not_compared": [
          {"path": "blocklist_ip.203.0.113.5.bl.spamcop.net.listed", "reason": "lookup_failed"}
        ]
      }
    }
  3. Добавьте в cron

    С diff=true каждый запуск сравнивается с предыдущим, а jq преобразует ответ в код завершения.

    Запрос

    # exits non-zero if the domain is broken or its setup changed
    curl -s 'https://email-spam-tester.com/api/v1/infra/check?domain=example.com&selector=mail&diff=true' \
      | jq -e '.ok and (.diff.changed | not)'
domainОбязательный. Принимает то же, что и инструменты: домен, URL, адрес электронной почты.
ipАдрес, с которого вы отправляете почту. Укажите параметр повторно, чтобы добавить другие, но не более 6.
selectorСелектор DKIM. Укажите параметр повторно, чтобы добавить другие, но не более 10. Каждый переданный селектор должен существовать, иначе раздел dkim получает fail.
heloИмя, которое ваш сервер указывает в HELO, сопоставляется с его PTR.
accountУказывает, для кого выполняется запрос. Обязателен при использовании ключа, который обслуживает много пользователей.
checksРазделы для запуска, разделённые запятыми. По умолчанию запускаются все.
diffЗначение true сравнивает этот запуск с вашим последним запуском для домена.
since7d, 12h или дата в формате ISO 8601. Сравнивает с вашим запуском, ближайшим к этому моменту в пределах 12 часов, а если такого нет, с последним запуском до него. Включает diff.
baselineid одного из ваших запусков, с которым нужно сравнить. Включает diff.
freshtrue позволяет пропустить 60-секундный кеш.

Чтение ответа

Завершённая проверка возвращает 200, а вердикт находится в теле ответа. status соответствует худшему результату обязательных разделов: spf, dkim, dmarc, ptr, blocklist_ip, blocklist_domain, mx и smtp. unknown в обязательном разделе считается warn. ok имеет значение true, когда status равен pass или warn. score принимает значения от 0 до 100 по обязательным разделам, которые вернули ответ, и равен null, когда из-за ошибок и unknown остаётся менее половины применимого веса. mta_sts, tls_rpt, bimi, dnssec, dane, ns и registration включаются в отчёт и сравниваются, но не влияют на ok или score.

Раздел может иметь статус pass, warn, fail, error (мы не смогли выполнить проверку), unknown (недостаточно данных) или skipped (не применимо). skipped не влияет на результат, а причина указывается в not_checked. dkim_signature и alignment присутствуют всегда, поскольку для них требуется реальное сообщение.

Что меняют ip и selector

PTR и списки блокировок относятся к адресам, поэтому для запуска нужны адреса. Используются переданные вами значения ip. Если их нет, берётся до четырёх адресов с ваших MX-хостов и из терминов ip4: и ip6: с одним адресом в корневой записи SPF. Адреса известного почтового провайдера помечаются как managed и не проверяются, а если после этого адресов не остаётся, ptr и blocklist_ip возвращают skipped. selector нельзя получить из DNS, поэтому при запуске проверяются переданный вами selector, значения, найденные вашими предыдущими запусками, и список распространённых имён. Если ничего не найдено, это ничего не доказывает, и dkim возвращает unknown. Если вы отправляете почту со своего сервера, передайте оба параметра.

Что изменилось

Каждая запись в diff.changes содержит path, kind (added, removed, changed), severity (critical, warning, info) и effect (worsened, improved, neutral). Только critical и warning устанавливают diff.changed, поэтому ротация ключа DKIM на ключ той же длины, новый адрес MX или обновлённый сертификат не поднимают тревогу в cron. diff.worsened следует значению effect любого изменения. При первом запуске сравнивать не с чем, и diff.first_run указывает на это.

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

Почему для запланированной проверки следует использовать ключ

Без ключа ваша история привязана к хешу вашего IP-адреса с ключом, поэтому она заканчивается при изменении адреса, а пользователи с одним адресом используют её совместно: запуск коллеги смещает вашу базовую линию. При использовании персонального API-ключа в Authorization: Bearer история привязывается к ключу. Запуски с ключом хранятся 365 дней и доступны только с этим ключом. Запуски без ключа хранятся 30 дней и доступны любому, у кого есть их id.

6 запросов в минуту и 50 в день на IP либо 30 и 500 на ключ. При превышении лимита возвращается ответ 429 с Retry-After. Идентичный запрос в течение 60 секунд обслуживается из кеша, помечается как cached: true, не создаёт запись о запуске и не учитывается. Для чтения сохранённых запусков разрешено 120 запросов в минуту на клиента. Ответ 503 с Retry-After означает, что выполняется слишком много проверок, или, при чтении сохранённых запусков, что хранилище недоступно. 401 означает неверный ключ. Ответ 422 содержит detail.code: invalid_domain, invalid_ip, invalid_selector, invalid_check, invalid_since, unknown_baseline или account_required.

Конечные точки

GET/api/v1/infra/check

Запускает проверку. Параметры указаны в таблице выше.

GET/api/v1/infra/runs/{public_id}

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

GET/api/v1/infra/domains/{domain}/runs

Ваши запуски для домена, сначала самые новые: идентификатор, время, статус, оценка и количество изменений. Принимает limit (от 1 до 100, по умолчанию 30) и before, идентификатор запуска.

GET/api/v1/infra/diff

То же сравнение между двумя сохранёнными запусками, ?from=<id>&to=<id>. Вам нужен доступ к обоим.

GET/api/v1/infra/checks

Каждый раздел с его весом, версией оценки и ограничениями.

Отдельные проверки

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

Быстрый старт

  1. Выберите проверку

    Выберите инструмент из списка ниже и передайте домен, адрес или IP, который он запрашивает.

    Запрос

    curl -s 'https://email-spam-tester.com/api/v1/tools/spf?domain=example.com'
  2. Проверьте статус и результаты

    Каждый инструмент возвращает статус и результаты. Последующие поля зависят от инструмента.

    Ответ

    {
      "tool": "spf",
      "query": {"domain": "example.com"},
      "checked_at": "2026-10-31T12:00:00Z",
      "duration_ms": 412,
      "status": "fail",
      "findings": [
        {"code": "spf.too_many_lookups", "level": "fail",
         "params": {"limit": 10, "count": 12},
         "message": "RFC 7208 §4.6.4 allows at most 10 DNS lookups, and this record needs 12, so receivers return permerror."}
      ],
      "record": "v=spf1 include:_spf.example.net ~all",
      "lookups": {"count": 12, "limit": 10, "void": 0}
    }

Конечные точки

Все они возвращают 200 со статусом и списком результатов проверки, каждый из которых содержит код и его параметры. Статус имеет значение pass, warn, fail или error, а инструмент, общий с проверкой инфраструктуры, также может вернуть unknown или skipped. Запрос, завершившийся по тайм-ауту, или список, отклонивший запрос, никогда не считается pass. Не более 30 запросов в минуту и 300 в день на один IP для всех инструментов; при превышении лимита возвращается 429 с Retry-After.

GET/api/v1/tools/spf

Запись SPF домена: её синтаксис, все пройденные include и redirect, а также количество DNS-запросов, которое всё дерево расходует из лимита в десять. Передайте ?domain=example.com.

GET/api/v1/tools/dmarc

Запись DMARC домена или его организационного домена, если у него нет своей записи: теги, политика и наличие согласия каждого внешнего адреса для отчётов принимать отчёты. Передайте ?domain=example.com.

GET/api/v1/tools/dkim

Ключ DKIM, опубликованный для селектора: существует ли он и декодируется ли, его тип и размер, а также флаги отзыва и тестирования. Передайте ?domain=example.com&selector=s1.

GET/api/v1/tools/blocklist

Адрес IPv4, адрес IPv6 или домен, проверенный по DNS-блоклистам, которые использует отчёт, с ответом каждого списка. Передайте ?target=203.0.113.5.

GET/api/v1/tools/mx

MX-записи домена в порядке, в котором их пробуют отправители, с адресами IPv4 и IPv6 каждого хоста. Сообщается о нулевом MX, домене без MX, хостах, которые являются IP-адресами или CNAME, и хостах, которые не разрешаются, а также о записях MTA-STS и TLS-RPT. Передайте ?domain=example.com.

GET/api/v1/tools/bimi

Настройка BIMI домена в четыре шага: политика DMARC, необходимая для BIMI, запись в default._bimi, логотип SVG, проверенный на соответствие профилю Tiny PS, и сертификат знака с его типом, доменами и сроком действия. Передайте ?domain=example.com и &selector= для селектора, отличного от default.

GET/api/v1/tools/ptr

PTR-записи адреса и проверка того, разрешается ли какое-либо из этих имён обратно в этот адрес. Неудачный запрос считается error; отсутствие записи считается fail. Передайте ?ip=8.8.8.8.

GET/api/v1/tools/mta-sts

MTA-STS-запись домена и файл политики, на который она указывает: режим, перечисленные хосты и все MX-хосты, не включённые в политику. Передайте ?domain=example.com.

GET/api/v1/tools/tls-rpt

TLS-RPT-запись домена и адреса, которые получают её отчёты. Передайте ?domain=example.com.

GET/api/v1/tools/dnssec

Проверка того, подписана ли зона домена, не подписана или повреждена, по её записям DNSKEY и DS. Некорректная подпись отличается от сбоя резолвера. Передайте ?domain=example.com.

GET/api/v1/tools/dane

TLSA-записи MX-хостов, сопоставленные с сертификатом, который предоставляет хост, если этот сертификат удалось прочитать. Передайте ?domain=example.com.

GET/api/v1/tools/smtp

STARTTLS и сертификат на первых двух MX-хостах: версия TLS, издатель, дата истечения срока действия, а также действительны ли цепочка и имя. Мы подключаемся только к хостам в указанном вами домене и пропускаем почтовых провайдеров, а один результат для каждого адреса повторно используется в течение 6 часов. Почта не отправляется. Передайте ?domain=example.com.

GET/api/v1/tools/ns

Серверы имён домена и наличие записи SOA в его зоне. Один сервер имён считается предупреждением. Передайте ?domain=example.com.

GET/api/v1/tools/registration

Дата окончания регистрации домена по данным RDAP. Если осталось менее 30 дней, это считается предупреждением. Для зоны без сервиса RDAP ответ имеет статус skipped. Передайте ?domain=example.com.

POST/api/v1/tools/header

Заголовки полученного сообщения, отправленные как JSON {"headers": "..."} или как text/plain: маршрут по переходам с задержками, TLS и рассинхронизацией часов, собственный Authentication-Results получателя, согласование доменов From, DKIM d= и Return-Path, а также заголовки DKIM, ARC, отписки и спам-фильтра. Всё после первой пустой строки отбрасывается без чтения. Заголовки обрабатываются в памяти и не сохраняются, не кешируются и не записываются в журнал.

Проверяйте домен каждую ночь.
Тестируйте письмо перед отправкой.

Общее для всех продуктов

Доступ, ключи, формат отчета, статусы, ошибки, а также OpenAPI и llms.txt для машин.

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

Её нет. Не нужно запрашивать ключ, задавать заголовок или создавать учётную запись. Полученный слаг и есть средство доступа: любой, у кого он есть, может прочитать этот отчёт, а остальные не могут его угадать.

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

Персональные ключи API

Everything above works without a key. A key is for automation platforms such as Zapier, where every user's calls come from the platform's servers and per-IP limits would be shared by all of them. With a key, limits count per key (50 tests a day, 3 with placement, 5 permanent mailboxes), the key's tests form a history, and the key can keep permanent mailboxes whose reports only it can read. Send the key as Authorization: Bearer est_live_… on any call on this page. The routes below also take account, a short name of your choosing ([A-Za-z0-9_-], up to 64 characters) that keeps separate lists under one key. GET /api/v1/installations/tests requires it; pass the same one on POST /api/v1/inbox so the test shows up there. The Zapier integration uses zapier.

POST /api/v1/keys

Send JSON {"email":"you@example.com"}. Returns HTTP 201 with key and email. The key is shown once; only its hash is kept. Asking again gives a new key and leaves the earlier ones working. Limit: 5 keys per IP per UTC day. The form on /zapier/ calls this.

GET /api/v1/keys/me

Returns email, key_prefix and created_at of the key in the header, or HTTP 401. Use it to check a key.

GET /api/v1/installations/tests

The key's tests, newest first: ?account=…&limit=50 (up to 100), and before=<slug> for the next page. Each item has slug, created_at, analysis_status (waiting or expired before an email arrived), score_ours, score_compat, placement and changes, the checks that moved since the previous test of the same sending domain. Read the full report at /api/v1/tests/{slug}.

POST /api/v1/installations/mailboxes

Send JSON {"domain":"example.com","account":"…"}. Returns the permanent mailbox of that sending domain: id, address, domain, state, daily_cap and created. HTTP 201 when it is new, 200 when it already existed, 409 when the key keeps as many mailboxes as it may. Subscribe the address to a newsletter or a sequence and every email that arrives is checked. GET on the same path with ?account=… lists them, and DELETE /api/v1/installations/mailboxes/{mailbox_id} stops one.

GET /api/v1/installations/mailboxes/{mailbox_id}/letters

The emails that arrived, oldest first, paged with after_id and next_after_id. settled=true ends the page before the first email still being checked, so paging never skips one. newest=true turns the order round, for a quick look at the latest; settled does nothing with it. Each has test_id, slug, received_at, analysis_status, score_ours, score_compat, subject, from_addr and kind.

GET /api/v1/installations/letters/{slug}

The report of one email in a permanent mailbox, the same JSON as /api/v1/tests/{slug} with report_url null: there is no public page for it. HTTP 410 once the report has expired.

Чтение отчета

Поля, содержащие ответ, в том порядке, в котором они, вероятно, вам понадобятся.

score_oursОт 0 до 100. Наша модель. Аутентификация и инфраструктура имеют наибольший вес, потому что они определяют доставку до того, как фильтр прочитает хотя бы слово текста.
score_compatОт 0 до 10. Воспроизводит показатель в стиле SpamAssassin, с которым уже привыкли сравнивать, поэтому отчет сопоставим с тем, что кто-либо видел в другом месте.
subscoresТа же шкала от 0 до 100 для каждого раздела: auth, infra_spam, content, compliance.
checks[]Все 42, каждый со статусом, выводом в одну строку, данными, на основании которых он был сделан, и тем, сколько баллов он стоил двум оценкам.
checks[].citationsИсточник результата проверки: раздел RFC, процитированный дословно, и страница, где Google указывает собственное требование. Подобрано вручную, а не сгенерировано, поэтому этим данным можно доверять.
fixes[]Что изменить, в каком порядке и сколько баллов дает каждое изменение. Прирост рассчитывается путем повторной оценки отчета, а не приблизительно.
completeFalse, если проверку не удалось выполнить. Непроверенный элемент никогда не считается пройденным, поэтому считайте оценку оптимистичной, пока это значение не станет true.
report_urlСтраница в удобном для чтения виде. Передайте человеку ее, а не стену JSON.

Статусы

Проверка имеет один из пяти статусов, и разница между двумя из них важнее, чем кажется.

passПроверка выполнена и не выявила проблем.
warnСтоит исправить. Снижает оценку.
failУхудшит доставляемость. Стоит больше баллов.
пропускНе применимо. Нет вложений для сканирования, нет HTML-части для оценки. Это не успешная проверка.
ошибкаНам не удалось это выяснить. Исключено из оценки и помечено, а не засчитано как успешная проверка.

analysis_status принимает значения received, analyzing, checks_ready, failed. ai_status принимает значения pending, running, ready, fallback, error. Детерминированный отчёт окончательно формируется при checks_ready; ai_status только добавляет план.

Что может вернуться

202Адрес зарезервирован, и сообщение ещё не поступило. Тело содержит адрес, срок действия и язык, поэтому вызывающая сторона, которая не создавала резервирование, всё равно может их отобразить.
404Такого идентификатора нет. Он либо никогда не существовал, либо резервирование было забыто.
410Срок действия адреса истёк до поступления сообщения.
409Вы попытались изменить язык после того, как сообщение уже поступило.
429Лимит бесплатных тестов для вашего адреса. Сейчас в этом сервисе нет лимита на пользователя; если он когда-либо будет установлен, в теле будет указано, когда он сбрасывается.

Четыре важных момента

Одно сообщение на адрес

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

Час на использование

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

Отправляйте с платформы

Тестирование кампании из личной учётной записи оценивает эту учётную запись. Почти всё в разделе аутентификации относится к инфраструктуре отправки, а не к тексту.

Повторите тест после исправления

Ожидаемые улучшения рассчитываются для каждого исправления отдельно и не суммируются. Второй отчёт покажет достоверный результат.

Для машин

GET/api/health

Проверка работоспособности. Без аутентификации, без побочных эффектов.

Сначала попробуйте вручную

Это занимает около минуты и показывает, что именно описывает JSON.

Получить тестовый адрес

Песочница.

Каждая конечная точка снабжена кнопкой, которая запускает запрос к рабочему сервису. Здесь нигде не нужен ключ, поэтому запрос, отправленный с этой страницы, является реальным: он резервирует реальный адрес и учитывается.

Попробовать в песочнице