Сохраняем входящую и исходящую почту в postfix

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

  1. добавить в цепочку обработки входящей почты так называемый postfix milter (postfix mail filter), чтобы сохранять входящие письма (приходящие по протоколу SMTP).
  2. Включить обработку заголовков писем. Это позволяет организовать почту при помощи регулярных выражений на основе заголовков. В зависимости от содержимого определенных заголовков мы можем выполнить те или иные действия. Чуть ниже посмотрим конкретный пример

Что из себя представляет postfix milter

Postfix milter — это просто программа, которая получает письмо, что-то с ним делает (или не делает), и возвращает обратно postfix’у. Задачи, для которых используются такие механизмы, могут быть разными — фильтрация спама, добавление заголовков, подпись писем, и так далее. Самое главное — понимать, что мы делаем с почтовым сообщением.

Цепочка при использовании milters выглядит следующим образом:

  1. Postfix получает почтовое сообщение
  2. Postfix передает его на обработку при помощи milter’а
  3. Письмо доставляется или не доставляется адресату

Пишем простой milter

Напишем простой milter. Будем использовать для этого bash. Назовем его mail_script.sh

#!/bin/sh

INSPECT_DIR=/var/spool/filter
SENDMAIL="/usr/sbin/sendmail -G -i"

EX_TEMPFAIL=75

MAIL_FILE_NAME=mail-$(date "+%Y-%m-%d-%H:%M:%S")
cd $INSPECT_DIR || { echo $INSPECT_DIR does not exist; exit $EX_TEMPFAIL; }

cat > $MAIL_FILE_NAME || { echo Cannot save mail to file; exit $EX_TEMPFAIL; }

$SENDMAIL "$@" < $MAIL_FILE_NAME

exit $?

Теперь можно подключить его следующим образом: в файл /etc/postfix/master.cf добавляем фильтр. То есть, меняем строчку

smtp      inet  n       -       -       -       -       smtpd

на строчку

smtp      inet  n       -       -       -       -       smtpd -o content_filter=mail_saver

А в конец файла добавляем следующее:

mail_saver	unix	-	n	n	-	-	pipe
  flags=Rq user=filter argv=/home/filter/milter.sh -f ${sender} -- ${recipient}

Естественно, нужно будет предварительно создать пользователя filter с домашней директорией /home/filter.

При получении письма просто записываем все данные в файл с названием, включающим текущее время и дату, чтобы в дальнейшем можно было посмотреть, что именно пришло на сервер извне.

Сохранение исходящей почты

Для того, чтобы сохранить исходящую почту, нам нужно будет просто все исходящие письма перенаправить локальному пользователю, под которым мы потом сможем эту почту просматривать.

Вот что нам для этого потребуется. В директории /etc/postfix создаем файл с названием «header_checks». Этот файл содержит шаблоны заголовков, включающие регулярные выражения, и правила для перенаправления почты на основе совпадения соответствующего заголовка с регулярным выражением. Запишем в этот файл следующее:

/^To: */ REDIRECT user@localhost

Вместо user@localhost можно подставить необходимый адрес, и тогда все исходящие письма, в соответствии с этим правилом, будут перенаправлены указанному пользователю.

После создания файла нужно указать postfix’у использовать этот файл для проверки заголовков. Это можно сделать следующим образом: в файл /etc/postfix/main.cf необходимо добавить строчку

header_checks = regexp:/etc/postfix/header_checks

Останется только перезагрузить настройки postfx’а, и можно работать с почтой и быть уверенным, что ничего не уйдет наружу, но при необходимости можно будет получить письмо снаружи.

 

Сохраняем входящую и исходящую почту в postfix: 6 комментариев

  1. Error

    Также нам надо установить, куда нужно отправлять почту далее. Скажите Postfix фильтровать всю почту через внешний фильтр содержимого, и включите явный выбор маршрута, чтобы Postfix знал, куда направлять почту.

  2. Denis

    вместо: trap «rm -f in.$$» 0 1 2 3 15
    полагаю должно быть: trap «rm -f $MAIL_FILE_NAME» 75
    а строчка MAIL_FILE_NAME=mail-$(date «+%Y-%m-%d-%H:%M:%S»)
    Должна быть выше trap

    1. Maxim Norin Автор записи

      MAIL_FILE_NAME — да, поправил, а вот 75 — нет. 0 1 2 3 15 — это сигналы, которые мы ловим

      1. Denis

        В оригинале http://www.postfix.org/FILTER_README.html#simple_filter судя по логике файл будет удаляться при ошибке (сигнал больше нуля) и при успешной работе скрипта (0 сигнал), то есть всегда :)
        А наша задача файл сохранить, а не удалять всегда. Так вот судя по коду и сигналам, нужно удалять при ошибке и при «exit $EX_TEMPFAIL;» (это уже наша кастомная ошибка).

        1. Maxim Norin Автор записи

          На самом деле нам вообще этот файл можно не удалять.
          Потому что это для дебага во время разработки, на реальной системе такое никто делать не будет.
          Поэтому trap можно с легкостью убрать.

  3. Антон

    Здравствуйте.
    Можно ли сохранять почту в файлы по заголовку To(получатель)?
    Хотелось бы получить письма вида: mail_to@mai.ru_2020_02_25_21_20

Обсуждение закрыто.