В прошлом уроке Postfix принял письмо и решил, что оно для локального пользователя. Дальше его задача - отдать сообщение агенту локальной доставки (MDA/LDA), который положит письмо в ящик. Но между приёмом и записью в ящик есть целый слой, которым управляет администратор и сам пользователь: куда именно класть письмо, в какую папку, не переслать ли его дальше, не выкинуть ли спам. В этом уроке разберём классический .forward, коротко глянем на легаси procmail, а основное время посвятим современному способу - языку фильтров Sieve, серверной сортировке в Dovecot и управлению скриптами по протоколу ManageSieve.

Как это работает
Доставку удобно представлять как конвейер. MTA (Postfix) отвечает за маршрутизацию и приём по SMTP. Когда адресат локальный, Postfix не пишет в ящик сам - он вызывает MDA. Исторически это был mail.local или procmail, сегодня в подавляющем большинстве установок это Dovecot: либо его LDA (бинарь dovecot-lda), либо доставка по протоколу LMTP. Именно на этом шаге и работают пользовательские правила сортировки.
Самый простой инструмент пользователя - файл .forward в домашнем каталоге. В нём построчно перечисляют, куда направить почту: другой адрес, локальный аккаунт, или конвейер во внешнюю программу через символ канала. Если первой строкой поставить адрес, а второй - обратную косую с собственным логином, копия и пересылается, и остаётся в ящике. Это удобно, но логики кроме голой пересылки тут нет.
procmail когда-то закрывал эту нишу: рецепты в .procmailrc позволяли раскладывать письма по папкам, отбрасывать спам, запускать скрипты. Знать его на уровне идеи полезно для экзамена, но в 2026 году procmail - мёртвый проект: последний релиз вышел больше двадцати лет назад, у него были проблемы с безопасностью, и из современных дистрибутивов его выпиливают. Новые системы используют Sieve, а где нужна именно процедурная логика - maildrop. Так что воспринимайте procmail как наследие.
Sieve (RFC 5228) - это специализированный язык фильтрации почты. Его принципиальное отличие: он намеренно ограничен. В нём нет циклов, переменных по умолчанию и доступа к внешним командам, поэтому скрипт не может зациклиться, повесить сервер или выполнить произвольный код. Это делает Sieve безопасным для запуска на стороне сервера от имени пользователя - в отличие от procmail, которому можно скормить запуск любого бинаря. Скрипт состоит из правил вида if (условие) { действие }. Условия проверяют заголовки, адреса, размер; действия кладут письмо в папку (fileinto), пересылают (redirect), молча удаляют (discard), отклоняют с уведомлением (reject) или оставляют по умолчанию (keep).
Важный момент - неявная доставка. Если ни одно правило не сработало или ни одно явно не вызвало keep/fileinto/discard, Sieve в конце выполнит keep, то есть положит письмо в INBOX. А вот fileinto и discard отменяют этот неявный keep. Поэтому одно правило с discard молча съест письмо без следа - будьте осторожны.
В Dovecot Sieve реализован плагином Pigeonhole. Скрипты лежат в домашнем каталоге пользователя (обычно ~/.dovecot.sieve, с активным символьной ссылкой на файл в ~/sieve/). Чтобы пользователю не давать SSH-доступ к серверу для правки этих файлов, есть протокол ManageSieve (RFC 5804, порт 4190): почтовый клиент или утилита подключается, загружает, проверяет и активирует скрипты удалённо. Сервер заранее проверяет синтаксис, так что битый скрипт просто не активируется.
Команды и примеры
Простейший .forward - переслать всё на другой ящик и оставить копию себе:
Код: Выделить всё
# ~/.forward
ivan@example.org
\ivan
Код: Выделить всё
"| /usr/local/bin/myfilter.sh"
Код: Выделить всё
# Debian 13 / Ubuntu 24.04
apt install dovecot-sieve dovecot-managesieved
# RHEL 10 / Fedora 41+
dnf install dovecot-pigeonhole
Код: Выделить всё
# /etc/dovecot/conf.d/15-lda.conf
protocol lda {
mail_plugins = $mail_plugins sieve
}
# /etc/dovecot/conf.d/20-managesieve.conf
protocols = $protocols sieve
Код: Выделить всё
require ["fileinto", "envelope"];
# письма из списка рассылки - в отдельную папку
if header :contains "List-Id" "lpic.example.org" {
fileinto "Lists/LPIC";
}
# по адресу отправителя
elsif address :is "from" "boss@example.org" {
fileinto "Important";
}
# крупные вложения - в отдельную папку
elsif size :over 5M {
fileinto "Big";
}
# явный спам - молча в helpку (осторожно с discard!)
elsif header :contains "subject" "viagra" {
discard;
}
# всё прочее упадёт в INBOX неявным keep
Код: Выделить всё
doveadm sieve list -u ivan@example.org # какие скрипты есть
doveadm sieve activate -u ivan@example.org main # сделать активным
sieve-test ~/.dovecot.sieve message.eml # прогнать тест на письме
Частые грабли
- discard молча удаляет письмо без копии и без отлупа отправителю - легко потерять почту навсегда. Для сомнительных правил лучше fileinto в папку Junk, а discard оставить для заведомого мусора.
- Забыли require для используемого действия (например fileinto или imap4flags) - скрипт не активируется или падает. Каждое расширение надо объявить в require сверху.
- fileinto в несуществующую папку: без расширения mailbox папка не создаётся, письмо может уйти в INBOX или потеряться. Включайте require "mailbox" и :create.
- Думают, что fileinto оставляет копию в INBOX - нет, он отменяет неявный keep. Чтобы и разложить, и оставить копию, явно добавьте keep.
- .forward с конвейером во внешний скрипт - дыра в безопасности и частая причина почтовых петель. В 2026 это решается Sieve, а не пайпом.
- procmail ещё встречается в старых инструкциях - не тащите его на новый сервер, его уже нет в репозиториях многих дистрибутивов.
- ManageSieve слушает 4190, но клиент ходит без TLS - пароль уходит в открытом виде. Включайте STARTTLS/SSL для managesieve.
- Правили скрипт прямо в ~/.dovecot.sieve, но Dovecot держит скомпилированный .svbin - после ручной правки он перекомпилируется сам, а вот при правке через ManageSieve активный скрипт мог остаться старым, если не вызвали activate.
- Установите Sieve и managesieve: apt install dovecot-sieve dovecot-managesieved (Debian) или dnf install dovecot-pigeonhole (RHEL), подключите плагин sieve в 15-lda.conf и перезапустите dovecot.
- Создайте тестового пользователя с ящиком и положите ему ~/.dovecot.sieve с правилом fileinto по заголовку Subject (например все письма с темой TEST - в папку Tests, не забудьте require и :create).
- Сгенерируйте тестовое письмо в файл message.eml с нужной темой и прогоните sieve-test ~/.dovecot.sieve message.eml - убедитесь, что действие fileinto сработало.
- Отправьте реальное письмо через локальный SMTP (sendmail или swaks) и проверьте, что оно легло в папку Tests, а не в INBOX.
- Добавьте правило с discard для письма с темой DROP, отправьте такое письмо и убедитесь, что оно исчезло - сделайте вывод об опасности discard.
- Подключитесь к порту 4190 (например openssl s_client -connect localhost:4190 -starttls sieve) и убедитесь, что ManageSieve отвечает и анонсирует расширения.
- Через doveadm sieve list и activate переключите активный скрипт и проверьте, что поведение доставки изменилось.
- Какой агент в современной установке выполняет локальную доставку и пользовательские Sieve-правила, и как Postfix передаёт ему письмо?
- Что произойдёт с письмом, если ни одно правило Sieve не вызвало явного действия, и как fileinto и discard влияют на неявный keep?
- Чем Sieve принципиально безопаснее procmail для запуска на стороне сервера?
- Какие действия Sieve вы знаете и в чём разница между discard и reject?
- Зачем нужен протокол ManageSieve, на каком порту он работает и почему важен TLS?
- Как одной строкой .forward переслать почту на внешний адрес и одновременно сохранить копию в локальном ящике?