max-message-hops

<source>

Сколько заголовков Received может нести письмо
в конфигурации это строкаmax-message-hops 100внутри блока <source>
Защита от петли, считанная по числу пересылок

Сколько заголовков Received узел согласен увидеть в письме. Каждая почтовая система, через которую письмо прошло, дописывает такой заголовок сверху — получается след маршрута. Слишком длинный след означает, что письмо ходит по кругу, и узел его не принимает.

Это счёт по чужим следам, а не по своим. Узел смотрит на то, что уже есть в письме на момент приёма. Умолчание 100 рассчитано на нормальную почту, где пересылок единицы: письмо со ста заголовками не «долго шло», а зациклилось.

Откуда берутся петли. Обычно из пересылки: ящик A пересылает на B, B настроен обратно на A — письмо ходит между ними, и на каждом круге след удлиняется на два заголовка. Счётчик — единственное, что такой круг останавливает: сами системы петли не видят.

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

Главная ловушка. Считать по заголовкам может только тот, кто их видит, а добавлять их узел не обязан. Соседняя строка add-received-header со значением false отключает добавление своего Received — и наш узел перестаёт удлинять след. Петля, которая закручивается через нас, тогда не растёт: счётчик остаётся на том же числе круг за кругом и порог не берёт никогда. Защита не ломается, но перестаёт срабатывать на петлях, чей путь идёт только через этот узел.
Что делает Хаб. Не пишет — остаётся вендорское 100.

🔴 Но в том же блоке подачи Хаб пишет add-received-header false — осознанно, чтобы не раскрывать в письме внутренние адреса. Побочный результат: наш узел не добавляет своего Received, и счётчик петель на письмах, проходящих только через нас, не растёт. Для нашей подачи это безопасно: письмо приходит напрямую, от подающей платформы или от прогрева самого Хаба, и никуда не пересылается. Но значит это и то, что защита от петель у нас держится не на этой строке, а на том, что пересылки в схеме нет.

Рекомендуемые значения

Умолчание трогать незачем. Сто пересылок — это заведомо петля, и нормальная почта до такого числа не доходит. Понижение имеет смысл как разовая диагностика, а не как настройка на каждый день.

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

Ноль здесь не описан. Руководство говорит только о положительном целом; что сделает 0, оно не поясняет, и проверять это стоит на стенде, а не на рабочем узле.

Совет о диагностике — наш. Из руководства здесь умолчание 100, грамматика значения и то, что счёт идёт по заголовкам Received.
Пример в конфигурации
# пониженный предел на время разбора петли
<source 0/0>
    add-received-header true
    max-message-hops 10</source>
Верхняя строка здесь не для красоты: без своего Received узел не удлиняет след, и пониженный предел на петле через этот же узел не сработает.
жёлтым — — имена директив, голубым — блоки. Так же они подсвечены и в тексте карточки.
▲

Типичные ошибки и проблемы

что делают не так и чем это кончается3 ошибки▶

Понижают предел при отключённом своём Received

§ 3.3.7.6

Чем чреватоСчётчик не растёт от прохождения через наш узел, поэтому письмо, закрученное в петлю через него же, порог не возьмёт ни на десятом круге, ни на сотом. Предел выглядит настроенным и не работает.
Как заметитьОдно и то же письмо появляется в очереди снова и снова, число заголовков Received в нём не меняется.
Как правильноНа время разбора вернуть add-received-header в true — тогда каждый круг будет виден в следе и предел сработает.

Держат низкий предел постоянно

§ 3.3.7.38

Чем чреватоПонижение полезно на время разбора, а как постоянная настройка начинает отбивать честную почту: письма из корпоративных цепочек с несколькими шлюзами набирают заголовки быстро и упираются в предел без всякой петли.
Как заметитьОтказы на приёме приходят от одних и тех же отправителей — обычно из организаций с собственными почтовыми шлюзами.
Как правильноВернуть вендорские 100 после разбора. Если петля не найдена, искать её надо в настройках пересылки, а не в пороге.

Ждут, что предел остановит исходящую петлю

§ 3.3.7.38

Чем чреватоСтрока живёт в блоке подачи и проверяет письма на приёме. Письмо, которое узел отправляет и которое возвращается к нему от чужой системы, будет проверено на входе, а не на выходе — если оно вообще к нам вернётся.
Как заметитьПетля между двумя чужими системами продолжается, хотя предел на нашем узле выставлен.
Как правильноРазбирать такую петлю по журналу доставки, а не порогом приёма: останавливать её должна та система, которая пересылает письмо обратно.
Совместимость
PowerMTA 6.0
описана в руководстве этой версии · платформа: любая
С какой версии директива доступна, вендор указывает не для всех — здесь пометки нет. Имя встречается и в издании руководства 5.0.
Справочные данные
Синтаксис
max-message-hops <integer>
Значения
положительное целое число
Умолчание
100 § 3.3.7.38
Применение
reload, перезапуск не нужен
Очередь
уже поставленное в очередь не затронет
Где писать
<source>
Сколько раз
один раз в блоке
Всё здесь — из руководства, с разделом.
Наследование
Значение сливается по совпадающим блокам <source>, узкая запись перекрывает широкую. Выше блока подачи наследовать не от чего — на уровне узла директива не описана. Подхватывается по pmta reload.
Как проверить на узле
Ни одна команда узла эту настройку не печатает — смотреть надо конфигурацию, и вместе с ней соседнюю строку:
grep -n 'max-message-hops\|add-received-header' /etc/pmta/config
pmta test config
Если add-received-header стоит в false, предел останется формальностью для петель через этот узел. Само срабатывание видно в журнале при приёме — письмо отвергается, не попадая в очередь.
В Хабе
Цена ошибки
обратимо: вредит, пока стоит
Сценарии
Разобрать зависшую очередь