Официальная возможность получить лицензионный софт бесплатно.
Giveaway of the Day
Это не реклама!

Щелкните для получения прогноза по Биробиджану


понедельник, 7 сентября 2015 г.

Zimbra: postfix, aliases и почтовые роботы

Содержание: как заставить postfix в составе Zimbra нормально принимать почту на псевдо-адреса в файле /etc/aliases или его аналоге.

Понадобилось мне обработать дополнительно письма, приходящие на конкретный адрес. Это было частью весьма эротичной (в смысле - поебаться с ней пришлось конкретно) задачи: письмо, отправленное на несколько абонентов "Мегафона", разбить на отдельные сообщения. То есть, "Мегафон" позволяет отправлять емайлы на "адреса" вида номер_телефона@sms.megafondv.ru (для Дальнего Востока). Но из строк to:/cc:/bcc: обрабатывается только последний адрес получателя, все остальные молча игнорируются. "Мегафон" предлагает услугу, что-то вроде пакетной рассылки смс таким способом, но за приличные таньга.
Проблема только в том, что если не удастся отправить своевременно короткие сообщения именно этим нескольким конкретным получателям, то "Мегафон" в нашей области может сдохнуть через несколько часов после наступления необходимости в такой отправке - диспетчер энергосистемы должен таким способом проинформировать начальство о серьезных сбоях вроде взрыва Фукусимы или пожаре на входном городском трансформаторе.
Тем не менее, такая общественно-полезная рассылка меньше чем на десяток корпоративных номеров всё равно осталась платной услугой, и мы решили её не покупать.


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

Очевидно, решение простое:

1) прописываем в /etc/aliases псевдонимы либо для файла:

псевдоним: "полный путь к файлу"
robot: "/tmp/robomail"


либо для команды:

псевдоним: "|полный путь к команде"
bobot: "|/usr/local/sbin/mailtest.sh"


2) разрешаем постфиксу отправлять почту в файлы и командам:

[postfix/conf/main.cf]
# разрешаем отправлять почту только на команды и файлы, описанные псевдонимами
allow_mail_to_files=alias
allow_mail_to_commands=alias
recipient_delimiter = +


3) запускаем newaliases для обновления хэшированной таблицы псевдонимов и делаем postfix reload.

И радуемся жизни. Так просто? А вот хрен там!


NB! Дальше после всех манипуляций с zmprov обязательно выполнять zmmtactl restart, чтобы обновить настройки агента доставки сообщений в конфигах.
Там, где действия надо выполнять от имени пользователя zimbra, я явно указываю sudo su - zimbra.
Разумеется, никто не запрещает открыть несколько сеансов от разных пользователей и переключаться между ними. Я всё это вообще проделывал в одном сеансе, открыв в byobu/tmux несколько "окон" - от имени зимбры, от своего имени и от рута.


Начнем с того, что вписать последний параметр в main.cf не получилось - после перезапуска всей зимбры или хотя бы zmmtactl restart знак "+" исчезал. Вот просто брал и исчезал, словно я его и не ставил.

Чтобы он не исчезал, надо внести изменения в конфигурацию зимбры:

$ sudo su - zimbra
$ zmprov mcf zimbraMtaRecipientDelimiter +


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

Готово? Нет, не готово: postfix продолжает ругаться на неправильное имя получателя что для робота, что для бобота. Копаем дальше.

Во-первых, находим в master.cf.in (именно cf.in, а не просто .cf - в .in файлах зимбра хранит шаблоны, из которых при каждом запуске формирует настоящие файлы. То есть, если внести изменения в master.cf, то они исчезнут при перезапуске зимбры) ищем строки:

    -o mynetworks_style=host
    -o mynetworks=127.0.0.0/8,[::1]/128


Во всяком случае, у меня они выглядели именно так. Меняем их:

#    -o mynetworks_style=host
    -o mynetworks=127.0.0.0/8,IP-вашего-почтового-сервера/32,[::1]/128


То есть, указали, что список "мои сети" это именно список сетей, а не узлов, и добавили в этот список сеть из одного узла - почтового сервера. Я не очень понимаю, зачем это надо, но у меня без этого не заработало.

Ну что, поехали? Нет, не поехали. Осталось еще немного поплясать с бубном. Ну, или дать в бубен разработчикам зимбры за то, что не предусмотрели более удобного способа для таких настроек.

$ sudo su - zimbra
$ zmprov gacf|grep zimbraMtaM
zimbraMtaMaxMessageSize: 10485760
zimbraMtaMyDestination: localhost


Я ленив, и предпочитаю, чтобы комп искал нужное мне, поэтому выдалось две настройки - максимальный размер сообщения (настраивается через GUI, аналог main.cf://message_size_limit) и аналог параметра main.cf://MyDestination (в файле /opt/zimbra/conf/zmconfigd.cf есть полный список соответствия параметров конфигурации зимбры и параметров отдельных ее составляющих, например, того же постфикса, желающие могут посмотреть)

Вот последний параметр нам надо изменить, добавив в него FQDN нашего сервера. Может прокатит и с не нашим - не проверял.

$ sudo su - zimbra
$ zmprov mcf zimbraMtaMyDestination "FQDN.вашего.сервера.ru localhost"
$ zmprov gacf|grep zimbraMtaM
zimbraMtaMaxMessageSize: 10485760
zimbraMtaMyDestination: FQDN.вашего.сервера.ru localhost


(в некоторых источниках, например http://forums.zimbra.com/administrators/9986-urgent-etc-alias-configuration-after-upgrade.html рекомендуют вместо FQDN писать просто слово LOCAL:

$ sudo su - zimbra
$ zmprov mcf zimbraMtaMyDestination "LOCAL localhost"


Но у меня это не сработало.)

А вот теперь можно проверять...
(протоколы ручного SMTP, содержимое логов и доставленных сообщений приведено частично, только моменты, необходимые для объяснений)

telnet мой-сервер 25

...
mail from:tester
250 2.1.0 Ok   #у меня разрешен из локалки прием почти от не FQ имен
rcpt to: robot

504 5.5.2 <robot>: Recipient address rejected: need fully-qualified address
rcpt to: bobot
504 5.5.2 <bobot>: Recipient address rejected: need fully-qualified address
# опаньки! а где ж взять FQA для этих алиасов? попробуем указать наш домен
rcpt to:robot@мой-домен
250 2.1.5 Ok
data
354 End data with <CR><LF>.<CR><LF>
test
.
250 2.0.0 Ok: queued as 84A2F921A3A


Уфф, заработало! Эй, а почему файл не создался?

$ grep robot /var/log/mail.log|tail
...
...postfix/error[7844]: 41DCA921A3A: to=<robot@мой-домен>, relay=none, delay=0.05, delays=0.01/0.03/0/0.01, dsn=5.0.0, status=bounced (мой-домен)


Печально: сообщение отброшено, поскольку в мой-домен и в самом деле нет такого пользователя. А вот теперь вернемся немного назад и вспомним, что выше настраивали параметр zimbraMtaMyDestination. А что, если...

Снова телнет до сервера, повторяем то же самое, но в качестве адресов получателей пишем:

rcpt to: robot@FQDN-моего-сервера
250 2.1.5 Ok
rcpt to: bobot@FQDN-моего-сервера
250 2.1.5 Ok
data
354 End data with <CR><LF>.<CR><LF>
test robot-bobot
.
250 2.0.0 Ok: queued as A1790922241

$ grep -E "robot|bobot" /var/log/mail.log|tail
...
...postfix/smtp[24605]: A1790922241: to=<bobot@FQDN-моего-сервера>, relay=127.0.0.1[127.0.0.1]:10026, delay=44, delays=43/0/0.01/0.16, dsn=2.0.0, status=sent (250 2.0.0 from MTA(smtp:[127.0.0.1]:10030): 250 2.0.0 Ok: queued as E862F922246)
postfix/smtp[24605]: A1790922241: to=<robot@FQDN-моего-сервера>, relay=127.0.0.1[127.0.0.1]:10026, delay=44, delays=43/0/0.01/0.16, dsn=2.0.0, status=sent (250 2.0.0 from MTA(smtp:[127.0.0.1]:10030): 250 2.0.0 Ok: queued as E862F922246)
postfix/smtp[19265]: E862F922246: to=<bobot@FQDN-моего-сервера>, relay=127.0.0.1[127.0.0.1]:10032, delay=0.26, delays=0.05/0/0/0.21, dsn=2.0.0, status=sent (250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as 2D2B7922241)
postfix/smtp[19265]: E862F922246: to=<robot@FQDN-моего-сервера>, relay=127.0.0.1[127.0.0.1]:10032, delay=0.26, delays=0.05/0/0/0.21, dsn=2.0.0, status=sent (250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as 2D2B7922241)
...
postfix/local[29251]: 2F2049226EF: to=<robot@FQDN-моего-сервера>, relay=local, delay=0.09, delays=0.01/0.05/0/0.03, dsn=2.0.0, status=sent (delivered to file: /tmp/robomail)
postfix/local[29250]: 2F2049226EF: to=<bobot@FQDN-моего-сервера>, relay=local, delay=0.09, delays=0.01/0.05/0/0.03, dsn=2.0.0, status=sent (delivered to command: /usr/local/sbin/mailtest.sh)


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

$ cat /usr/local/sbin/mailtest.sh
#!/bin/sh
# Этот скрипт выполняется при отправке сообщения на bobot@FQDN-моего-сервера
# Для проверки работоспособности просто сохраняем переданный stdin в файл
tee /tmp/testmail.log
exit 0

$ cat /tmp/robomail
...
X-Original-To: robot@FQDN-моего-сервера
Delivered-To: robot@FQDN-моего-сервера
...
Received: ... with SMTP id A1790922241;
...
From: tester@FQDN-моего-сервера

test robot-bobot


$ cat /tmp/testmail.log
...
X-Original-To: bobot@FQDN-моего-сервера
Delivered-To: bobot@FQDN-моего-сервера
...
Received: ... with SMTP id A1790922241;
...
From: tester@FQDN-моего-сервера

test robot-bobot
Отличие между командой и файлом в том, что команде передается одно конкретное сообщение, тогда как сообщения, предназначенные для файла-получателя, дописываются в конец и файл может неконтролируемо расти, если не предусмотреть средств его очистки.

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

Дополнительные материалы:


Обработка входящей почты на PHP
http://habrahabr.ru/post/126448/
Postfix Configuration Parameters
Postfix main.cf file format http://www.postfix.org/postconf.5.html#mydestination

Комментариев нет:

Отправить комментарий

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