DKIM fail: почему подпись не проходит проверку и что делать
DKIM fail означает, что принимающий сервер не смог подтвердить цифровую подпись письма: либо не нашел или не смог прочитать открытый ключ в DNS, либо письмо изменилось после подписания. Причина всегда записана в заголовке Authentication-Results рядом со словом fail. Ниже дерево диагностики: от текста ошибки к конкретной проверке и исправлению.
1. Что означает DKIM fail
При получении письма сервер получателя берет из подписи DKIM-Signature домен (d=) и селектор (s=), запрашивает в DNS открытый ключ вида selector._domainkey.example.com и заново вычисляет подпись по заголовкам и телу письма. Если ключ не найден, не читается или вычисленный хэш не совпал с тем, что зашит в подпись, в результатах проверки появляется dkim=fail.
Само по себе dkim=fail не всегда приводит к спаму: если SPF проходит и совпадает с доменом From, DMARC может все равно дать pass. Но постоянные провалы DKIM ухудшают картину для фильтров Gmail, Mail.ru и Яндекса, а при политике DMARC quarantine или reject и провале обоих механизмов письмо будет отклонено.
Диагностику всегда начинайте с исходного текста письма на стороне получателя. Отправьте тестовое письмо на ящик в Gmail или Mail.ru, откройте исходник и найдите блок Authentication-Results. Именно там стоит код причины, а не в интерфейсе вашей платформы рассылок.
- •Найдите строку dkim=fail в заголовке Authentication-Results письма-получателя.
- •Выпишите причину в скобках, значения d= и s=.
- •Сверьте причину с деревом диагностики в разделе 3 и идите в нужный раздел.
2. Где искать ошибку: заголовок Authentication-Results
Формат заголовка Authentication-Results описан в RFC 8601. Вот реалистичный пример из исходника письма, принятого Gmail:
Authentication-Results: mx.google.com; dkim=fail (body hash did not verify) header.i=@example.com header.s=selector1 header.b=Ab3f9Kq2; spf=pass smtp.mailfrom=bounce.example.com; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=example.com
Здесь важны четыре поля. Код в скобках после fail: конкретная причина провала. header.i или d=: домен, чья подпись проверялась. header.s: селектор, то есть имя DNS-записи с ключом. header.b: фрагмент самой подписи, он нужен только для справки.
Если заголовок длинный и в нем несколько подписей (так бывает, когда письмо подписывают и платформа рассылок, и ваш ретранслятор), проверяйте ту подпись, где d= совпадает с доменом From. Именно она влияет на DMARC.
Разобрать заголовки вручную можно, но быстрее вставить исходник письма в анализатор заголовков: он покажет результаты SPF, DKIM и DMARC по каждому механизму отдельно.
3. Дерево диагностики: от текста ошибки к причине
Ниже сводка типовых причин, которые принимающие серверы пишут рядом с dkim=fail, и первое действие для каждой.
| Текст ошибки в Authentication-Results | Наиболее вероятная причина |
|---|---|
| body hash did not verify | Тело письма изменили после подписания: футер, переадресация, антивирусный шлюз |
| signature verification failed / bad signature | Изменились подписанные заголовки или подпись сделана другим ключом |
| invalid public key | Запись ключа в DNS повреждена: лишние пробелы, обрезана, неверный формат |
| no key for signature / key not found | Нет записи selector._domainkey.example.com или селектор не совпадает |
| key has been revoked | В записи пустое поле p=, ключ отозван |
| tempfail / DNS error | Временный сбой DNS, стоит перепроверить через несколько минут |
Порядок действий простой: если ошибка про хэш тела или подпись, ищите, кто меняет письмо в пути (раздел 4). Если ошибка про ключ или его отсутствие, проверяйте DNS (разделы 5 и 6). Если tempfail, не чините то, что не сломано: повторите проверку позже и убедитесь, что у домена нет проблем с DNS-сервером.
- ✕Проверяйте причину в письме у получателя, а не в тестовом письме самому себе через веб-интерфейс ESP: путь может отличаться.
- ✕Одно и то же письмо может давать pass у Gmail и fail у Mail.ru, если по пути к одному из них срабатывает ретранслятор, меняющий тело.
4. body hash did not verify: письмо изменили после подписи
DKIM подписывает не только заголовки, но и тело письма: в подписи есть хэш bh=. Если после подписания хотя бы один байт тела изменился, проверка хэша падает с ошибкой body hash did not verify. Это самая частая причина фразы "сломалась DKIM подпись".
Типовые виновники. Первый: списки рассылок и корпоративные ретрансляторы, которые дописывают в конец письма служебный футер или дисклеймер. Второй: переадресация, когда промежуточный сервер пересобирает письмо. Третий: антивирусные шлюзы, которые заменяют ссылки или вставляют предупреждение во внешнее письмо. Четвертый: собственная сборка письма, когда шаблонизатор меняет переносы строк или кодировку уже после этапа подписания.
Как локализовать. Отправьте одно и то же письмо напрямую на тестовый ящик и через подозреваемый узел (переадресацию, список рассылки, шлюз). Если напрямую dkim=pass, а через узел body hash did not verify, виновник найден. Дальше два пути: отключить модификацию письма на этом узле или настроить на нем повторное подписание своим ключом, чтобы итоговое письмо несло валидную подпись домена From.
Отдельный сценарий из запросов: DKIM после изменения письма. Если вы правите шаблон уже в ESP, это безопасно, платформа переподпишет письмо при отправке. Ломается подпись только тогда, когда изменение происходит после момента подписания, то есть где-то в пути между отправителем и получателем.
5. invalid public key и запись не подтверждается: проблемы DNS
Вторая большая группа причин: приемник не может получить или прочитать открытый ключ. Сначала смотрите, что реально опубликовано в DNS. Команды для терминала:
dig TXT selector1._domainkey.example.com nslookup -type=TXT selector1._domainkey.example.com
Здоровая запись выглядит примерно так: v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA... Дальше сверяйте по чек-листу.
| Что проверить | Как должно быть |
|---|---|
| Имя записи | selector._domainkey.example.com, селектор из header.s письма, без опечаток |
| Тип записи | TXT с ключом или CNAME на ключ платформы (см. раздел 6) |
| Префикс | v=DKIM1 в начале значения, без лишних слов до него |
| Целостность p= | Длинная base64-строка без обрывов и пропущенных символов при копировании; сами по себе переносы строк и пробелы внутри значения стандарт разрешает и верификатор их игнорирует |
| Отзыв ключа | Поле p= не пустое: пустое p= означает отозванный ключ |
| Дубли | На одно имя одна TXT-запись DKIM, несколько записей дают непредсказуемый результат |
Типовая история для ошибки invalid public key: ключ копировали из кабинета ESP в DNS-редактор, и редактор разбил длинную строку на части с кавычками или съел часть символов. Другой вариант: в панели хостинга запись создали на уровне поддомена, и вместо selector1._domainkey.example.com она оказалась на selector1._domainkey.example.com.example.com.
Если запись вообще не отвечает (No answer или NXDOMAIN), а в кабинете платформы статус "DKIM запись не подтверждается", почти всегда дело в имени записи или в том, что DNS еще не обновился. Проверьте запись через dig с явным указанием публичного резолвера: dig TXT selector1._domainkey.example.com @8.8.8.8. Так вы отсечете кэш корпоративного DNS.
6. CNAME или TXT: как правильно опубликовать ключ
Многие платформы рассылок предлагают два способа подтвердить DKIM: создать TXT-запись со значением ключа или создать CNAME, который указывает на ключ в домене платформы. Частый вопрос: что выбрать. Короткий ответ: оба варианта рабочие, но у них разная эксплуатация.
| TXT с ключом | CNAME на ключ платформы |
|---|---|
| Вы копируете ключ в свой DNS вручную | Запись ссылается на DNS платформы, ключ хранится у нее |
| Ротация ключа требует ручной замены записи | Платформа может менять ключ у себя, ваша запись не меняется |
| Ошибка при копировании дает invalid public key | Ошибка обычно только в имени CNAME |
| Подходит, когда нужен полный контроль | Удобно для агентств с десятками доменов |
Если платформа дала CNAME, а вы создали TXT с тем же именем и адресом назначения в значении, проверка упадет: по адресу ключа должен лежать сам ключ с v=DKIM1, а не строка с доменом. Сверьтесь с инструкцией вашей платформы и не смешивайте форматы.
Важно для наблюдаемости: статистика в Google Postmaster Tools и Mail.ru Postmaster привязана к домену d= в подписи, а не к селектору s=. Сам по себе переход с TXT на CNAME обычно не требует менять селектор, но даже если селектор изменится, статистику это не уведет: история репутации домена считается по d= и сохранится.
7. Как проверить, что DKIM починился
После исправления DNS или настройки шлюза проверку делайте в три шага. Шаг 1: dig TXT selector._domainkey.example.com показывает целую запись с v=DKIM1 и полным p=. Шаг 2: отправьте тестовое письмо на ящики в Gmail, Mail.ru и Яндексе, откройте исходники и убедитесь, что везде dkim=pass с вашим доменом в header.i. Шаг 3: прогоните домен через инструмент проверки DKIM, чтобы зафиксировать состояние записи.
Учитывайте кэш DNS: если TTL записи был большой, приемники могут еще некоторое время видеть старое значение. Поэтому финальный вывод делайте по новым письмам, отправленным после обновления, а не по повторной проверке старых.
Если DKIM проходит, но письма все равно уходят в спам, проблема уже не в подписи: смотрите репутацию домена, жалобы и контент. Разбор этой ситуации есть в статье про случай, когда SPF, DKIM и DMARC проходят, а письмо в спаме.
8. Как не узнавать о DKIM fail от клиентов
Разовая ручная проверка закрывает инцидент, но не защищает от повторения: ключ могут случайно удалить при чистке DNS, платформа может поменять селектор, ретранслятор начнет дописывать футер. Обычно об этом узнают по жалобам клиентов или по падению открываемости.
Рабочая схема контроля. Раз в день смотрите долю писем, прошедших DKIM, в Google Postmaster Tools и данные Mail.ru Postmaster. Проверяйте DNS доменов на наличие и валидность DKIM-записей. Настройте уведомления о пересечении порогов в удобный канал, например в Telegram или на почту, чтобы реагировать в день инцидента, а не в конце недели.
PostmastersTool закрывает этот контур: собирает данные Google Postmaster Tools и Mail.ru Postmaster, проверяет DNS доменов (SPF, DKIM, DMARC, MX, черные списки), хранит историю по дням и присылает уведомления при ухудшении показателей. Это сокращает время между поломкой подписи и реакцией команды.
Что сделать дальше
Закрепите результат и закройте соседние точки отказа.
- 1Проверить DKIM-запись домена
Убедитесь, что запись селектора опубликована и отвечает из публичного DNS.
Проверить DKIM - 2Разобрать заголовки проблемного письма
Вставьте исходник письма и получите результат SPF, DKIM и DMARC по каждому методу отдельно.
Открыть анализатор заголовков - 3Разобраться с селекторами
Если сомневаетесь, какой селектор используется и где его запись, читайте статью про DKIM selector.
DKIM selector - 4Обсудить аудит настройки аутентификации
Если DKIM fail повторяется или ломается в разных потоках, закажите настройку SPF, DKIM и DMARC под вашу инфраструктуру.
Настройка SPF, DKIM, DMARC