Generated from Postwind commit a19b2e4 OpenAPI 0.1.0 synced

Deliverability checklist

This guide is in Russian; an English version is pending.

Что настроить, чтобы письма доходили до входящих, а не в спам. Нормативные источники: требуемые записи и их проверка — docs/spec/10-dns-adapters.md, «Требуемые записи» и «Верификация»; сетевые требования — docs/spec/13-deployment.md, «Сетевые требования для direct-доставки»; заголовки, DKIM и транспорты — docs/spec/06-delivery.md. Развёртывание — руководство.

Обозначения, как в docs/spec/10-dns-adapters.md: D — домен отправки (адрес From), B — bounce-поддомен (по умолчанию bounce.D, домен MAIL FROM), S — DKIM-селектор (по умолчанию pw1), H — хост web.public_url, T — tracking host (если задан).

1. Исходящие адреса (транспорт direct)

  • Исходящий TCP 25 с узлов доставки открыт у облачного провайдера (по умолчанию его часто блокируют — заявка на снятие).
  • У каждого адреса каждого пула ([smtp.outbound.pools.<name>]) есть hostname; PTR адреса → hostname, A/AAAA hostname → адрес (forward-confirmed reverse DNS). PTR ставит владелец адреса — хостер или облако; Postwind только проверяет. EHLO идёт с этим hostname.
  • Адрес поднят на интерфейсе узла доставки (или пул из одного адреса за NAT: ip = "", public_ip).
  • Адреса не в списках блокировок (Spamhaus и др.) — особенно новые адреса облака, у которых была чужая история.
  • Проверка ptr домена отправки — ok. Не ok даёт warning, а не failed: домен станет verified, но Gmail и Microsoft отклоняют письма без PTR; предупреждение видно в checks и в preflight кампании.

2. Требуемые DNS-записи домена отправки

Postwind считает набор записей сам по конфигу узла (web.public_url, пул домена, spf_include relay):

  • API: GET /api/v1/projects/{project_id}/domains/{domain_id}/records (и required_records[] в ответе на создание домена);
  • CLI на узле: postwind domain records <домен> — записи по строке, поля через табуляцию, для ручного ввода у провайдера (docs/spec/13-deployment.md, «postwind domain records»);
  • Porkbun: POST .../domains/{domain_id}/dns/apply ставит их сам (dns_provider = porkbun).
Запись Имя Содержание Проверка
TXT (SPF) B v=spf1 ip4:<адрес пула> ... [include:<spf_include relay>] -all spf_bounce
MX B 10 H mx_bounce
TXT (DKIM) S._domainkey.D v=DKIM1; k=rsa; p=<публичный ключ> dkim
TXT (DMARC) _dmarc.D v=DMARC1; p=none; rua=mailto:dmarc@D — только если записи ещё нет dmarc
CNAME T H tracking_cname (и tracking_tls при web.tls.mode = acme)
PTR каждый адрес пула hostname адреса ptr (warning)
  • Записи внесены; POST .../domains/{domain_id}/verify — домен verified. Кампанию запускает только verified-домен; узлы доставки перепроверяют его каждые dns.recheck_interval_hours (по умолчанию 6 h), и регресс блокирует новые запуски (docs/spec/10-dns-adapters.md, «Перепроверка по расписанию»).
  • После смены пула домена (PATCH ... ip_pool) или tracking_host — новые записи и снова verify: домен возвращается в pending.

SPF

  • SPF проверяется для домена MAIL FROM, то есть B, а не D: Postwind шлёт с VERP-адреса bounce+<token>@B. Запись на корне D Postwind не трогает и не требует.
  • Одна запись v=spf1 на B (две — mismatch, RFC 7208 разрешает одну); лишние механизмы допустимы. На B уже есть TXT, не начинающаяся с v=spf1, — conflict, Postwind её не перезаписывает.
  • Каждый адрес пула домена — свой ip4:/ip6:; для адреса за NAT — его public_ip.
  • Relay с spf_include (relays.<name>.spf_include, например amazonses.com) добавляет include: для каждого такого relay конфига — relay передаёт письмо с тем же MAIL FROM, поэтому его серверы должны быть в SPF B. Следите за пределом 10 DNS-запросов SPF (каждый include: их тратит).

DKIM

  • Запись S._domainkey.D с ключом, который Postwind сгенерировал для домена (RSA 2048, rsa-sha256, relaxed/relaxed, docs/spec/06-delivery.md, «Сборка письма»). Длинную TXT провайдер делит на строки сам; проверка склеивает их.
  • smtp.outbound.dkim_ed25519 = true — вторая запись с другим селектором (ed25519).
  • Relay с sign_dkim = true (по умолчанию): письмо подписывает Postwind ключом вашего домена; у relay свою подпись можно не включать. sign_dkim = false — письмо уходит без подписи Postwind.

DMARC

  • Запись _dmarc.D есть. Postwind создаёт p=none только если записи нет, и никогда её не меняет. Выравнивание проходит в relaxed-режиме: From — D, MAIL FROM и DKIM — поддомен B и домен D.
  • Отчёты rua кто-то читает. После нескольких недель чистых отчётов — p=quarantine, затем p=reject. Gmail и Yahoo требуют DMARC от массовых отправителей (от 5 000 писем в день).

MX bounce и входящий SMTP

  • B MX 10 H, и TCP 25 на адресе H доходит до подсервиса smtp.inbound (руководство, «Входящий SMTP»). Без этого отказы после приёма (DSN) и жалобы ARF не приходят, адреса не подавляются, репутация падает.

Tracking host

  • T CNAME H; при web.tls.mode = acme Postwind сам выпускает сертификат для T — проверка tracking_tls предупреждает, если его нет или он кончается раньше чем через 14 дней. При TLS на Ingress добавьте T в хосты и сертификат Ingress.

3. Отписка и жалобы

  • Ничего настраивать не нужно: каждое письмо кампании несёт List-Unsubscribe (ссылка one-click и mailto на unsubscribe@B) и List-Unsubscribe-Post: List-Unsubscribe=One-Click (docs/spec/06-delivery.md, «Сборка письма»). Нужны работающие web.public_url (HTTPS) и входящий SMTP.
  • Жалобы ARF приходят на fbl@B / abuse@B: подключите feedback loop провайдеров, где он есть (например, Yahoo CFL, Microsoft JMRP), с адресом на B.
  • Доля жалоб ниже 0,3 % (порог Gmail и Yahoo), лучше ниже 0,1 %. Hard bounce и жалоба подавляют адрес автоматически.

4. Прогрев IP

Новый адрес без истории получает низкие лимиты и спам-папку при резком объёме. В v1 прогрев ручной (docs/spec/13-deployment.md, «Сетевые требования для direct-доставки»): лимиты в конфиге, поднимаются вручную.

  • Лимиты на крупных получателей — [smtp.outbound.domain_limits."<домен>"]: messages_per_minute и max_connections на пару (исходящий адрес, домен получателя). Два адреса в пуле — двойной суммарный лимит. В Helm: config.smtp.outbound.domain_limits (пример — examples/single-node.yaml).
  • Скорость кампании — throttle_per_hour кампании (docs/spec/04-domain-model.md, «Campaign»).
  • Ориентир (не норма; следите за отказами и жалобами и замедляйтесь при росте): первые дни — сотни писем в день на адрес самым вовлечённым подписчикам; затем примерно удвоение объёма каждые 1–3 дня, пока не выйдете на рабочий объём за 4–8 недель. Пример для gmail.com на одном адресе: неделя 1 — messages_per_minute = 2, неделя 2 — 10, неделя 3 — 50, далее — по показателям.
  • Ответ 4xx с текстом про скорость (rate limit, too many, throttl, …) Postwind сам замедляет: скорость пары делится на два на 10 минут (docs/spec/06-delivery.md, «Адаптер direct»). Частые такие ответы — знак, что лимит в конфиге выше, чем позволяет репутация.
  • Наблюдение: Google Postmaster Tools (домен D), Microsoft SNDS (адреса), статистика Postwind по доменам получателей (GET .../stats/domains), события delivery.bounced, complaint.received.

5. Relay вместо direct

Если своих чистых адресов нет, исходящий 25 не открыть или PTR не поставить — шлите через relay (Amazon SES, Postmark, свой Postfix и т. п.): репутацией адресов занимается провайдер (docs/spec/06-delivery.md, «Адаптер relay»).

  • Секция [relays.<name>]: host, port, tls (starttls или implicit; учётные данные с tls = "none" — ошибка конфига), username и пароль (в Helm — secrets.relayPasswords), spf_include провайдера, sign_dkim = true.
  • Выбор транспорта: delivery.default_transport = "relay:<name>" для всей установки, settings.transport проекта или transport_override кампании. direct и relay можно сочетать: SPF B тогда содержит оба механизма.
  • Записи DKIM, DMARC и MX bounce те же: письмо по-прежнему от вашего домена с VERP MAIL FROM на B, отказы приходят на входящий SMTP Postwind.
  • Лимиты отправки провайдера (квоты SES и т. п.) — relays.<name>.max_connections и throttle_per_hour кампаний.

Copied from Postwind docs/ops/deliverability-checklist.md at commit a19b2e4.