Письмо, ушедшее с собственного сервера, в пути проходит допрос, о котором отправитель не догадывается. Приёмная сторона крупного провайдера за доли секунды сверяет адрес отправителя со списком разрешённых, проверяет криптографическую подпись письма и заглядывает в правила домена, чтобы понять, что делать с подозрительным. Отвечают на все три вопроса DNS записи домена: SPF, DKIM и DMARC. Без них письма формально уходят, но оседают в спаме у самых крупных получателей, и никакие настройки сервера это не компенсируют. В статье три записи по очереди: синтаксис, генерация ключей, публикация, проверка и типичные ошибки на живом домене.

Три слоя проверки отправителя на входе у крупных провайдеров

Механика приёма выглядит как конвейер из трёх вопросов. Первый, это письмо действительно с адреса, принадлежащего домену: за него отвечает SPF, список адресов, с которых домен разрешает отправку. Второй, не изменилось ли письмо по дороге: DKIM ставит на него подпись закрытым ключом сервера, а получатель проверяет её открытым ключом из DNS. Третий, что делать, если первые два ответа не сошлись: DMARC объявляет правило домена и просит отчёт о всех проверках. Порядок внедрения записей на новом домене выглядит так:

  1. SPF закрывает список адресов и серверов, которым разрешено отправлять письма домена;
  2. DKIM добавляет исходящим письмам криптографическую подпись с ключом в DNS;
  3. DMARC связывает обе проверки с видимым адресом автора и объявляет правило;
  4. Неделя чтения отчётов, и правило плавно ужесточается с наблюдения до отбраковки.

Смысл конструкции не в сложности, а в совместной работе. SPF проверяет конверт, по которому письмо путешествует, DKIM само письмо, DMARC сверяет и то и другое с адресом, который видит человек в почтовой программе. Отправитель, у которого все три слоя согласованы, отличается от спамера, который умеет подделать только один.

Формат записи SPF, лимит десяти поисков и выбор жёсткости хвоста

Запись SPF живёт в TXT домена и читается как инструкция для получателя:

example.com. IN TXT "v=spf1 a mx ip4:203.0.113.10 ~all"

Части записи разбираются по словарю. Механизм a разрешает отправку с адреса, на который указывает A запись домена, mx с адресов его почтовых серверов, ip4 и ip6 перечисляют адреса явно, include подключает чужой список, что нужно, когда домен шлёт письма ещё и из внешнего сервиса рассылок или облачной почты. Хвост записи решает судьбу писем с адресов вне списка: мягкий ~all намекает получателю на подозрительность, жёсткий -all прямо требует браковать, нейтральный ?all молчит. Для домена, который шлёт только со своего сервера, честный выбор это жёсткий хвост, но на время внедрения разумнее мягкий: сначала неделя наблюдения за отчётами, потом ужесточение.

У записи есть малоизвестный технический лимит, который ломает чересчур усердные списки: получатель выполняет не больше десяти DNS поисков при разборе одной SPF, и каждый include, a, mx, exists или redirect тратит из этого бюджета. Цепочка вложенных include от третьих сервисов легко исчерпывает десятку, и тогда вся запись считается сломанной, при том что выглядит она безупречно. Проверяют SPF отладчиками, а на глаз оценивают так: больше трёх include в одной записи это уже повод насторожиться.

Классических ошибок у SPF две. Первая, две записи SPF у одного домена: приёмная сторона в этом случае считает SPF невалидным, и весь список превращается из защиты в проблему. Вторая, забытый адрес рассылающего сервиса, после чего честные уведомления помечаются как подозрительные. Обе лечатся внимательным чтением, записи одна, и в ней собраны все источники отправки.
Сборка записи для живого домена выглядит как чек-лист. Адрес сервера идёт в ip4, собственное имя в a или mx, если часть писем уходит из корпоративного облака, добавляется include на список этого сервиса, если из платформы рассылок, ещё один. Готовую запись прогоняют через специализированный отладчик: он показывает израсходованные DNS поиски и результат разрешения каждого механизма, и это дешевле любых предположений о том, всё ли собралось правильно. Короткая запись в этом смысле надёжнее длинной: меньше механизмов, меньше поводов сломаться в пути.

Генерация ключа DKIM и публикация открытой части в TXT записи

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

opendkim-genkey -b 2048 -d example.com -s mail2025
rspamadm dkim_keygen -b 2048 -d example.com -s mail2025

Утилита из комплекта фильтра Rspamd удобнее тем, что сразу печатает готовую DNS строку. Длина 2048 бита достаточна и по стойкости, и по совместимости, длиннее некоторые провайдеры DNS режут по лимиту строки. Результат публикации выглядит так:

mail2025._domainkey.example.com. IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOC..."

Открытый ключ это просто длинная строка в кавычках, и единственная опасность тут механическая: панель регистратора обрезает или ломает строку при вставке, и подпись перестаёт проверяться, хотя запись формально существует. Длинные значения DNS иногда разбиваются на несколько строк, и склейка должна получиться без потерь. Проверяют публикацию всегда снаружи, с публичного резолвера, а не с сервера, где кеш может показывать старое.
Закрытый ключ хранится рядом с прочими секретами почтового сервера: права на файл ограничены пользователем службы, ключ не попадает в репозитории конфигураций, в архивах копий он едет под тем же замком, что и пароли. Утёкший ключ не ломает почту немедленно, но обесценивает подпись до самой ротации, и в этом смысле ключ равен паролю.

Селектор как адрес ключа и подпись исходящих писем сервером

Часть mail2025 в имени записи называется селектором, и это адрес конкретного ключа. Когда домен подписывает письма с двух серверов или с сервера и сервиса рассылок, у каждого свой селектор и свой ключ, и все они спокойно живут в DNS рядом. Письмо несёт в заголовке подписи имя селектора и домена, получатель собирает из них адрес записи, находит ключ и проверяет подпись. В заголовке готового письма это выглядит как строки с полями d= для домена и s= для селектора, по ним видно, каким ключом подписано письмо, ещё до всяких проверок.
Проверка подписи со стороны получателя смотрится в заголовке Authentication-Results: в нём приводится вердикт dkim, pass или fail, и селектор, которым письмо подписано. Тестовое письмо отправляется на дружественный адрес или адрес тестового сервиса, заголовки открываются в почтовой программе, и пять минут чтения строк закрывают вопрос о всей цепочке: подпись, публикация, проверка у получателя.

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

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

Настройка DMARC от наблюдения к строгому отбраковыванию писем

DMARC живёт на отдельном поддомене с подчёркиванием и отвечает на вопрос получателя, что делать с письмами домена, не прошедшими проверку подлинности:

_dmarc.example.com. IN TXT "v=DMARC1; p=none; rua=mailto:Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в браузере должен быть включен Javascript."

Значение p=none это режим наблюдения: письма не отбраковываются, но на адрес из параметра rua приходят агрегированные отчёты о всех письмах от имени домена, прошедших проверку и проваливших её. Начинают всегда с него, и это не трусость, а метод: резкий переход к reject без недели чтения отчётов отрубает доставку легитимных писем, о которых администратор не знал. В отчётах первой недели обычно всплывают забытое: рассылки из маркетинговой платформы, уведомления из биллинга, письма из CRM, и каждый источник либо добавляется в SPF и подписывается ключом, либо осознаётся как лишний.

Дальше правило ужесточается ступенями. Режим quarantine велит получателям пристраивать непрошедшие письма в спам, режим reject прямо отбраковывать. Плавность хода регулируется параметром pct, долей писем, к которым применяется правило: сначала сто процентов в наблюдении, затем десять процентов в quarantine, и лишь потом полные строгие режимы. Для домена небольшой организации весь путь занимает месяц и заканчивается записью, после которой подделка писем от его имени становится для спамера бесполезной.

Выравнивание доменов и чтение агрегированных отчётов о письмах

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

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

Проверка записей через dig и ошибки с PTR и пересылкой писем

Все три записи проверяются снаружи за минуту:

dig +short TXT example.com
dig +short TXT mail2025._domainkey.example.com
dig +short TXT _dmarc.example.com

Первая команда обязана вернуть ровно одну строку SPF, вторая открытый ключ, третья правило DMARC. Пустой ответ или лишняя запись это сигнал разбираться до того, как письма начнут теряться. Типичные провалы на живых доменах известны по годам практики. Обратная запись адреса, не совпадающая с именем сервера, роняет доверие ещё до всех трёх записей, и ставится она у хостера. Подпись DKIM ломается, когда письмо по дороге пересылки изменяется, например, лист рассылки дописывает собственные заголовки в тело или субъект, поэтому списки рассылок переписывают адрес автора на свой. Пересылка писем на личные адреса ломает SPF, потому что письмо отправляется уже с чужого сервера, и спасает тут именно подпись DKIM, которая переживает пересылку нетронутого письма.

Итог по всем трём записям укладывается в строку: SPF отвечает за адреса, DKIM за целостность, DMARC за правило и наблюдение. Домен с согласованной тройкой получает у крупных провайдеров то, что и искал, честное место во входящих, а дальше уже работает репутация адреса и поведение людей, которые письма открывают и отвечают.
Тройка записей настраивается не один раз и навсегда, но это самая дешёвая часть сопровождения почты: взгляд на отчёты раз в неделю и правки пару раз в год. Сравните это с попытками доказывать поддержке крупного провайдера, что ваши письма честные, и ценность тройки становится очевидной без дальнейших аргументов.