DMARC от p=none до p=reject: инженерная выкатка без потери легитимной почты
DMARC не ломает почту в момент публикации записи — он ломает её, когда вы перескакиваете через этап. Разбираем сценарий выкатки на 6-10 недель: как использовать pct как вентиль, rua-отчёты как радар и sp для поддоменов, чтобы дойти до p=reject и не потерять ни одного легитимного письма.
EvilMail Team16 июля 2026 г.11 мин чтения
Почему домены теряют почту именно на reject, а не на none
Классический инцидент выглядит так. Приходит аудитор, требует «закрыть спуфинг», админ ставит p=reject, ставит галочку в отчёте и уходит на выходные. В понедельник выясняется, что биллинговая система, которая раз в месяц шлёт инвойсы через сторонний MTA без DKIM, полтора дня билась о reject. Письма не отбились с баунсом клиенту — они молча исчезли на стороне Gmail и Microsoft. Клиенты не заплатили, потому что не получили счёт. И никто не увидел ни одной ошибки в логах своего сервера, потому что отклонение произошло на чужой инфраструктуре.
Ключевое, что нужно понять до первой строчки в DNS: DMARC — это не фильтр контента, а политика поверх выравнивания (alignment) SPF и DKIM. Письмо проходит DMARC-проверку только если выполнено хотя бы одно из двух условий:
домен в конверте (return-path, он же envelope-from), по которому прошёл SPF, совпадает с доменом в заголовке From: — это SPF alignment;
DMARC p=none → p=reject: пошаговая выкатка с pct и мониторингом — EvilMail Blog
домен из подписи DKIM (тег d=), которая валидна, совпадает с доменом в From: — это DKIM alignment.
Достаточно одного aligned-механизма. Именно здесь кроется большинство «внезапных» отказов: у большинства ESP (Mailchimp, SendGrid, Amazon SES из коробки) SPF технически проходит, но по их собственному return-path вида bounces.sendgrid.net — а значит SPF не aligned с вашим From:. Если при этом DKIM не настроен или подписан их доменом, DMARC падает. На p=none это не видно. На p=reject это стоит вам почты.
Выравнивание бывает двух режимов. Relaxed (`r`) сверяет организационный домен — mail.evilmail.pro считается aligned с evilmail.pro. Strict (`s`) требует точного совпадения FQDN. По умолчанию — relaxed, и начинать нужно именно с него, иначе вы отрежете половину легитимных рассыльщиков ещё до того, как поймёте, кто они.
Нулевой этап: p=none как режим наблюдения, а не «выключено»
Первая запись не блокирует ничего. Её единственная задача — включить поток агрегатных отчётов (rua), чтобы вы увидели, кто вообще отправляет почту от вашего имени. Без этого шага вы слепы.
dns
_dmarc.evilmail.pro. IN TXT "v=DMARC1; p=none; rua=mailto:[email protected]; fo=1"
Разберём теги, которые реально имеют значение:
`v=DMARC1` — версия, всегда первая, обязательна.
`p=none` — политика: только наблюдать, применять к почте штатную доставку.
`rua=` — куда слать агрегатные (aggregate) XML-отчёты. Это ваш радар.
`ruf=` — куда слать forensic/failure отчёты по каждому письму. Не закладывайтесь на них. Google и Microsoft отключили отправку ruf ещё в прошлом десятилетии из-за приватности и GDPR, так что 99% провайдеров их просто не пришлют. Ставить ruf= можно, но строить процесс на нём нельзя.
`fo=1` — генерировать failure-отчёт, если *любой* механизм не прошёл (по умолчанию fo=0 — только если провалились *оба*). fo=1 информативнее, хотя, опять же, зависит от доброй воли принимающей стороны.
`adkim`/`aspf` — режим выравнивания для DKIM и SPF, по умолчанию relaxed.
Сколько держать этот этап: минимум 14 дней, а лучше один полный биллинг-цикл. Месячные рассылки — инвойсы, зарплатные квитки, отчёты — вылезают только раз в месяц. Просидите на none неделю — гарантированно пропустите какой-нибудь legacy-сервис и убьёте его на следующем этапе.
Как читать агрегатные отчёты и на какие цифры смотреть
Раз в сутки на адрес из rua= начнут прилетать сжатые XML от каждого крупного провайдера. Читать их руками не надо — структура тяжёлая. Внутри каждого отчёта по каждому источнику (source IP) лежит: количество писем (count), решение (disposition), результат SPF и DKIM плюс — самое важное — их alignment.
Метрика, по которой вы принимаете решение двигаться дальше, ровно одна: доля aligned-трафика (DMARC pass) по каждому источнику. Не общая — по каждому. Вам нужно дойти до состояния, когда идентифицировано ≥95% объёма и все легитимные источники дают pass хотя бы по одному механизму.
Инструменты парсинга:
dmarcian, Postmark DMARC (бесплатный), Valimail — SaaS: загружаете отчёты или делегируете rua на их адрес, получаете дашборд.
parsedmarc — open-source для self-hosted, складывает данные в Elasticsearch и рисует в Grafana.
bash
# self-hosted парсинг накопленных отчётов
parsedmarc -c /etc/parsedmarc.ini reports/*.xml
# → Elasticsearch, а дальше готовый дашборд в Grafana
Отдельно держите в голове «длинный хвост»: форвардинг (пользователь настроил пересылку на Gmail) и mailing lists. Они ломают SPF — return-path меняется на форвардящий сервер — но выживают на DKIM, потому что подпись едет вместе с телом письма. Если такой трафик в отчётах падает по SPF, но проходит по DKIM, это норма, трогать не нужно. Именно поэтому DKIM для DMARC важнее SPF.
Заклеиваем дыры: SPF, DKIM и выравнивание по каждому источнику
Прежде чем ужесточать политику, доведите каждый идентифицированный источник до pass. Типовые проблемы и фиксы:
ESP шлёт со своим return-path → SPF не aligned. Решение: включить custom return-path / CNAME-делегирование у провайдера (в SendGrid это «Domain Authentication», в SES — Custom MAIL FROM domain). После этого return-path становится поддоменом вашего домена и SPF выравнивается.
Забыли DKIM на транзакционном сервисе → добавьте селектор. Провайдер даёт вам CNAME или TXT вида selector1._domainkey, вы публикуете и проверяете:
Превышен лимит 10 DNS-lookup в SPF → SPF отдаёт permerror, и DMARC падает по SPF на всём трафике. Это жёсткий лимит спецификации, а не рекомендация. Лечится флаттенингом записи или, что правильнее, переходом на DKIM-only alignment — вы перестаёте полагаться на SPF для DMARC и держите выравнивание на DKIM.
Повторю тезис, потому что он определяет всю стратегию: DKIM переживает форвардинг, SPF — нет. При пересылке письма меняется return-path, SPF ломается, а DKIM-подпись остаётся валидной. Поэтому если приходится выбирать, куда вкладывать усилия, — вкладывайте в DKIM.
Этап quarantine с pct: контролируемый вентиль
Вот здесь — и только здесь — тег pct имеет смысл. Он позволяет применять политику не ко всему провалившемуся трафику сразу, а к его части.
pct=25 при p=quarantine означает: 25% провалившихся писем отправляются в спам, а оставшиеся 75% доставляются так же, как при none. Это управляемая проба. Вы поднимаете вентиль лестницей — 25 → 50 → 100, держа каждую ступень 5-7 дней и следя по rua, не выросло ли число отказов у легитимных источников. Если на pct=50 внезапно всплыл забытый сервис — откатываетесь на pct=25, чините DKIM, продолжаете. Ущерб ограничен половиной трафика этого источника, а не всем.
А теперь тонкость спецификации, на которой ошибается большинство. `pct` при `p=reject` работает не так, как вы думаете. При reject неотклонённая доля деградирует не до none, а до quarantine. То есть p=reject; pct=25 — это НЕ «отбиваем 25%, остальное доставляем». Это «отбиваем 25%, а оставшиеся 75% отправляем в спам». «Мягкого reject» через pct не существует. Настоящий контролируемый прогон делается на этапе quarantine — поэтому именно на quarantine вы и проводите всю лестницу pct, а на reject приходите уже с pct=100.
Переход на p=reject и защита поддоменов через sp
К reject вы переходите, когда quarantine с pct=100 отработал хотя бы неделю без единого легитимного отказа в отчётах. Финальная запись:
sp=reject — это отдельный контур для поддоменов. Без тега sp поддомены наследуют политику из p. Но sp позволяет задать им другую — и, что важнее, он автоматически накрывает все несуществующие поддомены, с которых почта не ходит вообще. Именно их любят использовать для спуфинга, потому что администраторы про них забывают. Для полностью неиспользуемого поддомена sp=reject уже закрывает исходящий спуфинг; добавьте ещё null MX (запись вида sub.evilmail.pro. IN MX 0 .), чтобы на него нельзя было даже принять почту.
adkim=s; aspf=s — переход на strict alignment. Ставить его нужно последним и только если инфраструктура это переживает: strict ломает большинство ESP, которые работают на поддоменах. Если сомневаетесь — оставайтесь на relaxed, безопасность DMARC от этого почти не страдает.
Для припаркованного домена, с которого вы вообще не шлёте почту, запись максимально простая — и её надо ставить сразу reject, никакой лестницы не нужно:
dns
_dmarc.parked-domain.example. IN TXT "v=DMARC1; p=reject;"
Бонус, ради которого многие и проходят весь путь: BIMI (ваш логотип в интерфейсе Gmail/Apple Mail) требует минимум p=quarantine, а на практике — p=reject. Так что дойти до конца имеет и маркетинговый смысл, не только защитный.
Чек-лист выкатки и типовые грабли
1.Опубликовать p=none с rua=, дождаться потока отчётов.
2.Собирать минимум 14 дней или полный биллинг-цикл.
3.Идентифицировать все источники, дойти до ≥95% узнанного объёма.
4.Починить SPF/DKIM по каждому источнику, довести каждый до pass.
5.p=quarantine; pct=25 → 50 → 100, шаг 5-7 дней, следить за rua.
6.p=reject, затем sp=reject, в самом конце — adkim=s; aspf=s.
7.Оставить мониторинг rua навсегда.
Грабли, на которых спотыкаются даже опытные:
Снятие мониторинга после reject. rua нужен постоянно: новые сервисы появляются, и вы должны видеть их до того, как они начнут падать.
Забытый TTL DNS. Заранее опустите TTL записи _dmarc до 300 секунд — если что-то пойдёт не так, откат до p=none займёт минуты, а не сутки.
Отсутствие плана отката. Держите готовую p=none-запись под рукой. При инциденте вы возвращаете наблюдение мгновенно, а разбираетесь потом.
Строгий `aspf=s`/`adkim=s` слишком рано. Он ломает большинство ESP. Начинайте с relaxed, strict — финальный штрих для тех, кто контролирует всю цепочку.
DMARC не опасен сам по себе. Опасен прыжок через этап. Пройдите лестницу с вентилем pct и радаром rua — и p=reject станет просто последней строкой в DNS, а не причиной пропавших инвойсов.