Копирование почты с помощью sendmail

Оригинал: www.freeman.org.ua

Нижеизложенный материал не претендует на полноту, четкость, ясность или достоверность изложения и предоставляется автором "КАК ЕСТЬ". Автор не несет никакой отвественности за любое использование данного материала. Любое использование, копирование, цитирование, полностью или частично должно включать данный текст, ссылку на данный ресурс, а так же следующию строку без изменений:

© 2001-2002, O. Koreshkov <okorsalut.ru>.

Принцип работы копирования почтовых сообщений с помощью sendmail, описанный в данной статье, состоит в описании своего майлера(mailer), называемого в дальнейшем copymail, а так же в задании набора правил, который "передает" всю проходящую почту на наш майлер. Copymail, получив почтовое сообщение, действует как обычный транспортный агент, доставляя письмо оригинальному получателю, а так же на дополнительный адрес, заданный администратором. Почтовый адрес, на который будет копироваться почта, не обязательно должен быть локальным для данной машины. Описанный майлер (copymail) представляет из себя sendmail с "оригинальным" (без изменений) конфигурационным файлом.


Рис. 1

sendmail(1), работающий в режиме daemon (-bd) получает (A) письмо и передает (B) его sendmail(2). ( sendmail(2) — это вышеописанный майлер copymail). sendmail(2) отсылает письмо оригинальному получателю (C) и дополнительному получателю (D).

Далее описаны несколько вариантов, конфигурации sendmail, для различных требований к копированию почтовых сообщений.
При описании, автор подразумевает, что читатель обладает некоторым "специфическим" набором знаний, а именно:


Вариант 1.
(C одним конфигурационным файлом sendmail)
Вся проходящая почта будет (дополнительно) пересылаться на заданный почтовый адрес.

Недостатки:

¹. В этом и последующих примерах можно помещать строки из copymail.m4 непосредственно в конфигурационный файл sendmail(.mc), не забывая о правильном порядке директив.
². MAILER следует помещать в конце конфигурационного файла, а define — до MAILER.


Вариант 2.
(C двумя конфигурационными файлами sendmail)

ВНИМАНИЕ! Если вы допустите ошибку при конфигурировании sendmail (например вместо конфигурационного файла "nocopy", вы укажете "copy"), sendmail уйдет в "вечный" цикл, с доставкой писем самой себе и с потреблением всех ресурсов системы.


Вариант 3.
(C возможностью избирательно копировать почту)

Желательно иметь возможность как то управлять процессом копирования почты. Например, избирательно копировать сообщения от какой либо группы пользователей или наоборот — не копировать. Для этого предназначен copymail.m4 (Вариант 3). Sendmail следует сконфигурировать как по Варианту 2, только вместо copymail.m4 (Вариант 2) возьмите copymail.m4 (Вариант 3)

Следует, так же создать файл /etc/mail/nocopy-users и поместить в него почтовые адреса (в виде user@FQDN-domen ) или IP адреса (в форме X.X.X.X). Почтовые сообщения приходящие на почтовые адреса¹, перечисленные в /etc/mail/nocopy-users или отправлямые от почтового адреса² или с IP адреса, перечисленных в /etc/mail/nocopy-users, не будут копироваться.

Для достижения обратного результата, т.е. копирования почтовых сообщений от определенных почтовых адресов или на определенные почтовые адреса, и прохождения всех остальных почтовых сообщений без копирования, следует воспользоваться copymail.m4 (Вариант 4).
Так же, следует создать файл /etc/mail/copy-users и поместить в него "копируемые" адреса (формат адресов см. выше).

¹. Имеется в виду rcpt to: <addr>
². Имеется в виду mail from: <addr>

Тестирование и отладка.

Прежде чем запускать sendmail в "боевом" режиме, я советую проверить полученную конфигурацию. Для этого следует запустить sendmail в режиме тестирования адреса (ключ -bt). Рассмотрим результат преобразования адреса, который должен получиться при использовании copymail.m4 (Вариант 1): mx# sendmail -bt -C /etc/mail/sendmail.cf ADDRESS TEST MODE (ruleset 3 NOT automatically invoked) Enter <ruleset> <address> > 3,0 user@domen.ru canonify input: user @ domen . ru Canonify2 input: user < @ domen . ru > Canonify2 returns: user < @ domen . ru . > canonify returns: user < @ domen . ru . > parse input: user < @ domen . ru . > Parse0 input: user < @ domen . ru . > Parse0 returns: user < @ domen . ru . > ParseLocal input: user < @ domen . ru . > ParseLocal returns: $# copymail $@ domen . ru . COPYMAIL $: user @ domen . ru . COPYMAIL parse returns: $# copymail $@ domen . ru . COPYMAIL $: user @ domen . ru . COPYMAIL > В результате должен вызваться майлер copymail и адрес должен переписаться в виде user@domen.ru.COPYMAIL. Теперь следует проверить "обратное" преобразование, т.е. письмо принятое от copymail должно разрешиться в "нормальный" адрес: > 3,0 user@domen.ru.COPYMAIL canonify input: user @ domen . ru . COPYMAIL Canonify2 input: user < @ domen . ru . COPYMAIL > Canonify2 returns: user < @ domen . ru . COPYMAIL > canonify returns: user < @ domen . ru . COPYMAIL > parse input: user < @ domen . ru . COPYMAIL > Parse0 input: user < @ domen . ru . COPYMAIL > Parse0 returns: user < @ domen . ru . COPYMAIL > ParseLocal input: user < @ domen . ru . COPYMAIL > ParseLocal returns: user < @ domen . ru . > Parse1 input: user < @ domen . ru . > MailerToTriple input: < > user < @ domen . ru . > MailerToTriple returns: user < @ domen . ru . > Parse1 returns: $# esmtp $@ domen . ru . $: user < @ domen . ru . > parse returns: $# esmtp $@ domen . ru . $: user < @ domen . ru . > > В результате адрес должен разрешиться в один из майлеров, кроме copymail. К примеру адрес может разрешиться в локальный майлер ($# local $: user) или в майлер esmtp ($# esmtp $@ domen . ru . $: user < @ domen . ru . >).

Теперь рассмотрим результат преобразования адреса при использовании copymail.m4 (Вариант 2 (3,4)): mx# sendmail -bt -C /etc/mail/sendmail.copy.cf ADDRESS TEST MODE (ruleset 3 NOT automatically invoked) Enter <ruleset> <address> > 3,0 user@domen.ru canonify input: user @ domen . ru Canonify2 input: user < @ domen . ru > Canonify2 returns: user < @ domen . ru . > canonify returns: user < @ domen . ru . > parse input: user < @ domen . ru . > Parse0 input: user < @ domen . ru . > Parse0 returns: user < @ domen . ru . > ParseLocal input: user < @ domen . ru . > ParseLocal returns: $# copymail $@ localhost $: user < @ domen . ru . > parse returns: $# copymail $@ localhost $: user < @ domen . ru . > > В результате должен вызваться майлер copymail: $# copymail $@ localhost $: user < @ domen . ru . >.

Если в результате тестирования адресов у вас не получается то, что вы ожидаете, например используется copymail.m4 (Вариант 3), пользователь user@domen.ru включен в /etc/mail/nocopy-users, а в результате почта для этого пользователя все равно копируется, то попробуйте воспользоваться следующими рекомендациями:


Privacy violation.
(Морально-этические стороны вопроса)

Копирование почты является нарушением морально-этических (а возможно даже и юридических) прав, если только пользователь не был предупрежден об этом до начала процесса копирования почты (а ещё лучше до того как получил почтовый ящик)... Предлагаемый ниже вариант copymail.m4 позволяет вставить в каждое копируемое письмо некоторый заголовок (например назовем его X-Privacy-violation), в котором будет честно сказано что данное письмо было скопировано, а так же будет указано кому и зачем оно было скопировано. По такому же принципу можно изменить/дополнить один из стандарных заголовков, например To: или Subject:. ... Received: (from user@localhost) by mx.domen.ru ESMTP id g1KEPD001282 for user2@domen.ru; Wed, 20 Feb 2002 17:25:13 +0300 (MSK) (envelope-from user) Date: Wed, 20 Feb 2002 17:25:13 +0300 (MSK) From: User Message-Id: <200202201425.g1KEPD001282@mx.domen.ru> X-Privacy-violation: The copy of this message was sent to <postmaster@domen.ru> due to business requirements To: user2@domen.ru Subject: TEST ... Другие варианты copymail.m4 следует дополнить по аналогии с приведенным примером.


copymail.m4 (Вариант 1): PUSHDIVERT(-1) ifdef(`COPYMAIL_MAILBOX',, `define(`COPYMAIL_MAILBOX', `postmaster')')dnl POPDIVERT ######################################### ### COPYMAIL Mailer specification ### ######################################### VERSIONID(`$Id: cpsendmail.html,v 1.2 2002/06/14 18:39:10 freeman Exp $')dnl LOCAL_CONFIG D{COPYMAIL}COPYMAIL C{CP}${COPYMAIL} LOCAL_RULE_0 # Send all mail to copymail mailer R$* < @ $+ . $~{CP} . > $#copymail $@ $2 . $3 . ${COPYMAIL} $: $1 @ $2 . $3 . ${COPYMAIL} # if mail has been processed by copymail mailer, process it usual way... R$* < @ $* . ${COPYMAIL} > $1 < @ $2 . > # Send message to original recipient + additional mailbox: COPYMAIL_MAILBOX Mcopymail, P=/usr/sbin/sendmail, F=fmSDFMu, S=0, R=0, A=sendmail -N never COPYMAIL_MAILBOX.${COPYMAIL} $u
copymail.m4 (Вариант 2): PUSHDIVERT(-1) ifdef(`COPYMAIL_MAILBOX',, `define(`COPYMAIL_MAILBOX', `postmaster')')dnl ifdef(`NOCOPY_CONFIG',, `errprint(`*** You must define NOCOPY_CONFIG for copymail mailer!!! ***')')dnl POPDIVERT ######################################### ### COPYMAIL Mailer specification ### ######################################### VERSIONID(`$Id: cpsendmail.html,v 1.2 2002/06/14 18:39:10 freeman Exp $')dnl LOCAL_RULE_0 # Send all mail to copymail mailer R$* < @ $+ . > $* $#copymail $@ localhost $: $1 < @ $2 . > $3 # Send message to original recipient + additional mailbox: COPYMAIL_MAILBOX Mcopymail, P=/usr/sbin/sendmail, F=fmSDFMu, S=0, R=0, A=sendmail -N never -C NOCOPY_CONFIG COPYMAIL_MAILBOX $u
copymail.m4 (Вариант 3): PUSHDIVERT(-1) ifdef(`COPYMAIL_MAILBOX',, `define(`COPYMAIL_MAILBOX', `postmaster')')dnl ifdef(`NOCOPY_USERS',, `define(`NOCOPY_USERS', `-o /etc/mail/nocopy-users')')dnl ifdef(`NOCOPY_CONFIG',, `errprint(`*** You must define NOCOPY_CONFIG for copymail mailer!!! ***')')dnl POPDIVERT ######################################### ### COPYMAIL Mailer specification ### ######################################### VERSIONID(`$Id: cpsendmail.html,v 1.2 2002/06/14 18:39:10 freeman Exp $')dnl LOCAL_CONFIG F{NOCOPY}NOCOPY_USERS LOCAL_RULE_0 # Send all mail (except $={NOCOPY}) to copymail mailer R$* < @ $+ . > $* $: $1 < @ $2 . > $3 $| $1 @ $2 R$* < @ $+ . > $* $| $={NOCOPY} $@ $1 <@ $2 . > $3 R$* < @ $+ . > $* $| $* $: $1 <@ $2 . > $3 $| $&{client_addr} R$* < @ $+ . > $* $| $={NOCOPY} $@ $1 <@ $2 . > $3 R$* < @ $+ . > $* $| $* $: $1 <@ $2 . > $3 $| $&f R$* < @ $+ . > $* $| <$*> $: $1 <@ $2 . > $3 $| $4 R$* < @ $+ . > $* $| $={NOCOPY} $@ $1 <@ $2 . > $3 R$* < @ $+ . > $* $| $* $#copymail $@ localhost $: $1 < @ $2 . > $3 # Send message to original recipient + additional mailbox: COPYMAIL_MAILBOX Mcopymail, P=/usr/sbin/sendmail, F=fmSDFMu, S=0, R=0, A=sendmail -N never -C NOCOPY_CONFIG COPYMAIL_MAILBOX $u
copymail.m4 (Вариант 4): PUSHDIVERT(-1) ifdef(`COPYMAIL_MAILBOX',, `define(`COPYMAIL_MAILBOX', `postmaster')')dnl ifdef(`COPY_USERS',, `define(`COPY_USERS', `-o /etc/mail/copy-users')')dnl ifdef(`NOCOPY_CONFIG',, `errprint(`*** You must define NOCOPY_CONFIG for copymail mailer!!! ***')')dnl POPDIVERT ######################################### ### COPYMAIL Mailer specification ### ######################################### VERSIONID(`$Id: cpsendmail.html,v 1.2 2002/06/14 18:39:10 freeman Exp $')dnl LOCAL_CONFIG F{COPY}COPY_USERS LOCAL_RULE_0 # Send mail $={COPY} to copymail mailer R$* < @ $+ . > $* $: $1 < @ $2 . > $3 $| $1 @ $2 R$* < @ $+ . > $* $| $={COPY} $#copymail $@ localhost $: $1 < @ $2 . > $3 R$* < @ $+ . > $* $| $* $: $1 <@ $2 . > $3 $| $&{client_addr} R$* < @ $+ . > $* $| $={COPY} $#copymail $@ localhost $: $1 < @ $2 . > $3 R$* < @ $+ . > $* $| $* $: $1 <@ $2 . > $3 $| $&f R$* < @ $+ . > $* $| <$*> $: $1 <@ $2 . > $3 $| $4 R$* < @ $+ . > $* $| $={COPY} $#copymail $@ localhost $: $1 < @ $2 . > $3 R$* < @ $+ . > $* $| $* $: $1 <@ $2 . > $3 # Send message to original recipient + additional mailbox: COPYMAIL_MAILBOX Mcopymail, P=/usr/sbin/sendmail, F=fmSDFMu, S=0, R=0, A=sendmail -N never -C NOCOPY_CONFIG COPYMAIL_MAILBOX $u
copymail.m4 (Вариант 5): PUSHDIVERT(-1) ifdef(`COPYMAIL_MAILBOX',, `define(`COPYMAIL_MAILBOX', `postmaster')')dnl ifdef(`NOCOPY_CONFIG',, `errprint(`*** You must define NOCOPY_CONFIG for copymail mailer!!! ***')')dnl POPDIVERT ######################################### ### COPYMAIL Mailer specification ### ######################################### VERSIONID(`$Id: cpsendmail.html,v 1.2 2002/06/14 18:39:10 freeman Exp $')dnl LOCAL_CONFIG H?{COPIED}?X-Privacy-violation: The copy of this message was sent to <COPYMAIL_MAILBOX> due to business requirements Kiscopied macro LOCAL_RULE_0 # Send all mail to copymail mailer R$* < @ $+ . > $* $#copymail $@ localhost $: $1 < @ $2 . > $3 $(iscopied {COPIED} $@ YES $) # Send message to original recipient + additional mailbox: COPYMAIL_MAILBOX Mcopymail, P=/usr/sbin/sendmail, F=fmSDFMu, S=0, R=0, A=sendmail -N never -C NOCOPY_CONFIG COPYMAIL_MAILBOX $u

Расположение ${CFDIR} в некоторых OS:

Solaris/usr/lib/mail
Linux/usr/lib/sendmail-cf
FreeBSD/usr/share/sendmail/cf

Список литературы:

Special thanks to: Lev Walkin.

P.S. Поправки приветствуются...