SPF, DKIM и DMARC: что это такое, зачем нужны и как правильно настроить
Вы настроили корпоративную почту, подключили SMTP-сервер и отправили письмо клиенту. Вместо доставки пришёл отказ. Или сервер письмо принял, но почтовый сервис стал относиться к сообщениям с этого домена с подозрением.
Почему так происходит? Адрес в поле «От» указан верно, сервер отвечает, логин и пароль подходят. Казалось бы, этого достаточно.
Получателю этого мало. Ему нужно понять, имеет ли отправитель право пользоваться доменом, кто подписал письмо и не изменилось ли оно после подписи. Строка, которую видит человек, на эти вопросы не отвечает: её можно поставить любую.
Для такой проверки домен публикует SPF, DKIM и DMARC. Давайте разберёмся, как эти три механизма связаны, чем они отличаются и как собрать их под те серверы, которые реально отправляют почту вашего домена. Готовая строка из чужой инструкции сюда не переносится: в записи оказываются ваши источники, а не чей-то учебный список.
Как письмо доходит до чужого сервера
Обычная отправка выглядит так. Программа на компьютере открывает соединение с вашим почтовым сервером, представляется логином и паролем и передаёт конверт: адрес отправителя для серверов, адрес получателя и само письмо. Ваш сервер уже со своего IP-адреса соединяется с почтовым сервером домена получателя и повторяет передачу. Тот сервер либо принимает письмо в очередь, либо отказывает.
Программа
| SMTP: логин, MAIL FROM, RCPT TO, текст письма
v
Ваш почтовый сервер
| новое SMTP-соединение уже с его IP
v
Сервер получателя
| смотрит DNS домена и решает, принять ли конверт
v
Очередь, отказ или раскладка по папкам
Получатель на входящем соединении видит IP вашего почтового сервера, не IP компьютера, на котором открыта программа. Если между программой и вашим сервером стоит прокси, для получателя он тоже не виден: наружу выходит сервер, который сдаёт почту дальше.
Дальше сервер получателя может посмотреть DNS. SPF отвечает на вопрос «этот IP есть в списке домена?». DKIM отвечает на вопрос «подпись в письме сходится с ключом в DNS и письмо по дороге не переписали?». DMARC смотрит, относятся ли успешные проверки к тому домену, который человек видит в поле «От». Как выглядит рассылка, в которой этих записей нет, разобрано в статье 8 ошибок начинающих email-арбитражников. Как MxToolbox показывает ошибки в этих записях, разобрано в статье MxToolbox – швейцарский нож email-маркетолога.
Принятие письма и папка «Входящие» — разные шаги. Сервер может ответить успехом и уже потом положить письмо в спам по своим правилам. Записи домена эту вторую раскладку не обещают.
Четыре сущности, которые участвуют в проверке
В одном сеансе одновременно существуют четыре сущности, и их легко смешать.
| Что | Где находится | Кто на это смотрит |
|---|---|---|
| Адрес в поле «От» | Заголовок письма, его видит человек | DMARC сравнивает с ним домен SPF и домен DKIM |
MAIL FROM | Команда SMTP, конверт. На этот адрес приходят отбои | SPF проверяет домен именно этого адреса |
| IP отправившего сервера | Соединение, с которого пришёл конверт | SPF ищет этот IP в политике домена |
| Домен в DNS | Зона, где лежат TXT-записи | Сервер получателя читает оттуда SPF, ключ DKIM и политику DMARC |
По стандарту SPF проверяет домен из MAIL FROM. Если конверт пустой, как у некоторых служебных отбоев, проверяется имя из HELO/EHLO. Поле «От», которое видит человек, в проверку SPF само по себе не входит. Это описано в RFC 7208.
Поэтому возможна такая картина: SPF для bounce@news.example.com проходит, а в письме человек видит anna@example.com. Для SPF это успех. Для вопроса «письмо правда от example.com» успеха ещё нет. Его добавляет DMARC, и только если домены согласованы.
Почему адреса в шапке недостаточно
Протокол SMTP с самого начала не требовал доказать, что автор имеет право поставить в письмо чужой адрес. Любой сервер может передать конверт, в котором в поле «От» указан anna@example.com, даже если к этому домену он не имеет отношения. Для человека письмо выглядит как письмо Анны. Для сервера Анны это чужая отправка, о которой он не просил.
Отсюда практические проблемы. Получатели перестают верить адресу. Мошеннические письма приходят «от банка» и «от директора». Честные письма компании теряются среди подделок, и чужой сервер уже не отличает рассылку фирмы от подделки с тем же адресом. Когда подделка начинает получать отказы и жалобы, страдает имя домена, даже если настоящий сервер компании в этот час ничего не отправлял.
SPF появился, чтобы домен мог опубликовать список разрешённых отправителей. DKIM появился, чтобы можно было проверить целостность письма и домен подписи, даже если письмо ушло не с того IP, который смотрит SPF, или прошло через пересылку, сохранившую подпись. DMARC появился, потому что успех SPF или DKIM сам по себе не обязан относиться к адресу, который видит человек. Политика DMARC связывает проверку с полем «От» и сообщает получателям, чего домен от них ждёт: только отчёт, карантин или просьбу отклонить письмо.
Одного механизма мало. Обычная пересылка уводит письмо на чужой IP, и SPF исходного MAIL FROM часто уже не сходится, хотя текст письма ваш. Пересыльщик может переписать адрес конверта по схеме SRS: тогда SPF проходит для домена пересыльщика, но этот успех относится к пересыльщику, а не к исходному полю «От». DKIM сохраняет подпись исходного домена, если по дороге не менялись тело и те заголовки, которые входили в подпись. Дописанная тема или дисклеймер в подписанной части подпись ломают. DMARC смотрит на итог: нужен хотя бы один успех, согласованный с доменом, который видит человек. Подпись чужого домена при вашем адресе в шапке этого не даёт, а политика DMARC без рабочих SPF и DKIM не на что опереться.
SPF
SPF — это TXT-запись в DNS домена. Она начинается с v=spf1 и перечисляет механизмы. Сервер получателя берёт домен из MAIL FROM, запрашивает TXT, находит политику и проверяет IP входящего соединения сверху вниз. Первое совпадение с квалификатором решает результат. Если не совпало ничего, результат neutral, кроме случая, когда в конце стоит механизм all: он совпадает с любым IP.
Запись публикует владелец зоны. Программа рассылки её не создаёт.
Как выглядит проверка
- Из конверта берётся домен, например
example.com. - Запрашиваются TXT-записи
example.com. - Среди них должна быть одна, начинающаяся с
v=spf1. Вторая такая же запись — уже ошибкаpermerror. - Механизмы читаются слева направо.
ip4иip6сравниваются с IP соединения без дополнительного DNS-запроса.a,mx,include,existsиredirectпорождают запросы. - Совпавший механизм возвращает результат. Если список кончился без
allи без совпадения, результатneutral.
Квалификаторы
Перед механизмом может стоять знак. Если знака нет, подразумевается +.
| Знак | Результат | Что это значит для получателя |
|---|---|---|
+ | pass | IP разрешён. Плюс обычно не пишут |
- | fail | IP не разрешён. Получатель может отказать, но сам SPF его к этому не обязывает |
~ | softfail | IP не в списке, но домен просит относиться мягче, чем к -all |
? | neutral | Домен не высказывает мнения об этом IP |
-all в конце записи означает: всё, что не перечислено выше, получает fail. ~all оставляет softfail. ?all почти ничего не запрещает. +all разрешает слать кому угодно и делает запись бессмысленной для защиты домена.
Это результаты проверки, а не команда «положите письмо в спам». Как поступить с fail, решает уже сервер получателя и, если она есть, политика DMARC. Крупные почтовые службы fail учитывают. Протокол при этом не обещает одинаковую реакцию у всех.
Механизмы, которые реально используют
ip4:203.0.113.30 разрешает один адрес. ip4:203.0.113.0/24 разрешает сеть. То же для ip6.
a разрешает IP, на который указывает A-запись домена. a:mail.example.com берёт адрес указанного имени. mx разрешает серверы из MX-записей. Оба делают DNS-запрос. Их имеет смысл ставить, когда почта действительно уходит с этих адресов, а не «на всякий случай».
include:_spf.mailhost.example запускает отдельную проверку политики другого домена. Если у того домена результат pass, он становится pass и здесь. Если там fail, обработка вашей записи продолжается дальше, а не заканчивается отказом. Если включённая политика сломана (permerror) или её нет, ошибка может всплыть уже у вас. Поэтому include копируют из инструкции почтового сервиса целиком, а не собирают по памяти.
redirect= — не механизм, а модификатор. К нему переходят, если ни один механизм текущей записи не совпал. Им пользуются, когда вся политика живёт в другом месте и провайдер прямо просит redirect. Для нескольких своих серверов понятнее явный список и include, а не цепочка перенаправлений.
exists и ptr в обычной настройке корпоративного домена не нужны. ptr в RFC 7208 оставлен как дорогой и ненадёжный механизм, его не рекомендуют.
all ставится последним. После него другие механизмы уже не читаются.
Одна политика и ошибка permerror
На имя должна приходиться одна запись SPF. Две TXT-записи, каждая из которых начинается с v=spf1, дают permerror: получатель не обязан угадывать, какая из них верная. Отдельная TXT для подтверждения сайта, которая не начинается с v=spf1, рядом жить может.
Одна логическая запись иногда передаётся несколькими строками в кавычках внутри одного TXT. DNS их склеивает. Это по-прежнему одна запись. Ошибкой будет именно два независимых TXT с двумя политиками.
permerror также возникает при синтаксической ошибке и при превышении лимита DNS-запросов.
Лимит в десять запросов
Проверка идёт слева направо и останавливается на первом совпавшем механизме. Всё, что стоит правее, для этого письма уже не вычисляется и в лимит не попадает.
RFC 7208 ограничивает число механизмов и модификаторов, которые во время конкретной проверки делают DNS-запрос: не больше десяти, включая вложенные include. Считаются include, a, mx, ptr, exists и redirect, и только те из них, до которых проверка реально дошла. ip4, ip6 и all запроса не делают.
Верный ip4 в начале записи поэтому закрывает этот адрес, даже если дальше в политике тяжёлые include. permerror появляется, когда совпадения ещё нет, а проверяющая сторона уже дошла до одиннадцатого DNS-механизма. Стоящий ещё правее правильный ip4 в этом проходе уже не рассматривается: очередь до него не дошла.
Вложенность считается целиком. Один ваш include — это один запрос плюс запросы внутри политики провайдера, если этот include вообще пришлось вычислять. Три сервиса легко подходят к десяти.
Пустые ответы DNS считаются отдельно. Пустым считается запрос, который вернул «имени нет» или ответ без записей нужного типа. RFC 7208 рекомендует обрывать проверку с permerror после двух таких ответов. Реализация может сделать порог настраиваемым, рекомендуемое значение по умолчанию — два. Обязательный предел при этом остаётся прежним: десять DNS-механизмов за проверку. Предел пустых ответов — отдельная рекомендация, которую многие проверяющие всё же применяют. На живом домене её не проверяют методом «добавим ещё пять include».
Несколько источников на одном домене
Если с домена пишут корпоративная почта, форма на сайте и отдельный SMTP для рассылок, в политике должны быть все три источника. Пропущенный IP получает fail, хотя логин на сервере успешный и письмо ушло.
Порядок такой: сначала конкретные свои ip4/ip6, затем include сервисов, в конце один all. Дублировать одно и то же и через ip4, и через include того же сервиса не нужно: лишний запрос тратит лимит и ничего не уточняет.
DKIM
SPF привязан к IP соединения. Если письмо ушло с разрешённого сервера, а потом его переслал другой сервер, у получателя IP уже чужой, и SPF исходного домена не сходится. Подпись DKIM едет внутри письма. Она проверяется по DNS домена, который указан в подписи, и не зависит от того, какой IP был у последнего SMTP-шага.
Подпись не заменяет список серверов. Она отвечает на другой вопрос: это письмо подписал держатель приватного ключа домена, и подписанные части с тех пор не менялись.
Пара ключей
На сервере отправки хранится приватный ключ. В DNS публикуется только публичный. Сервер получателя берёт публичный ключ, считает подпись заново и сравнивает с той, что лежит в заголовке DKIM-Signature. Приватный ключ в DNS не кладут: кто его прочитал, тот может подписывать письма домена.
Ключ создаёт тот, кто подписывает: почтовый сервис, ваш SMTP или оба, если подписывают разные серверы. Программа, которая только передаёт готовое письмо на SMTP, ключ обычно не генерирует. Его выпускают в панели сервиса или на самом сервере отправки, а в DNS переносят публичную часть.
Селектор
У домена может быть несколько ключей. Селектор — это имя конкретного ключа. Запись живёт по адресу:
selector._domainkey.example.com
Если селектор называется send, запрос идёт на send._domainkey.example.com. В подписи тот же селектор указан в теге s=. Несовпадение имени в DNS и s= в письме означает, что получатель ищет ключ не там.
Селекторы как раз позволяют сменить ключ, не ломая старый в ту же секунду: новый сервер подписывает новым селектором, старые письма ещё проверяются старым, затем старую запись убирают.
Как выглядит запись
Публичный ключ — TXT примерно такого вида:
v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
v=DKIM1 обозначает запись ключа. k=rsa — алгоритм ключа; если тег опущен, по RFC 6376 подразумевается RSA. p= — сам публичный ключ в base64. Пустой p= означает отозванный ключ.
Длинный ключ иногда разбивают на несколько строк в кавычках внутри одного TXT. Это нормально, если зона склеивает их в одну запись без лишних пробелов и переносов внутри base64.
Пример выше обрезан. В зону кладут ключ, который показал ваш сервер, а не учебный фрагмент.
Что стоит в заголовке письма
В исходнике принятого письма появляется заголовок DKIM-Signature. Из него для сверки с DNS важны два тега:
d=— домен, чей ключ нужно взять и чей домен потом сравнивает DMARC;s=— селектор, то есть левая часть имени в DNS.
Остальные теги описывают, как считали подпись: h= перечисляет подписанные заголовки, bh= — хеш тела, b= — сама подпись, a= — алгоритм. Если после подписания изменить тему, адрес «От» или тело, а эти части входили в подпись, проверка перестаёт сходиться. Так и должно быть: подпись фиксирует содержимое. Заголовки отписки ящик предлагает своим одним кликом, когда действующая подпись их покрывает.
Поэтому трекер, который дописывает в письмо пиксель уже после подписи, или шлюз, который переписывает тему, ломает DKIM, хотя отправитель всё подписал правильно. Подпись должна ставиться на том сервере, который выпускает окончательный вид письма.
Пересылка, которая не трогает подписанные поля, подпись сохраняет. Пересылка, которая дописывает тему «Fwd:» в подписанный заголовок, её ломает. Для таких промежуточных серверов существует отдельный механизм цепочки подписей, ARC, описанный в RFC 8617. На первую настройку своего домена он не влияет: сначала должен подписывать ваш собственный сервер.
Как посмотреть подпись у себя
Отправьте письмо с боевого сервера на ящик, где можно открыть исходник. Найдите DKIM-Signature. Сверьте d= с доменом, который хотите защищать, и s= с именем, которое создали в DNS. Затем отдельно запросите TXT по имени s._domainkey.d. В ответе должен быть тот же публичный ключ, которым подписывает сервер, без обрезки и без ключа от другого селектора.
Пока исходник письма не показывает DKIM-Signature, публиковать ключ в DNS нечего проверять: сервер отправки ещё не подписывает.
DMARC
SPF может пройти для домена конверта, а DKIM может пройти для домена подписи. Человек при этом смотрит на другой адрес. DMARC, в действующей редакции RFC 9989, требует согласования: хотя бы одна успешная проверка должна относиться к домену из поля «От». И публикует политику, чего домен просит у получателя, если согласования нет.
Запись одна на домен и лежит по фиксированному имени:
_dmarc.example.com
Согласование, или alignment
Сравниваются домены, не IP.
Для ветки SPF берётся домен из MAIL FROM, и только если SPF для этого домена дал pass. Отдельный успешный результат проверки HELO сюда не подставляется. Если обратный путь пустой, SPF сам определяет проверяемый адрес как postmaster на имени из HELO, и уже этот домен может участвовать в согласовании. Для DKIM берётся домен из d= у подписи, которая прошла проверку. Оба сравниваются с доменом в поле «От».
Режим по умолчанию мягкий, r. В мягком режиме домены согласованы, если у них общий организационный домен. news.example.com и example.com в мягком режиме сходятся. В строгом режиме, s, имена должны совпасть полностью, и news.example.com против example.com уже не сходится.
Режим задаётся отдельно: aspf=r или aspf=s для SPF, adkim=r или adkim=s для DKIM. Если тег опущен, действует мягкий режим.
Успех DMARC наступает, когда SPF дал pass и домен согласован, или DKIM дал pass и домен согласован. Достаточно одного. Второй может отсутствовать или не сойтись. Если оба прошли, но ни один не согласован с полем «От», для DMARC это неуспех: проверки относятся к чужим доменам.
Softfail SPF (~all) для DMARC не считается pass. Pass — это именно pass.
Политики
p= говорит, чего домен просит у получателей, если DMARC не прошёл.
| Значение | Просьба к получателю |
|---|---|
p=none | Не менять судьбу письма из-за DMARC, но можно прислать отчёт |
p=quarantine | Отнестись к неуспеху как к подозрительному: чаще это карантин или спам |
p=reject | Считать такой провал ясным признаком, что домен использован неправомерно, и просить отклонить письмо |
Это опубликованная просьба домена, а не команда, которую каждый сервер обязан исполнить одинаково. RFC 9989 прямо оставляет окончательное решение принимающей стороне. Получатель может принять письмо и при p=reject, если у него есть другие основания. И наоборот: отклонять только потому, что в DNS написано reject, стандарт не разрешает. Без дополнительного разбора такое письмо следует обработать как quarantine. Крупные сервисы политику учитывают, но прибавляют к ней свою картину потока.
Параметра pct, который в прежней спецификации просил применить строгую политику к проценту писем, в RFC 9989 больше нет. Промежуточные проценты на практике исполнялись по-разному, и новую настройку на них не строят.
Вместо доли потока появился тестовый режим t. По умолчанию t=n: опубликованная политика применяется как написана. t=y просит получателя, который понимает этот тег, применить политику на одну ступень мягче. При p=quarantine это none, при p=reject это quarantine. То же снижение действует для sp и np. Отчёты при t=y продолжают собираться, поэтому в сводке видно, что строгая политика поймала бы. На p=none тег ничего не меняет. Долю писем он не выбирает: смягчение, если получатель его понял, относится ко всему потоку. Часть промежуточных серверов при t=y может ещё и переписать поле «От». Если получатель тега не знает, он его пропускает. Незнакомый тег по стандарту пропускают. Сервер, который ещё живёт по прежней спецификации, увидит p=reject и не увидит просьбу смягчить его. Поэтому t=y не заменяет спокойный переход через none и quarantine.
sp — политика для существующих поддоменов организационного домена. На сам домен, где опубликована запись, она не действует. np — отдельная политика для поддоменов, которых в DNS нет. Если np не задан, для несуществующих имён берётся sp, а если нет и его — p. Обычному домену без отдельной политики для поддоменов достаточно p: он и распространяется вниз. np имеет смысл, когда вымышленные имена вроде случайного поддомена нужно просить обрабатывать строже, чем реальную почту. Получатель, который тега не знает, снова опирается на sp или p.
Сразу ставить reject не стоит. Пока не видно, кто легально пишет от домена, строгая политика заденет и рассылку, и форму сайта, и почту коллег, если их источник забыли внести в SPF или они не подписывают DKIM.
Отчёты
rua=mailto:dmarc@example.com просит присылать сводные отчёты. Формат описан в RFC 9990. В отчёте агрегаты за период: обнаруженная политика, сколько сообщений, какой IP и какие домены участвовали, результаты SPF и DKIM, было ли согласование, какое решение принял получатель. Это XML, обычно не реже раза в сутки у тех, кто отчёты шлёт, а не письмо о каждом отказе. По сводке как раз видно забытый сервис: незнакомый источник с устойчивым fail.
Присылают такие отчёты не все. RFC 9989 рекомендует их отправлять, но прямо называет причины отказа: нехватка ресурсов, местный запрет делиться данными и приватность. Отсутствие отчёта от конкретного сервиса не означает, что у него ваша почта проходит.
ruf= просит отчёты об отдельных неудачах. Их формат — в RFC 9991. Стандарт разрешает получателю их слать, но не обязывает. В таком отчёте могут оказаться адрес, служебные заголовки и даже содержимое письма, поэтому многие крупные операторы их не отправляют или сильно вычищают. Для первой настройки нужен rua и ящик, который эти сводки реально кто-то читает.
Адрес в rua на том же домене принимается просто. Адрес на другом домене должен быть разрешён отдельной записью в DNS того домена, иначе отчёты могут не прийти. На старте проще ящик вида dmarc@example.com внутри своего домена.
Как ужесточать
Практический порядок, который не вытекает из протокола как единственный законный, но бережёт живую почту:
- Составить полный список живых источников, а не только того сервера, с которого ушло тестовое письмо. В него входят корпоративная почта, SMTP и рассылки, сайт и формы, CRM, транзакционные сервисы и любой сторонний сервис, который ставит ваш домен в поле «От».
- Собрать SPF так, чтобы эти источники давали pass, когда проверка до них доходит.
- Включить подпись DKIM на каждом сервере, который выпускает окончательный вид письма, и убедиться, что
d=совпадает с доменом в поле «От» или согласован с ним. Дляp=rejectстандарт требует не опираться на один SPF: у писем должна быть действительная подпись DKIM. Иначе пересылка и ранний отказ по SPF оставят домен без подтверждения. - Опубликовать
p=noneиrua. Читать сводки тех получателей, которые их присылают. Несколько дней активного потока могут показать забытый сервер. Этого мало, чтобы объявить домен готовым: один удачный тест не проходит через CRM, форму сайта и рассылку прошлой недели. Для домена, с которого люди ведут обычную переписку, RFC 9989 советует продержатьp=noneне меньше месяца, затем столько жеp=quarantine, и сравнить, как получатели распорядились почтой. - Источники из отчётов либо внести в SPF и DKIM, либо признать чужими.
- Перейти к
quarantine, когда известные легальные потоки стабильно дают согласованный pass.t=yна этом шаге можно поставить рядом с новой политикой, чтобы понимающий её получатель применил ступень мягче, а сводка показала, кого политика поймала бы. Сервер, который тег игнорирует, применитquarantineсразу, поэтому перед тегом уже должен быть чистый список источников. - Перейти к
reject, когда за длинный период сводок легальная почта проходит и по SPF, и по DKIM с согласованием. Одно письмо сdmarc=passэтого не доказывает.
Протокол не заставляет проходить эти ступени. Он позволяет опубликовать reject в первый день. В этот день списка своих отправителей ещё нет, а часть получателей начнёт учитывать политику сразу.
Как три результата складываются
В таблице домен в поле «От» — example.com. «Согласован» значит: домен проверки сходится с ним в выбранном режиме alignment.
| SPF | DKIM | Согласование с полем «От» | DMARC |
|---|---|---|---|
| pass | нет подписи или fail | SPF согласован | pass |
| fail или softfail | pass | DKIM согласован | pass |
| pass | pass | оба не согласованы | fail |
| pass | fail | согласован только SPF | pass |
| fail | fail | согласовано не с чем | fail |
Отдельные сценарии, которые по этой таблице обычно читают неверно.
SPF прошёл, DKIM нет. Для этой передачи DMARC сходится, если домен MAIL FROM согласован с полем «От». Письмо при этом не защищено подписью: пересылка с другого IP может потерять и SPF. Домен, который собирается публиковать p=reject, на одном SPF останавливаться не может: стандарт требует действительную подпись DKIM.
DKIM прошёл, SPF нет. Для DMARC тоже хватает, если d= согласован. Так бывает у пересланного письма. Для прямой отправки с вашего сервера SPF всё равно стоит довести до pass: часть получателей смотрит на него ещё до DMARC.
Оба механизма прошли, согласования нет. Типичный случай: конверт и подпись принадлежат mailer.example.net, а человек видит example.com. Зелёные pass относятся к другому домену. DMARC для example.com не выполнен. Лечится это не «ещё одной галочкой», а тем, чтобы хотя бы один успешный механизм был про домен из поля «От»: либо MAIL FROM на @example.com, либо подпись d=example.com.
Оба не прошли. Для DMARC это fail: ни одна ветка не дала pass с согласованием. p=reject просит получателя считать такое использование домена неправомерным. Примет ли он письмо, решит уже он сам, вместе с остальным контекстом. p=none просит судьбу письма из-за DMARC не менять. Само письмо от отсутствия политики не становится доверенным.
Один pass без второго не означает, что домен «полностью настроен». Он означает, что для этой конкретной передачи DMARC сошёлся одним способом. Вторая проверка может быть сломана и всплывёт на другом маршруте: другая пересылка, другой сервер, письмо без подписи.
Настройка домена с нуля
Ниже схема для одного домена example.com. Адреса 203.0.113.0/24 взяты из диапазона для документации, имя example.com для этого и зарегистрировано в стандартах как пример. В свою зону их подставлять нельзя. Подставляются ваши IP и тот include, который написан в кабинете вашего почтового сервиса.
Условное разделение такое:
- корпоративные ящики обслуживает отдельный почтовый сервис, он просит
include:_spf.mailhost.example; - сайт на своём сервере
203.0.113.20сам отправляет письма с форм; - рассылки уходят через отдельный SMTP
203.0.113.30; - в поле «От» у всех трёх потоков домен
example.com.
_spf.mailhost.example здесь выдуман как место под настоящую инструкцию сервиса. Если сервис дал другой include или просил redirect, берётся его текст.
Сначала список источников
Пока список неполный, запись собирать рано. В него входят не только ящик, с которого вы входите в программу рассылки, но и всё, что ставит ваш домен в поле «От»:
- сервис корпоративной почты;
- сайт, если формы уходят с него, а не через тот же сервис;
- SMTP для кампаний;
- бухгалтерия, CRM, тикеты, факсы в почту, если они подписывают письма вашим доменом.
IP смотрят на стороне того сервера, который открывает соединение с внешним миром. IP офисного компьютера сюда не попадает, если компьютер только логинится на SMTP.
SPF
Для схемы выше запись домена может выглядеть так:
v=spf1 ip4:203.0.113.20 ip4:203.0.113.30 include:_spf.mailhost.example -all
Два ip4 стоят первыми: сайт и рассылочный SMTP совпадают без DNS-запроса, и тяжёлый include для этих писем уже не вычисляется. Корпоративная почта с этих адресов не уходит, поэтому проверка доходит до include и тратит запросы внутри политики сервиса. -all помечает любой другой IP как fail.
Если сайт на самом деле шлёт формы через корпоративный сервис, его IP в записи не нужен: источник уже внутри include. Лишний адрес не ломает проверку, но врёт о том, кто имеет право слать.
После публикации отправляют по одному письму каждым источником и смотрят, что SPF для них pass. Письмо с домашнего ящика, которого нет в списке, должно получить fail. Это и есть проверка, что -all работает.
DKIM
Корпоративный сервис обычно сам показывает селектор и TXT, который нужно создать. Его публикуют как есть.
Рассылочный SMTP, если он ваш, подписывает своим ключом. Селектор в этом примере — send. Тогда в DNS:
send._domainkey.example.com TXT "v=DKIM1; k=rsa; p=..."
p= берётся из публичного ключа этого сервера. В подписи исходящего письма должны быть d=example.com и s=send. Если сервис корпоративной почты подписывает селектором google или своим, это вторая запись имя._domainkey, она не мешает первой.
Пока рассылочный сервер не умеет подписывать, прямая отправка может пройти DMARC за счёт согласованного SPF. На пересылке этой опоры уже нет. Домен с p=reject стандарт просит не оставлять на одном SPF.
DMARC
Первая запись:
_dmarc.example.com TXT "v=DMARC1; p=none; rua=mailto:dmarc@example.com; aspf=r; adkim=r"
p=none ничего не блокирует. rua начинает копить сводку. Мягкое согласование разрешает поддомену сойтись с основным доменом; если вся почта идёт ровно с example.com, строгий режим тоже сойдётся, но включать его есть смысл после того, как отчёты чистые.
Ящик dmarc@example.com должен существовать. Отчёты приходят не сразу и не от всех получателей в первую минуту.
Когда сводки за длинный период не показывают легальных fail по всем известным источникам, политику меняют на p=quarantine, затем на p=reject. Меняется тег политики. SPF и согласованный DKIM к этому моменту уже должны проходить на боевой почте, иначе ужесточение заденет свои же письма. Одно тестовое письмо с pass этот период не заменяет.
Как проверить, что получилось
Проверяют и DNS, и реальное письмо. Запись в панели DNS ещё не значит, что её видит чужой резолвер: у зоны есть время обновления.
Запросы к зоне, в обозначениях этого примера:
nslookup -type=TXT example.com
nslookup -type=TXT send._domainkey.example.com
nslookup -type=TXT _dmarc.example.com
В первом ответе одна строка v=spf1 с вашими механизмами. Во втором v=DKIM1 и полный p=. В третьем v=DMARC1 и тот p=, который вы хотели на этом этапе. Если ответ пустой, смотрят имя: для DMARC обязателен префикс _dmarc, для ключа обязателен ._domainkey.
Затем письмо с рассылочного сервера на ящик, где открывается исходник. В заголовках ищут Authentication-Results. Условный успешный результат:
Authentication-Results: mx.receiver.example;
spf=pass smtp.mailfrom=example.com;
dkim=pass header.d=example.com header.s=send;
dmarc=pass header.from=example.com
Строки читаются так.
spf=pass и smtp.mailfrom=example.com — проверка SPF домена конверта прошла, IP соединения был разрешён. Если здесь fail или softfail, IP этого сервера не покрыт записью, либо домен конверта не тот, чью запись вы правили.
dkim=pass, header.d=example.com, header.s=send — подпись сошлась с ключом селектора send. Если fail, ключ в DNS не тот, селектор другой или письмо изменили после подписи. Если заголовка DKIM в результате нет, сервер письмо не подписал.
dmarc=pass и header.from=example.com — хотя бы один из успехов выше согласован с доменом в поле «От». dmarc=fail при двух pass почти всегда означает, что оба успеха про другой домен.
Формат этого заголовка описан в RFC 8601. Имя сервера и порядок методов у разных получателей отличаются, теги smtp.mailfrom, header.d и header.from остаются ориентиром.
Такое письмо подтверждает один маршрут: этот сервер, этот конверт, эту подпись. Пока нет даже его, рано говорить, что домен проходит проверку у получателя. Для перехода на reject нужен ещё и обзор остальных источников в сводках, а не только этот заголовок.
Типичные ошибки
Две записи SPF. В зоне два TXT с v=spf1, часто после переноса к новому хостеру старую не удалили. Симптом: permerror у всех писем, в том числе у тех, чей IP есть в обеих записях. Решение: оставить одну политику, в которую собраны все нужные источники.
В записи нет IP рассылочного SMTP. Корпоративный include на месте, кампании уходят с 203.0.113.30, которого в политике нет. Симптом: почта коллег проходит SPF, письма кампании получают fail или softfail, в отказе часто 5.7.1. Решение: добавить IP того сервера, который реально открывает внешнее соединение, и отправить тест.
Чужой или урезанный include. Из инструкции сервиса взяли домен без _spf или оборвали цепочку. Симптом: permerror или fail у почты, которая раньше уходила через этот сервис. Решение: вставить include дословно из текущей справки сервиса и пересчитать, не вышел ли общий объём запросов за десять.
Слишком много DNS-запросов. Несколько сервисов, у каждого тяжёлый include, плюс a и mx «для запаса», и всё это стоит раньше адреса, который должен совпасть. Симптом: permerror у писем, чей IP в записи указан верно, но правее уже исчерпанных запросов. Письмо с IP, который совпал до лимита, при этом проходит. Решение: поставить известные ip4 вперёд, убрать лишние a и mx и сократить число include, которые приходится вычислять.
Неверный селектор DKIM. Сервер подписывает s=send, а ключ лежит в mail._domainkey. Симптом: dkim=fail и в DNS по имени из подписи пусто. Решение: создать TXT ровно под селектором из заголовка либо переключить сервер на селектор, который уже опубликован.
В DNS не тот публичный ключ. В p= попал обрезанный base64, лишний пробел или ключ от другого сервера. Симптом: запись находится, подпись в письме есть, проверка dkim=fail. Решение: заново снять публичный ключ с того сервера, который подписывает сейчас, и заменить p=.
Приватный ключ оказался снаружи. Утечка приватного ключа — инцидент безопасности. Кто его прочитал, тот может ставить действительную подпись домена, и dkim=pass у такого письма будет честным. Нужна ротация: выпустить новую пару, опубликовать её новым селектором, переключить сервер отправки, перестать подписывать старым ключом и убрать старую запись. Пустой p= у старого селектора отзывает ключ. Пока старый ключ опубликован и ещё используется, смена одного символа в DNS проблему не закрывает.
Нет согласования. SPF и DKIM зелёные для домена сервиса рассылки, в поле «От» ваш домен, своей подписи d=example.com нет, конверт тоже на чужом домене. Симптом: dmarc=fail при spf=pass и dkim=pass. Решение: подписать письмо своим доменом или отправлять конверт с домена, который совпадает с полем «От».
Сразу p=reject. Политику ужесточили по одному тестовому письму с pass, в день, когда DNS ещё не обновился у всех, или когда CRM, форма сайта и сторонняя рассылка ещё шлют без согласованной подписи. Симптом: часть своей почты начинает получать отказ или карантин у крупных ящиков, в rua всплывают источники, о которых забыли. Решение: вернуть quarantine или none, пока эти источники не будут внесены и сводки за длинный период не станут чистыми. Отказы, которые уже ушли, сами не переигрываются.
Забытый сервис. Рассылки и корпоративная почта настроены, а билеты из helpdesk или письма сайта идут от того же домена с другого IP. Симптом: в сводном отчёте отдельный IP с fail, хотя тесты из почтовой программы проходят. Решение: либо добавить этот IP и его подпись, либо перестать ставить в этих письмах ваш домен в поле «От».
Где здесь MailNinja
MailNinja отправляет кампанию через тот SMTP, который вы подключили: свой сервер или подключённый сервис. В DNS она записи не создаёт и ключи DKIM за вас не выпускает. Проверки чёрных списков в программе нет.
Для домена это значит простую вещь. IP, который нужно внести в SPF, — это IP сервера, принимающего от программы почту и сдающего её получателям. Если этого IP нет в политике, SPF для конверта этой кампании не проходит. Само по себе это ещё не провал DMARC. Когда у того же письма есть подпись DKIM с pass и домен d= согласован с полем «От», DMARC может пройти и без SPF. Обратное тоже верно: зелёный SPF без согласования с полем «От» ветку SPF для DMARC не закрывает. Провал DMARC наступает, когда не сработала ни одна из двух веток.
Отсутствие IP всё равно оставлять нельзя. Часть получателей отклоняет конверт по жёсткому SPF ещё до того, как смотрит подпись и политику DMARC. Такое письмо даже не попадёт в сводный отчёт: до поля «От» сессия не дошла. Текст отказа остаётся в журнале кампании. По нему видно, ругается ли сервер на SPF, на политику домена или на что-то другое. Успешный логин на SMTP этот ответ не отменяет, и программа не обещает ни pass, ни папку «Входящие».
В адресах Кастом From программа может показать, нашлась ли у домена запись SPF и запись DMARC. Это ответ «запись есть или её нет», не ответ «эта запись разрешает именно тот сервер, через который уйдёт кампания». Разрешение конкретного IP по-прежнему читается в самой политике и в заголовке Authentication-Results у тестового письма.
Поле «От» в кампании должно быть на домене, для которого вы собрали SPF, DKIM и DMARC. Смена адреса на другой домен запускает уже его проверку и его политику. Подключение сервера и адрес в письме из-за этого проверяют вместе: сначала DNS, потом рассылка.
Источники
Технические правила выше сверены с документами IETF, а не с пересказом:
- RFC 7208 — SPF: идентичность
MAIL FROMи пустой обратный путь, механизмы, квалификаторы, одна политика на домен, предел в десять DNS-запросов во время проверки, рекомендация по пустым ответам, результатpermerror; - RFC 6376 — DKIM: подпись, селектор, теги
d=иs=, публикация публичного ключа, отзыв пустымp=; - RFC 9989 — действующий DMARC: согласование с полем «От», политики
none,quarantineиreject, тегиsp,npиt, удалениеpct; - RFC 9990 — сводные отчёты
rua; - RFC 9991 — отчёты об отдельных неудачах
rufи ограничения из-за приватности; - RFC 7489 — прежняя информационная спецификация DMARC. Для текущей настройки её заменяет RFC 9989; по ней ещё можно встретить
pct, которого в новом стандарте нет; - RFC 8601 — заголовок
Authentication-Results; - RFC 8617 — ARC, если письмо проходит через серверы, которые иначе ломают DKIM.
У Google и Microsoft в справке для администраторов почты есть собственные инструкции, как включить эти же записи на их стороне. Они описывают кабинет конкретного сервиса. Список разрешённых серверов и селектор всё равно определяются тем, кто реально отправляет почту вашего домена.