Анализ почтовых логов через pflogsumm и GoAccess: ежедневные отчёты по доставке
Ваш Postfix уже пишет в mail.log всё, что нужно для диагностики доставки. Проблема не в данных, а в том, что их читают только когда горит. Разбираем, как собрать связку cron → pflogsumm → почтовый дайджест плюс живой дашборд GoAccess, и какие три числа смотреть каждое утро.
EvilMail Team26 июля 2026 г.11 мин чтения
Postfix уже пишет в /var/log/mail.log каждую SMTP-транзакцию: кто отправил, кому, за сколько байт, с каким финальным статусом и какой код вернул принимающий сервер. Данных достаточно, чтобы поймать проблему за сутки до того, как о ней сообщит клиент. Но в реальности логи открывают в двух случаях: когда пришла жалоба «письмо не дошло» и когда Gmail начал ставить 421 4.7.0. К этому моменту вы уже отстаёте от проблемы на несколько часов, а grep по 200 тысячам строк — это гадание, а не диагностика.
Ниже — как заменить «грепаю руками, когда горит» на дисциплину: суточный отчёт pflogsumm на почту через cron и живой дашборд GoAccess поверх тех же логов. Двадцать минут настройки, дальше три числа каждое утро.
Что реально живёт в mail.log и почему grep не масштабируется
Ключевая деталь, которую упускают: одно письмо — это не одна строка лога, а три-шесть. Postfix пишет по мере прохождения письма через свои демоны, и склеивает их сквозной queue ID — шестнадцатеричный идентификатор вроде 4Xk2p13Nzz
pflogsumm + GoAccess: ежедневный анализ логов Postfix и мониторинг доставки — EvilMail Blog
Отсюда следует неприятный вывод: grep -c 'status=bounced' mail.log считает не письма, а события доставки. Письмо на три получателя, где двое отбились, даст два bounced — но письмо было одно. При ретраях deferred инкрементируется каждую попытку. Поэтому ручной grep систематически завышает и врёт в цифрах, на которые вы потом принимаете решения.
Второй подвох 2026 года: минимальные и облачные образы свежих дистрибутивов (Debian 13, Ubuntu 24.04) всё чаще идут без rsyslog — логи оседают только в journald, и файла /var/log/mail.log попросту нет. Либо ставите rsyslog, либо выгружаете журнал для анализатора:
На RHEL/Alma путь другой — /var/log/maillog. Дальше по тексту подставляйте свой.
pflogsumm: суточный отчёт за одну команду
pflogsumm — Perl-скрипт без демона, зависит от Date::Calc, ничего не крутится в фоне. Ставится тривиально:
bash
apt install pflogsumm # Debian/Ubuntu
dnf install postfix-perl-scripts # RHEL/Alma (пакет с тем же скриптом)
Базовый прогон по вчерашнему логу:
bash
pflogsumm -d yesterday /var/log/mail.log
Шапка отчёта — это те самые цифры, ради которых всё затевалось:
Grand Totals
------------
messages
14201 received
13980 delivered
12 forwarded
402 deferred
88 bounced
143 rejected
0 reject warnings
0 held
0 discarded
Читаются они так. received — сколько приняли в очередь. delivered — реально ушло с кодом 2xx. deferred — временно не смогли (4xx), письмо ещё в очереди и будет ретраиться. bounced — окончательный отказ (5xx), отправителю ушёл bounce. rejected — отбито прямо на нашем smtpd (спам-фильтр, RBL, неизвестный получатель на входящем) — это про входящую почту, не путайте с bounced на исходящей.
Ниже шапки идут разделы, которые и делают инструмент диагностическим. Флаг --problems-first поднимает их наверх, --verbose-msg-detail разворачивает конкретные адреса:
message deferral detail — сгруппированные причины отсрочек. Здесь видно, что 380 из 402 deferred — это connection timed out к одному релею. Это не ваша проблема с контентом, это сеть или репутация IP.
message bounce detail — окончательные отказы с текстом от принимающей стороны: 550 5.1.1 User unknown, 552 5.2.2 Mailbox full. Отсюда растут списки невалидных адресов.
Warnings — предупреждения Postfix, часто первый признак проблем с TLS или DNS.
senders by message count / recipients by message count — топы. Аномальный отправитель с тысячами писем за ночь — это либо легитимная рассылка, либо скомпрометированный аккаунт.
Полезные флаги для стабильных отчётов: --zero-fill заполняет пустые часы нулями (иначе почасовая сводка «прыгает» и её нельзя сравнивать день к дню), --iso-date-time даёт ISO-даты, -q глушит лишний вывод.
Ежедневный отчёт на почту через cron
Смысл в том, чтобы отчёт приходил сам, а не когда вы вспомнили. Кладём в /etc/cron.d/pflogsumm:
Читаем `mail.log.1`, а не `mail.log`. logrotate по умолчанию крутит логи ночью. Если запустить pflogsumm в 04:10 по mail.log, вы получите неполные сутки — часть уже уехала в .1. Либо считайте mail.log.1 после ротации, либо повесьте вызов прямо в секцию postrotate в /etc/logrotate.d/rsyslog, чтобы отчёт формировался ровно по закрытому суточному файлу до его сжатия.
Осмысленный Subject. Дата в теме и, в идеале, ключевое число прямо там — тогда красную зону видно, не открывая письмо. Небольшая обёртка, которая считает bounce-rate и подсвечивает его:
Не ловите рекурсию. Отчётное письмо само проходит через Postfix и оседает в логах. На объёме evilmail это шум в пределах погрешности, но если гоняете отчёты по нескольким доменам — фильтруйте служебный трафик, иначе postmaster@ начнёт попадать в топ-получателей.
GoAccess поверх почтовых логов: живой дашборд
pflogsumm — это утренняя газета: раз в сутки, для человека. Когда идёт 4xx-шторм, хочется смотреть в реальном времени и кликать. Для этого — GoAccess.
Честное ограничение: GoAccess создан для web access-логов и Postfix из коробки не понимает. Никакого пресета --log-format=postfix нет. Нужно вручную описать формат под конкретные строки вашего syslog. Это самая хрупкая часть связки — поля Postfix различаются между smtpd, qmgr и smtp, поэтому парсер придётся подгонять итеративно, глядя на реальные строки.
Где %d — дата, %t — время, %h берём как «хост» для группировки, %s — статус. %^ — пропускаемые поля. Реальную строку почти наверняка придётся дошлифовать под ваш формат syslog (приоритет, hostname, PID), но принцип такой.
Понадобится открытый WS-порт и reverse proxy с TLS перед ним — статику отдаёт nginx, а сокет проксируется на 7890. Взамен получаете дашборд, который обновляется по мере роста лога: топ-отправители, топ-получатели, распределение статусов, всплески по часам. Там, где pflogsumm даёт агрегат, GoAccess даёт drill-down — кликнуть на всплеск в 03:00 и увидеть, кто именно его создал. Слабое место обратное: GoAccess не знает семантики «bounce vs defer», для него это просто строки со статусом. Смысловую разбивку по-прежнему даёт pflogsumm.
Читаем цифры как инженер: defer, bounce, reject — три разные болезни
Главная ошибка новичка — лечить их одинаково. Это разные диагнозы.
`4xx deferred` — временно, само не смертельно.Deferred: connection timed out — принимающий сервер не ответил: сеть, их перегрузка или ваша репутация. 421 4.7.0 Try again later от Gmail/Outlook — это greylisting или rate limit по вашему IP. Лечится терпением и, если IP новый, прогревом (warmup). Одиночные deferred — норма, Postfix переретраит. Тревога — когда deferred растёт по часам к одному провайдеру: это уже репутация, а не случайность.
`5xx bounced` — окончательно.550 5.1.1 User unknown — адреса нет, чистите список. 552 Mailbox full — на стороне получателя. Всплеск bounce от одного отправителя почти всегда означает одно из двух: скомпрометированный аккаунт рассылает спам на мусорные адреса, или кто-то залил кривой список рассылки. И то и другое бьёт по репутации домена — реагировать в тот же день.
`reject` — на входящем периметре. Ваш smtpd отбил письмо: RBL, спам-скор, неизвестный локальный получатель. Само по себе это здоровье фильтров, а не проблема доставки. Но резкий рост reject на входящем — это либо атака, либо что-то сломалось в правилах.
Связка с deliverability прямая: растёт deferred/bounced к крупным провайдерам — идём проверять аутентификацию. PTR (обратная запись IP должна резолвиться в ваш HELO-хост), SPF (v=spf1 ... включает отправляющий IP), DKIM-подпись валидна, DMARC-запись _dmarc на месте, и IP не в Spamhaus/Barracuda. Порядок именно такой — PTR и SPF ломаются чаще всего.
Пороги, по которым стоит держать себя:
bounce-rate > 5% от delivered — красная зона. Крупные провайдеры начинают резать репутацию задолго до этого.
deferred, растущий по часам к одному провайдеру — проблема аутентификации/репутации, а не «интернет тормозит».
письмо в active queue дольше 4 часов — ручной разбор через postqueue -p / mailq.
Мини-runbook: что делать каждое утро
Открыть ночной отчёт pflogsumm. Сверить delivered / deferred / bounced со вчерашними — интересны не абсолюты, а дельта и bounce-rate.
Глянуть message bounce detail, топ-3 причины. User unknown в товарных количествах — чистка списка; всплеск от одного from= — проверять аккаунт.
Открыть дашборд GoAccess, посмотреть на всплески по часам. Ночной пик без причины — повод грепнуть queue ID.
mailq | tail — что застряло. Всё старше 4 часов разбираем руками.
При аномалии — вытащить конкретную транзакцию целиком: grep 4Xk2p13Nzz /var/log/mail.log покажет путь письма от smtpd до финального status=.
Полезно под рукой: postqueue -f форсирует доставку очереди, postsuper -d ALL deferred чистит отсрочки (осторожно — сносит письма без возврата).
Дальше это автоматизируется: mtail или grok_exporter превращают mail.log в метрики Prometheus через textfile-collector, а Grafana строит графики и шлёт алерт, когда bounce-rate переваливает порог. pflogsumm остаётся для человека — прочитать за кофе и понять контекст, — а метрики берут на себя круглосуточную вахту. Именно так это устроено в инфраструктуре evilmail.pro: суточный дайджест для глаз плюс метрики для алертинга, и ни одна жалоба на недоставку больше не приходит раньше, чем мы сами увидели проблему в цифрах.