[Карта]                [Начало]                [Sendmail-ссылки]                [Синтаксис]                [Типовые задачки]                  [Задачки по маршрутизации]                  [Задачки по маcкарадингу]                  [SendmailACL]                  [Spamooborona]                  [VadeRetro]                  [Regex]                  [Тонкости]                  [Недок.особен.]                  [Несущ.юзеры]                  [Прячемся!]                  [RFC1893.Цитаты]                  [ТП.Эмоции]                  [Антиспам&Разум]                  [Экзерсисы]                 


Типовые задачки по sendmail. Часть вторая. ([Часть первая]   [Часть третья]    [Рейтинг])


  • 1. Как запретить получать почту на адреса вида user@[1.2.3.4], где [1.2.3.4] - ip-адрес вашего почтовика (разрешаем подобное только для пользователей из локальной сети)
  • 2. Как запретить получать почту на локальные адреса, которые заканчиваются точкой.
  • 3.1. Выставляем ограничения на размер сообщения для определенного домена
  • 3.2. Выставляем ограничения на размер сообщения для определенной группы пользователей одного домена
  • 4. Выставляем ограничения на формат сообщения (text/plain) для определенных пользователей.
  • 5.1. Как заставить sendmail.cf просматривать заголовок To: в самом письме на предмет существования получателя на почтовом сервере?
  • 5.2 Как заставить sendmail.cf проверять конвертного получателя на наличие в passwd+aliases?
  • 5.3. Предыдущая задача с диференцированным отлупом (#discard or #error) в зависимости от адреса отправителя.
  • 5.4. Как проверять заголовок To: на наличие чужого домена в адресе локального получателя?
  • 5.5. Делаем проверку заголовка To: на соответствие записям в /etc/mail/access.
  • 5.6. Как заблокировать письма с пустым заголовком To:
  • 5.7. Вывод в лог, если конвертный получатель отсутствует в header To:
  • 6. Как заблокировать письма, поступающие с почтовых доменов, mx-записи для которых содержат определенные домены
  • 7. Как заблокировать письма, поступающие с почтовых доменов, mx для которых ссылается 127.0.0.1.
  • 8. Как заблокировать письма, в заголовке которых подзаголовок X-Mailer или отсутствует, или он пустой.
  • 9. Как заблокировать письмо, если среди получателей указан определенный пользователь-приманка (honey pot).
  • 10. Назначаем вес каждому спам-шаблону, по суммарному весу блокируем письмо.
  • 11. Проверяем MX.
  • 12.1. Как сравнить две величины. Общее решение.
  • 12.2. Как сравнить две величины. Частный случай. Сравниваем левую часть адреса отправителя и имя, которое он использовал для авторизации.
  • 13. Блокируем письмо, если адрес отправителя начинается с символов ("_" или "-") и если при этом выполняется одно из трех условий
  • 14. Еще одна проверочка Received: на наличие "from 207.228.33.220 (HELO mail.sppc.com)\n by anrb.ru with ESMTP (KPSGSLIVB BWMYF)\n id jN3Dbg-WGIsJO-10\n"
  • 15. Разрешаем писать на адреса некоторого домена только тем юзерам, у которых определенный IP.
  • 16. Как сказать sendmail'у, чтобы разалиасинг происходил до вызова milter'a.
  • 16.A. Про нерациональность использования Milter.
  • 17. Копирование транзитной почты для определенного домена в определенный ящик
  • 18. Анализ доменного имени релея для сообщений с адресов домена mail.ru
  • 19. Выводим в лог тему сообщения, если оно пришло с нашего mx-a.
  • 20. Как посчитать количество тем в заголовке письма?
  • Продолжение. Часть третья.
  • Обратная связь




  • 1. Как запретить получать почту на адреса вида user@[1.2.3.4], где [1.2.3.4] - ip-адрес вашего почтовика (разрешаем подобное только для пользователей из локальной сети)

    LOCAL_CONFIG
    LOCAL_RULESETS
    SLocal_check_rcpt
    R<$+@[1.2.3.4]>                       $: $&{client_addr} $| $1
    R$=R $* $| <$+@[1.2.3.4]>                       $@ OK
    R$+ $| <$+@[1.2.3.4]>                       $#error $: 554 Sorry, unallowed domain name.

    Если вы решите проверить, как это работает, обратите внимание на эту тонкость.
    А вот так запрещаем все локальным пользователям, кроме избранных, получать почту на адреса user@mail.domain.ru (пусть остальные используют только адреса вида user@mydomain.ru).
    LOCAL_CONFIG
    LOCAL_RULESETS
    SLocal_check_rcpt
    R$*                        $: $>Parse0 $>3 $1
    R$user1<@mail.anrb.ru.>                       $@OK
    R$user2<@mail.anrb.ru.>                       $@OK
    R$+<@mail.anrb.ru>                       $#error $: 554 Sorry, unallowed domain name.

    Вы спросите, а зачем такие запреты? См. здесь.

    А если вы спросите, зачем это вообще нужно: есть почтовый домен anrb.ru - пусть только его пользователи и выставляют!
    А я скажу так. До сих пор не видела и теперь не вижу причин ограничивать свободу своих пользователей в выборе домена.
    1. Нараздавали они по миру свои адреса и в виде paradise@anrb.ru, и в виде paradise@mail.anrb.ru (хотя вот этому я их не учила:), ну и слава богу! До сих пор это никому не мешало. Главное, "чтобы костюмчик сидел", т.е. почта исправно доставлялась-отправлялась.
    2. Больше всего вопросов возникает по поводу адресов вида consiglio@[1.2.3.4]. Зачем это нужно?
    Мои пользователи, во-первых, не просто advanced, а superadvanced. Шпарят цитатами из RFC2821 только так и знают о возможности отправки почты по ip-адресу почтовика.
    Во-вторых, постоянно выезжают на стажировки в зарубежные НИИ, и порой случаются на той стороне неполадки-проблемы с днс-ами, естественно, в этот момент отправить почту домену anrb.ru становится невозможным. Зная ip родного почтовика наизусть, они спокойно отправляют почту домой по ip-адресу.
    Ну и чем это плохо?
    Ограничивать прием такой почты по обратному домену смысла не вижу: если пользователям удобно в качестве адреса отправителя выставлять их заребежный e-mail, значит, так должно быть.
    Собирать с юзеров их зарубежные e-mail и ip-адреса тамошних почтовиков с целью внесения ограничений по этим параметрам тоже не буду.
    Стало быть, мне остается только смириться с тем, что Спамооборона не проверяет почту, предназначеную таким доменам, хотя в моем случае все они имеют прямое отношение к домену anrb.ru.

    2. Как запретить получать почту на локальные адреса, содержащие заключительную точку.

    Это спамерское нововведение появилось где-то с пол-года. Заголовок такого письма:

    Return-Path: <devils@ohiolinks.com>
    Received: from killersoft.com ([122.43.86.163])
                      by mail.anrb.ru (8.13.6/8.13.6) with SMTP id l3FAToYq001563
                      for <postmaster@anrb.ru.>; Sun, 15 Apr 2007 16:29:53 +0600
    Received: from ohiolinks.com (ohiohills.com.s6a2.psmtp.com [64.18.5.11])
                      by killersoft.com (Postfix) with ESMTP id F4348A8F7A
                      for <postmaster@anrb.ru . >; Sun, 15 Apr 2007 03:28:27 -0400
    ...
    ...
    X-Spam-Flag: SKIP
    X-Spam-Yversion: Spamooborona 1.5.2

    Напомню, что означает точка в понимании sendmail.
    Когда sendmail разбирает электронный адрес, он в добавляет точку после адреса в знак того, что адрес нормально разрезолвился.
    Если этой точки нет, то адрес не разрезолвлен, и такая почта отвергается.
    Естественно возник вопрос, а можно ли так делать , и не является ли это нарушением какого-либо RFC?

    Per Hederland ответил следующее:
    "Not AFAIK - that is certainly not valid syntax for an email address. Just be careful with the fact that sendmail.cf internally uses a trailing dot to indicate "canonical domain part" - testing the RCPT argument directly as you do should be fine, but if some standard ruleset processing has been done you're likely to have a trailing dot on all valid addresses (it is removed on "output" of course)."

    Ну что же, берем на себя отвественность и пишем:
    SLocal_check_rcpt
    R<$+@mydomain.ru.> $#error $: "554 Trailing dot in the recipient address."
    Ежедневно около 30-40 срабатываний на каждом mx, ложных срабатываний не отмечалось, до и быть их тут не должно: мои правила дописаны в локальный набор правил, который проверяется перед основным набором check_rcpt, а канонизация, вызывающая появление точки в случае благополучного исхода, мной здесь не задействуется.

    В /var/lod/maillog:
    Sep 2 04:34:44 apache sendmail[13097]: l81MYexQ013097: ruleset=check_rcpt, arg1=,
    relay=a213-22-204-9.cpe.netcabo.pt [213.22.204.9], reject=554 5.0.0 ...Trailing dot in the recipient address.


    3.1. Выставляем ограничения на размер сообщения для определенного домена.

    Взято отсюда: Can I remove this limit or change it for one domain only, and leave it for the other domains?
    LOCAL_CONFIG
    Kmsgsize hash /etc/mail/msgsize.db
    msgsize's format:
    To:domain.com         [TAB]             1000

    LOCAL_RULESETS
    Scheck_compat
    RMAILER-DAEMON $| $*                       $@ OK
    R$*$|$*                       $: $>3 $2
    R$*<@$+.>$*                        $: $(msgsize To:$2 $:UNLIMITED $)
    RUNLIMITED                       $@ OK
    R$*                        $: $(arith l $@ $&{msg_size} $@ $1 $)
    RFALSE                        $#error $@ 5.7.1 $: "MSG TOO BIG"

    Обращаю ваше внимение на то, что макрос $&{msg_size} становится известным только в наборе check_compat, а это значит, что письмо сначала будет принято (трафик!), и только потом будет проверен размер сообщения, и при превышении допустимого значения выслан отлуп.

    Еще одно решение (от Matej Vela):
    " ... However, now that I've tested it again, I found {MaxMsgSize} gets mysteriously unset between check_mail and check_compat, so *all* messages bounce. :-( The following does work: " LOCAL_CONFIG


    LOCAL_CONFIG
    F{BigUsers}/etc/mail/big-users
    Kstorage macro

    LOCAL_RULESETS
    SLocal_check_mail
    R$*                 $: < ? > $>canonify $1
    R< ? > $={BigUsers} < @ $=w . >                 $: 5000000 privileged max size
    R< ? > $*                  $: 1000000 default max size
    R$+                  $: $1 $| $(arith l $@ $&{msg_size} $@ $1 $)
    R$+ $| FALSE                 $#error $@ 5.2.3 $: "552 Message size exceeds " $1

    Scheck_compat
    R$* $| $*                  $@ $>Local_check_mail $1


    3.2. Выставляем ограничения на размер сообщения для определенной группы пользователей одного домена.

    LOCAL_CONFIG
    Kcomp arith
    Ksyslog syslog
    KRestrUsers hash /etc/mail/restricted
    makemap hash restricted <restricted

    LOCAL_RULESETS
    Scheck_compat
    RMAILER-DAEMON $| $*                $@ OK
    R<> $| $*                $@ OK

    R$+                                    $:<all> $1
    R<all1><$+> $ |$                  $:<$1>$|<all2>$2
    R<all1>$+ $ |$+                           $:<$1>$|<all2>$2
    R<all1>$+                           $: $(syslog syslog:check_compat:queer_thing <all>$1 $) <all>$1
    R<all1>$+                           $@ OK
    R$+$|<all2><$+@$+>                  $:$1$|<$2@$3>
    R$+$|<all2><$+>                           $:$1$|<$2@$j>
    R$+$|<all2>$+@$+                  $:$1$|<$2@$3>
    R$+$|<all2>$+                           $:$1$|<$2@$j>

    R<$*@$=w> $| $*                $: <$(RestrUsers $1 $: OK $)>
    R<OK>                $@ OK
    R<RESTR>                $: $>MesSizeCheck

    R$* $| <$*@$=w>                $: <$(RestrUsers $2 $: OK $)>
    R<OK>                $@ OK
    R<RESTR>                $: $>MesSizeCheck

    R$*                $@ OK

    SMesSizeCheck
    R$*                $: $(arith l $@ $&{msg_size} $@ 1000000 $)
    RFALSE                $#error $@ 5.2.3 $: "552 Message size exceeds 1Mb."

    /etc/mail/restricted:
    ivanov               [TAB]               RESTR
    petrov               [TAB]               RESTR
    make hash restricted <restricted

    Решение было выложено здесь.

    4. Выставляем ограничения на формат сообщения (text/plain) для определенных пользователей.
    Не тестировалось. Человеку, спросившему про это, пока не досуг проверить, ну и у меня тоже времени нет.

    LOCAL_CONFIG
    Ksyslog syslog
    Kstorage macro

    #Ограниченные в правах юзеры
    KRcp regex -a@LIST ^user1|user2$
    #Признак текстовости сообщения в Content-Type
    KCT regex -a@LIST ^$text/plain;$

    LOCAL_RULESETS
    SLocal_check_rcpt
    R$*                  $: <$(storage {CT-Check} $@ 0 $)> $1
    R$*                  $: $>3 $1
    R$+<@$=w.>                 $: $(Rcp $1 $)
    R@LIST                 $: <$(storage {CT-Check} $@ 1 $)>

    HСontent-Type:                 $>+CheckCT
    SCheckCT
    R$*                 $: $1 $| <$&{CT-Check}>
    R$* $| $*                  $: $1 $| $(storage {CT-Check} $) $2
    R$* $| <0>                 $@ OK
    R$* $| $*                  $: $1
    R$*                  $: $(CT $1 $)
    R@LIST                  $@ OK
    R$*                  $#error $: "554 Sorry, далее текст по смыслу ..."

    5.1 Как заставить sendmail просматривать подзаголовок To: в самом письме (внутренний подзаголовок) на предмет существования пользователя на почтовом сервере?
    Спрашивали здесь. Но о результатах не доложили.
    Переделано из решения Clauss Assmann.

    LOCAL_CONFIG
    Kpasswd user -m -a@LOCALUSER
    Kalias implicit -m -a@LOCALUSER /etc/mail/aliases
    Klocal sequence alias passwd

    LOCAL_RULESETS

    HTo:                 $>CheckTo
    HCc:                  $>CheckTo

    SCheckTo
    R$* <$+@$=w>                  $: $>CheckLocal $2

    SCheckLocal
    R$+                  $: $(local $1 $)
    R$+@LOCALUSER                 $@ OK
    R$*                  $#error $@ 4.1.8 $: "450 Unknown user " $1

    НО!
    1. Возможны проблемы со списками рассылок. Даже законные распространители рассылок во избежание "засвечивания" получателей письма, предпочитают в поле To: указывать что-то вроде list_name@list_domain.ru, а реальных получателей прописывать в Bcc:
    2. Если почтовый ящик настроен на форвардинг почты дальше (.forward, aliases, virtusertable, mailertable), то получатель увидит в поле To: адрес первоначального получателя, а не свой адрес.
    3. Поскольку, если подзаголовок пустой, то его невозможно обработать, в случае с Bcc: данная проверка работать не будет. Подзаголовок Bcc: в заголовке просто отсутствует.

    5.2. Как заставить sendmail.cf проверять конвертного получателя на наличие в passwd+aliases?

    В некоторых случаях sendmail'у нужно подсказать сразу, что получатель отсутствует в системе.
    В принципе почти все то же самое, что и в предыдущем примере, только набор правил - Local_check_rcpt.

    LOCAL_CONFIG
    Kpasswd user -m -a@LOCALUSER
    Kalias implicit -m -a@LOCALUSER /etc/mail/aliases
    Klocal sequence alias passwd

    LOCAL_RULESETS
    SLocal_check_rcpt
    R$* <$+@$=w>                  $: $>CheckLocal $2

    SCheckLocal
    R$+                  $: $(local $1 $)
    R$+@LOCALUSER                 $@ OK
    R$*                  $#error $@ 4.1.8 $: "450 Unknown user " $1

    18.12.2007.
    Сегодня выяснила, что, если письмо отправлено telnet'ом, то адрес получателя в угловые скобки не заключается:
    Dec 18 15:02:02 apache sendmail[12194]: lBIA0QHk012194: syslog:rcpt:0:paradise@[212.193.135.6]
    Dec 18 15:02:10 apache sendmail[12194]: lBIA0QHk012194: from=gatling@anrb.ru, size=2, class=0, nrcpts=1, msgid=<200712181002.lBIA0QHk012194@apache.anrb.ru>, proto=SMTP, daemon=MTA, relay=[1.2.3.4]
    Dec 18 15:02:10 apache sendmail[12360]: lBIA0QHk012194: to=paradise@[212.193.135.6], delay=00:00:08, xdelay=00:00:00, mailer=local, pri=30294, dsn=2.0.0, stat=Sent

    А мы с вами хорошо знаем, чем такое письмо "замечательно".
    В зависимости от того, контролируете вы почту с одним подзаголовком "Received:" или нет,
    перепишем правила.
    1.    Если контролируете, то отправить почту непосредственно через ваш почтовик смогут лишь пользователи вашей локальной сети, а мы будем априори полагать, что среди них нет "вредителей", поэтому оставим все, как есть:
    -если почта приходит с другого сервера, то адрес получателя окажется заключенным в угловые скобки, и наша проверка сработает;
    - если почта отправлена непосредственно через наш почтовик, то сделано это может быть исключительно нашим пользователем, а ему мы доверяем, поэтому не делаем ничего с адресом, не заключенным в угловые скобки.
    2.    Если не контролируете, то отправить почту непосредственно через ваш почтовик сможет кто угодно, значит, правила надо переписать.
    LOCAL_CONFIG
    Kpasswd user -m -a@LOCALUSER
    Kalias implicit -m -a@LOCALUSER /etc/mail/aliases
    Klocal sequence alias passwd

    LOCAL_RULESETS
    SLocal_check_rcpt
    #Проверяем адрес получателя, когда он в угловых скобках
    R$* <$+@$=w>                  $: $>CheckLocal $2
    ROK                $@ OK
    #Проверяем адрес получателя, когда угловые скобки опущены
    R$+@$=w                  $: $>CheckLocal $1
    ROK                $@ OK
    Если домен получателя внешний - пропускаем письмо.
    R$+ @ $+                 $@ OK
    #Все получатели с доменами обработаны. Остались бездоменные получатели
    #Если отправитель не указал домен получателя (а это позволяет telnet, TheBat!, etc), то считаем получателя локальным, и также отправляем его на проверку.
    R$+                $: $>CheckLocal $1

    SCheckLocal
    R$+                  $: $(local $1 $)
    R$+@LOCALUSER                 $@ OK
    R$*                  $#error $@ 4.1.8 $: "450 Unknown user " $1

    Другое решение (от Matej Vela) - здесь.

    5.3. Как заставить sendmail.cf проверять конвертного получателя на наличие в passwd+aliases и при отсутствии получателя выдавать диференцированный ответ:
    если письмо пришло с mx-а - #discard, если с любого другого relay'я - #error?

    (07.12.2007) Такая постановка задачи возникла после общения с одним sendmail-гуру, для которого, в принципе, нет ничего такого, чего бы он не смог заставить делать sendmail.

    А для чего это нужно?
    Чаще всего дополнительные mx находятся не в нашем ведении, поэтому, накладывая ограничения на прием почты для своих доменов, мы тем самым наказываем mx-ы, которые имеют несимметричные с нами конфиги, ничего не знают о наших требованиях к формату писем и страдают от наших отлупов. Поэтому имеет смысл проверить, откуда идет письмо, и в случае, если relay=mx, выдать #discard, что позволят письмо тихо уничтожить. Единственный, но весомый, минус - лишний трафик: письмо все же будет принято целиком (см. 5.1.4. Ловушки Наборов Правил), а потом уничтожено.

    LOCAL_CONFIG
    Kpasswd user -m -a@LOCALUSER
    Kalias implicit -m -a@LOCALUSER /etc/mail/aliases
    Klocal sequence alias passwd

    LOCAL_RULESETS
    SLocal_check_rcpt
    R$* <$+@$=w>                  $: $>CheckLocal $2

    SCheckLocal
    R$+                  $: $(local $1 $)
    R$+@LOCALUSER                 $@ OK
    R$*                $: < $&{client_addr} >
    #адреса mx-ов:
    R<1.2.3.4>                  $#discard
    R<2.3.4.5>                  $#discard
    #все остальные relays:
    R$*                  $#error $@ 4.1.8 $: "450 Unknown user "

    5.4 Как проверять заголовок To: на наличие чужого домена в адресе локального получателя?

    10.01.2008. Еще одно решение, взятое с www.opennet.ru (в ответ на вопрос, как отбивать письма, если не совпадает To: и RCPT TO. Но именно эту задачу данное решение не решает. Просто это решение дает одно из ограничений.)
    Автор - Z0termaNN.

    HTo                 $>checkhdr_TO
    Scheckhdr_TO
    R $*                 $: $( syslog "DEBUG: TO header is: " $1 $) $1
    R $*                  $: $1 $| $>CheckLocalNet $&{client_name}
    R $* $| CONN_LOCAL                  $@ $1
    R $* $| CONN_REMOTE                 $: $1 | $>canonify $1
    R $* $| $* < @ $* . >                  $: $1 | $>CheckLocalNet $3
    R $* $| CONN_REMOTE                  $#error $@ 5.1.2 $: "554 Invalid address"

    R $* $| $*                  $1
    R $*                  $@ $1
    SCheckLocalNet
    R $=w                  $@ CONN_LOCAL
    R $=R                  $@ CONN_LOCAL
    R $+. $=R                  $@ CONN_LOCAL
    R $*                  $@ CONN_REMOTE
    R $*                  $@ CONN_REMOTE

    5.5 Делаем проверку заголовка To: на соответствие записям в /etc/mail/access.

    05.12.2008. Для того, чтобы заголовок To: также проверялся в файле access, нужно добавить пару правил.
    /etc/mail/access:
    #Blocks local mail recipient (<mail>)
    Если указать почтовый ящик с @, но без логина, то при включенной FEATURE(blacklist_recipient) воздествию будут подвергаться все пользователя с именем mail всех локальных доменов данного почтового сервера. Та кчто 2 и 3 строки здесь явно лишние.
    To:mail@                                    550 Restricted account. Please use postmaster account instead.
    To:mail@anrb.ru                                    550 Restricted account. Please use postmaster account instead.
    To:mail@mail.anrb.ru                           550 Restricted account. Please use postmaster account instead.
    To:drweb@anrb.ru                           550 Restricted account. Please use postmaster account instead.
    To:drweb-daemon@anrb.ru                           550 Restricted account. Please use postmaster account instead.
    To:mailer-daemon@anrb.ru                  550 Restricted account. Please use postmaster account instead.
    To:mailer-daemon@mail.anrb.ru                  550 Restricted account. Please use postmaster account instead.

    #Blocks bogus user
    To:support@anrb.ru                   550 Bogus user
    To:manager@anrb.ru                   550 Bogus user
    To:info@anrb.ru                   550 Bogus user
    To:clients@anrb.ru          550 Bogus user
    To:orders@anrb.ru                           550 Bogus user
    To:recipient@anrb.ru                  550 Bogus user
    To:service@anrb.ru                           550 Bogus user
    To:register@anrb.ru                  550 Bogus user
    To:admin@anrb.ru                   550 Bogus user
    To:administartor@anrb.ru                  550 Bogus user
    To:sms@anrb.ru                           550 Bogus user
    To:james@anrb.ru                           550 Bogus user
    To:john@anrb.ru                           550 Bogus user
    To:donotreply@anrb.ru                           550 Bogus user

    HTo:                  $>CheckTo
    SCheckTo
    # Mal for bogus user
    R$*                                    $: $1 $| <$&{deliveryMode}>
    # R$*                                    $: $(syslog syslog:To:1: $1 $) $1
    R$+@$=w $| <b>                           $: $(access To:$1@$2 $:$1@$2$|<b> $)
    # R$*                                    $: $(syslog syslog:To:2: $1 $) $1
    R550 Bogus user                           $#error $: "554 Bogus user in the header To."
    R550 Restricted account $+                            $#error $: "554 Restricted account in the header To. Please use postmaster account instead."
    R$*<$+@$=w> $| <b>                  $: $(access To:$2@$3 $)
    R550 Bogus user                           $#error $: "554 Bogus user in the header To."
    R550 Restricted account $+                            $#error $: "554 Restricted account in the header To. Please use postmaster account instead."

    5.6 Как заблокировать письма с пустым заголовком To:

    Есть старый анекдот про то, как один человек регулярно приходил в аптеку и спрашивал пельмени. Однажды аптекарь не выдержал, купил пельмени, и когда тот человек пришел снова, продал ему эти пельмени. На что получил ответ: "Вот видите, а вы говорили, что аптека не продает пельмени!"

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

    В энный раз повторю, почему это не следует делать:
    - Bcc
    - в уведомлении о доставке/прочтении письма не бывает поля To:

    Received: from mail1.somedomain.com (mail1.somedomain.com [1.2.3.4]) by mail.anrb.ru (8.14.2/8.14.2) with ESMTP id mBFBGN79006785 for <terrapin@anrb.ru>; Mon, 15 Dec 2008 16:16:26 +0500
    Content-class: urn:content-classes:mdn
    MIME-Version: 1.0
    Content-Type: multipart/report;
    report-type=disposition-notification;
    boundary="----_=_NextPart_001_01C95EA6.43B4BD76"
    Subject: ????????: ????????????-2009
    X-MimeOLE: Produced By Microsoft Exchange V6.5
    Date: Mon, 15 Dec 2008 14:09:23 +0300
    Message-ID: <C119134F82F8BB4395F2288FCF0B7B7E89FDE3@mvk-exbor-02.somedomain.win2k.dom>
    In-Reply-To: <005801c95ea4$c6a3a270$ee01a8c0@bvk>
    X-MS-Has-Attach:
    X-MS-TNEF-Correlator:
    Thread-Topic: ????????????-2009
    Thread-Index: AclepSDaFQ21AcHFQtash5TbeTnRhAAAHT3k
    From: "Irina Austrid" <IAustrid@somedomain.com>
    X-Drweb-SpamState: no
    X-Drweb-SpamState-Num: 0
    X-Drweb-SpamScore: 30
    X-Drweb-SpamVersion: Vade Retro 01.280.12 AV+AS Profile: <none>; Bailout: N/A
    X-Antivirus: Dr.Web (R) for Unix mail servers drweb plugin ver.4.44.2.0805030
    X-Antivirus-Code: 0x100000
    ------_=_NextPart_001_01C95EA6.43B4BD76
    Content-Type: text/plain;
    charset="ISO-8859-1"
    Content-Transfer-Encoding: quoted-printable

    Your message
    To: Irina Austrid
    Cc: =20
    Subject: ????????????-2009
    Sent: Mon, 15 Dec 2008 14:03:32 +0300
    was read on Mon, 15 Dec 2008 14:09:23 +0300

    26.12.2008. Кстати, обратите внимание на эту особенность. Вам проблемы нужны? "Их есть у нас!"

    5.7. Вывод в лог, если конвертный получатель отсутствует в header To: (Cc:, Bcc: (если Bcc присутствует в заголовке, бывает и такое)).

    SCheckTo
    R$* $&u $*                  $@ OK
    R$*                           $: $(syslog syslog:To2:U-TO:0: <$&u>-$1 $)
    Ну а теперь анализируйте egrep syslog:To2: maillog и убеждайтесь в бесполезности блокировки по такому признаку.
    3 причины, по которым это делать не стоит:
    - списки рассылок
    - форвардинг почты
    - Bcc

    6. Как заблокировать письма, поступающие с почтовых доменов, mx-записи для которых содержат определенные домены

    У меня есть "любимый" спамерский домен outblaze.com.
    Сначала я блокировала его, как полагается, через access.
    И даже прописывала отдельные его сети в файрволе.
    Потом он перестал появляться в адресе отправителя и в адресе релея, но зато появился во внутренних Received, обходя таким образом iptables&access.
    В ответ я добавила проверку в CheckReceived. С проверкой содержимого пакетов с/п iptables тогда заморачиваться не стала.
    Теперь же спам приходит с почтовых доменов, mx-релеи которых содержат "славный, добрый" outblaze.com.
    Чем мне это грозит? Несмотря на то, что на всех моих mx-ах sendmail.mc одинаковые, иногда случается так, что спам-письмо проскакивает один mx, а при передаче письма основному почтовику получает от него отлуп.
    Его, естественно, нужно вернуть отправителю письма.
    Мой почтовик определяет mx почтового домена отправителя.
    И им оказывается, например, something.somewhere.oublaze.com.
    Как я уже говорила, часть outblaze-сетей заблокирована файрволом.
    Кто в этой ситуации будет крайним? Правильно, я.
    Каждые 4 часа в течение 2 дней sendmail будет пытаться доставить извещение о сбое при доставке отправителю, но далее моего mx-а не продвинется.

    В данном случае полезным будет ключ преобразований bestmx :
    " ...
    bestmx       Возвращает лучшую запись MX для заданного в качестве ключа имени хоста. Всегда предпочитается текущая машина- то есть, текущая машина является одним из хостов, перечисленных в качестве записи MX с самым низким значением предпочтения, следовательно, имеется гарантия его возврата. Это может использоваться для определения, является ли эта машина целью записи MX, и почта может быть принята на этом основании. Если задан флаг -z, то возвращаются все имена MX, разделенные заданным разделителем.
    ..."
    Сначала я выделяю почтовый домен, с которого пришло письмо, затем проверяю с/п bestmx список всех mx-ов для данного домена. И если в этом списке присутствует outblaze.com, то блокируем письмо.
    LOCAL_CONFIG
    Kbbestmx -z:
    LOCAL_RULESETS
    SLocal_check_mail
    # Берем доменную часть адреса отправителя и проверяем, кто является mx-ом для данного домена (вытаскиваем все mx-ы):
    R$*<$+@$+>          $: $(bbestmx $3 $)
    R$+           $: $(syslog syslog:MX1: $1 $) $1
    R$*outblaze.com$*          $#error $: "554 Sorry, далее текст по вашему уразумению."

    А теперь проверяем лог:
    Nov 15 16:31:42 apache sendmail[12830]: lAFBVa3N012830: syslog:MX1:leonlai-net.mr.outblaze.com.:leonlai-net-bk.mr.outblaze.com.
    Nov 15 16:31:42 apache sendmail[12830]: lAFBVa3N012830: ruleset=check_mail, arg1=<iberia@leonlai.net>, relay=119.Red-81-37-99.dynamicIP.rima-tde.net [81.37.99.119], reject=554 5.0.0 <iberia@leonlai.net>... Sorry, ...
    Nov 15 16:31:43 apache sendmail[12830]: lAFBVa3N012830: from=<iberia@leonlai.net >, size=0, class=0, nrcpts=0, proto=SMTP, daemon=MTA, relay=119.Red-81-37-99.dynamicIP.rima-tde.net [81.37.99.119]

    Погодите-погодите! Вы знаете, сколько лишних запросов вы отправите своему днс-у? "Оно вам надо"?
    Вот файл, где перечислены почтовые домены, ссылающиеся на outblaze.
    Копируем перечисленные в нем домены в access, ключ (REJECT, DISCARD, ERROR) - на ваше усмотрение.
    makemap hash access <access
    Ну а я, как всегда, не ищу легких путей, и потом интересно посчитать статистику именно по этому показателю, поэтому делаю так.
    Сохраняю файл outblaze в /etc/mail.
    Теперь переписываю конфиг следующим образом:

    LOCAL_CONFIG
    F{Outblaze}/etc/mail/outblaze
    F{IP127}/etc/mail/127
    LOCAL_RULESETS
    SLocal_check_mail
    R<$+@$={Outblaze}>               $#error $: "554 Sorry, далее текст по смыслу ..."
    Ежедневный egrep -c "Sorry, мой текст" maillog дает 2-4 тысячи срабатываний.

    7. Как заблокировать письма, поступающие с почтовых доменов, mx для которых ссылается на 127.0.0.1.

    Nota Bene! Начиная с версии 8.14.0 в sendmail есть FEATURE(`badmx'), которая позволяет отвергать почту, если домен ссылается на "плохую" mx-запись. См. README.

    Ситуация, схожая с предыдущей.
    Спам-письмо проскакивает один mx, а при передаче письма основному почтовику получает от него отлуп.
    Его, естественно, нужно вернуть отправителю письма.
    Мой почтовик определяет mx почтового домена отправителя.
    И вот засада: им оказывается 127.0.0.1.
    В итоге в логе на моем mx-е получаем стандартное:
    "Local configuration error. Mail loops back to me."
    Можно, конечно, подключится к базе RFC-ignorant, и добавить в конфиг что-то вроде
    FEATURE(rhsbl,`bogusmx.rfc-ignorant.org',`"550 Mail from domain " $`'&{RHS} " refused. MX of source domain points to 127.0.0.1 - see http://www.rfc-ignorant.org/"')
    но, если можно сделать провеку у себя на сервере, почему бы это не сделать?

    В этом решении помимо bestmx мы используем новое спец. преобразование dns:
    op.me:"...
    dns - This map requires the option -R to specify the DNS resource record type to lookup. The following types are supported: A, AAAA, AFSDB, CNAME, MX, NS, PTR, SRV, and TXT. A map lookup will return only one record. Hence for some types, e.g., MX records, the return value might be a random element of the list due to randomizing in the DNS resolver.
    ..."
    Снова выделяем почтовый домен, с которого пришло письмо, затем проверяем с/п bestmx список всех mx-ов для данного домена. И делаем запрос к dns на предмет A-записи для данного mx-имени.

    LOCAL_CONFIG
    Kbbestmx -z:
    Kddns2 dns -R A

    LOCAL_RULESETS
    SLocal_check_mail
    R$*                $: $(storage {Mail_from} $@ $1 $) $1

    #Do not check if it is local ip-address
    R$*                $: < $&{client_addr} >
    R< 127.0.0.1 >                $@ OK

    R$*                $: $&{Mail_from}
    R$*                 $: $(storage {Mail_from} $) $1
    # Берем доменную часть адреса отправителя и вытаскиваем за ушко на белый свет все (ключ -z) mx-ы этого домена
    R$*<$+@$+>                $: $(bbestmx $3 $)
    R$+                $: $(syslog syslog:MX1: $1 $) $1
    # Присваиваем списку mx-ов метку <MX>
    R$+                 $: <MX>$1
    # Если полный список mx-ов состоит из 4 адресов, вытаскиваем из ДНС ip-адрес каждого mx-а.
    # Попутно избавляемся от метки <MX> и присавиваем метку <4> только для того,
    # чтобы вывести четырехадресные mx-ы в лог:
    R<MX>$+:$+:$+:$+                $: <4> $(ddns2 $1 $) : $(ddns2 $2 $) : $(ddns2 $3 $) : $(ddns2 $4 $)
    R<4>$+:$+:$+:$+                 $: $(syslog syslog:DNS10: $1:$2:$3:$4 $) $1:$2:$3:$4
    # Если полный список mx-ов состоит из 3 адресов, вытаскиваем из ДНС ip-адрес каждого mx-а
    R<MX>$+:$+:$+                $: <3> $(ddns2 $1 $) : $(ddns2 $2 $) : $(ddns2 $3 $)
    R<3>$+:$+:$+                 $: $(syslog syslog:DNS11: $1:$2:$3 $) $1:$2:$3
    # Если полный список mx-ов состоит из 2 адресов, вытаскиваем из ДНС ip-адрес каждого mx-а
    R<MX>$+:$+                $:<2> $(ddns2 $1 $) : $(ddns2 $2 $)
    R<2>$+:$+                 $: $(syslog syslog:DNS12: $1:$2 $) $1:$2
    # Если полный список mx-ов состоит из 1 адреса, вытаскиваем из ДНС его ip-адрес
    R<MX>$+                $: <1>$(ddns2 $1 $)
    R<1>$+                 $: $(syslog syslog:DNS13: $1 $) $1
    # Если среди ip-адресов есть 127.0.0.1 - отлуп
    R$*127.0.0.$+                 $#error $: "554 Sorry, you are RFC-ignorant."

    А что у нас в логе?
    Nov 15 12:40:02 apache sendmail[26421]: lAF7dwdE026421: syslog:MX1:nomail.bluegravity.com.
    Nov 15 12:40:03 apache sendmail[26421]: lAF7dwdE026421: syslog:DNS13:127.0.0.1
    Nov 15 12:40:03 apache sendmail[26421]: lAF7dwdE026421: ruleset=check_mail, arg1=<Isaac703@calcitriol.com>, relay=[81.185.199.73], reject=554 5.0.0 ... Sorry, you are RFC-ignorant.
    Nov 15 12:40:03 apache sendmail[26421]: lAF7dwdE026421: from=<Isaac703@calcitriol.com>, size=1766, class=0, nrcpts=0, proto=ESMTP, daemon=MTA, relay=[81.185.199.73]

    Ну а теперь я повторюсь: не торопитесь! Зачем нагружать почтовик таким количеством лишних запросов?
    Вот файл, где перечислены почтовые домены, ссылающиеся на 127.0.0.1.
    Копируем перечисленные в нем домены в access, ключ (REJECT, DISCARD, ERROR) - на ваше усмотрение.
    makemap hash access <access

    Или опять-таки для оригиналов:
    Сохраняем файл в /etc/mail.
    Теперь переписываем конфиг следующим образом:

    LOCAL_CONFIG
    F{IP127}/etc/mail/127
    LOCAL_RULESETS
    SLocal_check_mail
    R<$+@$={IP127}>               $#error $: "554 Sorry, you are RFC-ignorant."
    Ежедневно около 1000 срабатываний.

    8. Как заблокировать письма, в заголовке которых подзаголовок X-Mailer или отсутствует, или он пустой.

    Мое отношение к этой проверке неоднозначное, тем не менее привожу ее здесь.
    LOCAL_CONFIG
    Kstorage macro
    #Определяем индикатор наличия поля X-Mailer (по умолчанию заголовок отсутствует, то есть значение макроса равно 0)
    D{XM_exist}0

    LOCAL_RULESETS
    #отправляем подзаголовок X-Mailer: на проверку в Check_XM
    #если этого подзаголовка нет вообще, или он пустой, то и проверки не будет,
    #если он есть, то
    #сработает правило, изменяющее значения макроса {XM_exist} на 1
    HX-Mailer:               $>Check_XM
    SCheck_XM
    R$*               $: $(storage {XM_exist} $@ 1 $) $1

    #заключительная проверка: если в нашем макросе 0 - блокируем
    Scheck_eoh
    #вызываем значение нашего макроса на разборку
    R$*               $: <$&{XM_exist}>
    #очищаем макрос для след. сессии, но при этом оставляем его значение для дальнейшей разборки
    R$*                $: $(storage {XM_exist} $) $1
    0 - отправляем в аут
    R<0>               $#error $:554 Sorry, далее все, что вы хотите сказать по этому поводу

    9. Как заблокировать письмо, если среди получателей указан определенный пользователь (ловля на живца или технология "Honey Pot").
    1. Допустим, некий юзер уже давно уволился, а спам для него продолжает поступать.
    Ну и что, скажете вы. Ведь Sendmail должен отвергнуть это письмо на этапе RCPT TO:
    Да, спорить не буду, sendmail знает свое дело.
    А что, если выцепить из этой ситуации максимум пользы для себЯ?
    Ведь поступающий на адрес уволившегося сотрудника спам часто приходит в составе рассылки.
    Значит, обнаружив среди получателей "помеченного" юзера, мы можем отвергнуть всю рассылку.

    Тут следует принять во внимание следующее.
    1. Этот сотрудник мог подписаться на массу законных рассылок, которые получают и другие ваши сотрудники.
    Значит, во-первых, желательно выждать какое-то время, чтобы он выпал из этих рассылок, или какое-то время понаблюдать за поступающей в этот ящик почтой и отписаться от рассылок;
    а во-вторых, неплохо добавить предварительную проверку на принадлежность отправителя "белому списку",
    в котором нужно перечислить адреса, с которых рассылки должны приходить без ограничений.
    2. У меня есть несколько e-mail'ов, не актуальных уже лет 5-7, на которые до сих пор приходит спам. И чаще всего этот спам идет рассылкой.
    Но здесь все индивидуально.
    Вышесказанное совсем не означает, что это технология будет эффективна на вашей почтовой системе.
    Все-таки нашему почтовому домену 10 лет, а 10 лет назад никто и предположить не мог, что проблема спама станет такой острой, и адреса моих пользователей не просто засвеченные, а жутко засвеченные!
    3. Можно создать специально "honey pot"-юзера, а затем наоставлять его адрес на форумах.
    В принципе, можно этого пользователя и не создавать: если придет почта для него одного, то случится отлуп "User unknown", а если он окажется в составе рассылки, то для всех остальных участников рассылки почта будет отвергнута уже с другим, определенным вами, сообщением.
    Минус: не обязательно спам на такой ящик будет приходить рассылкой. Поэтому предпочтительно использовать недействующие адреса уволившихся сотрудников.

    В данном случае используется 2 "белых списка" (для отправителей(/etc/mail/oksender) и получателей (CheckRcpt1))
    и один "черный список" (CheckRcpt2).
    LOCAL_CONFIG
    #По умолчанию адрес локального получателя не является ловушкой
    D{Honey_Check}0
    #По умолчанию адрес отправителя не принадлежит белому списку
    D{WL_mail_from}0
    #По умолчанию адрес получателя не принадлежит белому списку
    D{WL_mail_to}0

    #Внешних отправителей, чья почта не будет фильтроваться, можно задавать через файл
    KNoCheckSender hash /etc/mail/oksender

    #Список охраняемых от ложных срабатываний адресов получателей (даже если письмо пришло в виде рассылки, а среди получателей указан охраняемый получатель, то такая почта будет пропущена без проверки)
    KCheckRcpt1 regex -a@LIST ^user1|user2|user3$

    #Список адресов-ловушек
    KCheckRcpt2 regex -a@LIST ^honey_pot1|honey_pot2|honey_pot3|honey_pot4$

    LOCAL_RULESETS
    SLocal_check_mail
    Сохраняем адрес отправителя в макросе {Mail_from}
    R$*                $: $(storage {Mail_from} $@ $1 $) $1
    #Включен ли отправитель в белый список
    R$* < $+ @ $+ >                $: $(NoCheckSender $2@$3 $:$1<$2@$3> $)
    # Да - изменяем значение макроса {WL_mail_from} на 1 ...
    R@MATCH                $: $(storage {WL_mail_from} $@ 1 $) @MATCH
    #... и завершаем выполнение данного набора правил
    R@MATCH                 $@ OK

    #Аналогичная проверка: включен ли домен отправителя в белый список
    R$* < $+ @ $+ >                 $: $(NoCheckSender $3 $:$1<$2@$3> $)
    R@MATCH                 $: $(storage {WL_mail_from} $@ 1 $) @MATCH
    R@MATCH                $@ OK

    SLocal_check_rcpt
    #Сохраняем адрес получателя в макросе {Mail_to}
    R$*                $: $(storage {Mail_to} $@ $1 $)
    #Подаем на вход значение макроса {WL_mail_from}.
    R$*                 $: <$&{WL_mail_from}>
    #Если отправитель уже в белом списке (равен 1), то все остальное не имеет смысла проверять. Выходим.
    # Сначала очищаем макрос Mail_to для след. сообщения
    R<1>                 $: $(storage {Mail_to} $) <1>
    #Выходим.
    R<1>                $@ OK

    #Подаем на вход значение макроса Mail_to - адрес получателя
    R$*                 $: $&{Mail_to}
    # Сначала очищаем макрос Mail_to для след. сообщения
    R$*                $: $(storage {Mail_to} $) $1

    #Канонизируем адрес получателя
    R$*                 $: $>3 $1

    #Почту для локальных пользователей (домен принадлежит классу w) отправляем на дальнейшую проверку в CheckLocalUser, при этом освобождаемя от доменной части - она нам пока не понадобится
    R$+<@$=w.>                $: $>CheckLocalUser $1
    #Пропускаем почту с внешними доменными именами
    R$+<@$+>                 $@ OK
    #Остались адреса локальных получателей, у которых отсутствует доменная часть (это возможно сделать в sendmail -bs, telnet & TheBat)
    #Отправляем их на дальнейшую проверку в CheckLocalUser
    R$+                $: $>CheckLocalUser $1

    SCheckLocalUser
    Принадлежит ли получатель "белому списку"?
    R$+                 $: $(CheckRcpt1 $1 $:$1 $)
    #Да - присваиваем макросу {WL_mail_to} значение 1
    R@LIST1                 $: $(storage {WL_mail_to} $@ 1 $) @LIST
    #И заканчиваем
    R@LIST1                 $@ OK

    #Еще одно действие: если среди получателей есть хотя бы один пользователь-ловушка,
    #то это письмо помечаем, присвоив макросу {Honey_Check} значение 1 (блокировку делаем в наборе check_eoh для того, чтобы она сработала для всего письма)
    R$+                 $: $(CheckRcpt2 $1 $:$1 $)
    R@LIST                 $: $(storage {Honey_Check} $@ 1} $)

    Scheck_eoh
    #Return to WL_mail_from
    #Принадлежит ли отправитель "белому" списку
    R$*                 $: <$&{WL_mail_from}>
    # Clear the macros {WL_mail_from} for the next message
    R$*                 $: $(storage ${WL_mail_from} $) $1
    #Да - пропускаем письмо
    R<1>                $@ OK

    #Принадлежит ли получатель "белому" списку
    R$*                 $: <$&{WL_mail_to}>
    # Clear the macros {WL_mail_to} for the next message
    R$*                 $: $(storage ${WL_mail_to} $) $1
    #Да - пропускаем письмо
    R<1>                $@ OK

    #Помечено ли письмо "черной меткой"
    R$*                 $: <$&{Honey_Check}>
    # Clear the macros {Honey_Check} for the next message
    R$*                 $: $(storage ${Honey_Check} $) $1
    #Да - блокируем письмо
    R<1>                 $#error $: "554 Sorry, далее все, что вы хотите сказать по данному поводу."

    /etc/mail/oksender
    gluck@mail.subscribe.ru [TAB] @MATCH
    sender@ambar.mail.ru [TAB] @MATCH
    kaspersky.com [TAB] @MATCH

    makemap hash oksender <oksender


    30.09.2011.
    "А он мне нравится, нравится, нравится!!!"-пела когда-то Анна Герман.
    А мне нравится эта спам-ловушка. Нравится, нравится, нравится!!!
    Здесь 2 honey-pot-адреса: user000@anrb.ru & user4@anrb.ru. То есть в качестве ловушки может выступать как реальный,так и несуществующий адрес. В данном примере видно, что на 2 адреса-ловушки пришлось 10 реальных адресов, значит, 10 спам-писем не получено!

    Sep 30 16:17:23 mail sendmail[11206]: p8UAHKX0011206: <user000@anrb.ru>... User unknown
    Sep 30 16:17:23 mail sendmail[11206]: p8UAHKX0011206: ruleset=CheckFrom, arg1= =?koi8-r?B?7MXbwSDuwdXNz9c=?= <crumpetk@narod.ru>, relay=h178-129-63-244.dyn.bashtel.ru [178.129.63.244], reject=550 5.7.1 There is some error explaining text.
    Sep 30 16:17:23 mail sendmail[11206]: p8UAHKX0011206: from=<sender@domain.com>, size=3698, class=0, nrcpts=11, msgid=<20110930141615.anrb.ru@vrspam.narod.ru>, bodytype=8BITMIME, proto=ESMTP, daemon=MTA, relay=h178-129-63-244.dyn.bashtel.ru [178.129.63.244]
    Sep 30 16:17:23 mail sendmail[11206]: p8UAHKX0011206: to=<user1@anrb.ru>, delay=00:00:00, pri=123698, stat=There is some error explaining text.
    [skip]
    Sep 30 16:17:23 mail sendmail[11206]: p8UAHKX0011206: to=<user11@anrb.ru>, delay=00:00:00, pri=123698, stat=There is some error explaining text.
    Кстати, у себя на сервере я использую облегченный вариант проверки на "honey-pot".
    А вот новая статейка, описывающая, как легко получить полную выдержку из лога по какому-либо ключевому слову или выражению.

    10. Назначаем вес каждому спам-шаблону, по суммарному весу блокируем письмо.

    08.01.2008. Артель "Напрасный труд" продолжает коптить небо ...

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

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

    Мой sendmail-раздел начинался с regex-спам-фильтра.
    Со временем почти все приведенные в нем проверки стали неэффективными.
    Проверять тему письма, мэйлер, e-mail отправителя стало почти бесполезно.
    Сейчас я проверяю только:
    - EHLO/HELO на наличие моего домена и ip-адресов
    - домен релея отправителя и все подзаголовки Received на наличие некоторых доменов типа wanadoo;
    - количество неопознанных получателей;
    - adsl|ppp|dial|modem|etc в доменном адресе отправителя и одновременно количество получателей такого письма;
    - количество Received (с учетом многочисленных исключений)

    Вот по этим параметрам (кроме первого) я и проверю письмо, но назначу каждой проверке с положительным исходом определенный вес, а в check_eoh подведу итог.
    Написано, что называется, "на коленке". Имеенно в таком виде не проверялось. Но в моем конфиге имеется несколько аналогичных проверок.

    LOCAL_CONFIG

    # Максимально допустимое количество несуществующих получателей письма
    D{Allowed_Unknown_Rcpts}3

    #Максимально допустимое количество получателей письма, если оно отправлено с адреса, заматченного спец. преобразованием DialDomain
    D{Rcpts}2

    # Прибавка к весу письма, если в доменном имени релея встречается один из шаблонов, описанных в спец. преобразовании BadDomain
    D{RelayBadDom}2

    # Прибавка к весу письма, если в Received встречается один из шаблонов, описанных в спец. преобразовании BadDomain
    D{ReceivedBadDom}2

    # Прибавка к весу письма, если Received - один-единственный
    D{OneRec}3

    # Прибавка к весу письма, если в доменном имени встречается один из шаблонов, описанных в спец. преобразовании DialDomain, при условии превышения максимально допустимого количества получателей письма (в моей почтовой биографии случилось 2-3 ложных срабатывания по этому признаку, но никогда это не было рассылкой)
    D{DialDom}2

    # Прибавка к весу письма, если количество несуществующих получателей письма превышает значение макроса Allowed_Unknown_Rcpts
    D{NBadRcp}1

    # Начальный вес письма
    D{Weight}0

    # Спам-порог веса письма
    D{Spam-Weight}5

    Ksyslog syslog
    Kstorage macro
    KCH1 -regex -a@MATCH outblaze|check1check|mindspring|bigfoot|funnymail|bellsouth.net|tiscali.(it|nl|fr)|wanadoo.(it|nl|fr)|nic.*olastse.(com|net)|videotron.ca|blueyonder|mailcity[.]|mexico|comcast.net|earthlink.com|libertysurf.net|mozartmail.com|telepac.pt|edomex.com|quintanaroo.com|telia.com|hideakifan.com|icq.com|delphi.com|optonline.net|interbusiness.it
    KCH2 regex -a@YES sunrise.ch|videotron.ca|netvision.net|user.msu.edu|guadalupano.com|chello.(nl|pl|at)|midco.net|gmx.de|mexican..com|adelphia.net|telepac.pt|louiskoo.com|rickymail.com|terra.com.br|home.nl|slamdunkfan.com|barak.net.il|client.*attbi.com|concentric.com|veloxzone.com.br|wartaponsel.com|bezeqint.net|tlcfan.com|roxette.org
    KCH3 regex -a@YES swip[.]net|surfer.at|ezagenda.com|kyokofukada.net|nic[h]*olastse.(com|net)|hispeed.ch|e-post01\.e-se\.ru|speedy.net|E-RE.LAMA|(tele|sky)net.*\.be|home.nl|zemskov.ru|interpo(c|s)hta.ru|(garant|russian)post.ru|badtzmail.com|zapopan.com|zipolit..com|netcabo.pt|skynet.be|YourBizHelp\.biz|hsuchi.net|hinet.net|malaysia.net|dbzmail.com|infostroy.ru
    KCH4 regex -a@YES fairgamemail.us|brainpod.com|garaga.info|puertorrico.com|garzagarcia.com|takuyakimura.com|suslik.biz|phreaker.net|hostingseries.+net|bellnexxia.net|punkass.com|smapxsmap.net|norika-fujiwara.com|avistacorp.com|mailexcite.com|kubrik.biz|rusaero.ru|spamcactus.com|fiestabrava.com|standarthost.ru|nekto.info|chokofan.com|speed.planet.nl|asianet.co.th
    KCH5 regex -a@YES centurytel.net|verisign.com|pacbell.net|versanet.de|acadia.net|accesspro.net|netzero\.com|priest.com|veretekk.com|inetekk.com|barbara.+com|barak.net
    KBadDomain sequence CH1 CH2 CH3 CH4 CH5

    #Заматчим релеи такого вида
    #relay=triband-del-59.178.98.134.bol.net.in [59.178.98.134]
    #relay=161.231.88.202.asianet.co.in [202.88.231.161]
    #relay=LAubervilliers-153-52-38-64.w217-128.abo.wanadoo.fr
    #relay=host-89-230-67-82.rzeszow.mm.pl [89.230.67.82]
    KDD1 regex -a@MATCH [0-9]+[._-]+[0-9]+[._-]+[0-9]+.+\[.+\]
    KDD2 regex -a@MATCH ppp|customer|dhcp|dial|cable|modem|adsl|dynamic
    KDialDomain sequence DD1 DD2

    LOCAL_RULESETS

    HReceived:                $>+CheckReceived
    SCheckReceived
    # Подаем на вход два дополнительных параметра: ip-адрес клиента и признак имевшей (или не имевшей)
    # место smtp-авторизации:
    R$*                 $: $1 $| $: < $&{client_addr} > $| $: < $&{auth_authen} >
    #Разрешаем почту из нашей локальной сети:
    R$+ $| < $=R $* > $| <$*>                 $@ OK
    # Разрешаем почту, прошедшую smtp-авторизацию:
    R$+ $| < $+ > $| <$+>                 $@ OK
    # Избавляемся от добавленных нами праметров, остается только содержимое подзаголовков Received.
    R$+ $| $+                 $: $1

    # Вводим новый макрос {ReceivedCheck}. Если хотя бы один заголовок Received присутствует
    # в заголовке письма, то исполнится набор правил CheckReceived, и в этот макрос запишется OK.
    R$*                $: $(storage {ReceivedCheck} $@ OK $) $1
    # Проверяем Received на наличие некоторых доменов, в положит. случае на выходе мы получим метку @MATCH.
    R$+                $: $(BadDomain $1 $)
    # В случае срабатывания складываем текущий вес письма и значение, определенное нами для этого случая ({ReceivedBadDom}).
    R@MATCH                $: < @MATCH >$(arith + $@ $&{Weight} $@ $&{ReceivedBadDom} $)
    # Присваиваем макросу Weight полученное значение.
    R< @MATCH >$+                $: $(storage {Weight} $@ $1 $)

    Scheck_eoh
    #Разрешаем также почту из нашей локальной сети:
    R$*                $: < $&{client_addr} >
    R< $=R $* >                $@ OK
    # Разрешаем почту, прошедшую smtp-авторизацию:
    R$*                 $: < $&{auth_authen} >
    R< $+ >                 $@ OK

    # Проверяем внутренний макрос ${client_name} - доменное имя клиента.
    # Вообще-то это значение по умолчанию подается в check_relay, и мы могли бы сделать эту проверку гораздо раньше,
    # но (кажется, но, может, нагло вру) на этапе check_relay еще не известен макрос $&{auth_authen}.
    R$*                $: $(BadDomain $&{client_name} $)
    # В случае срабатывания складываем текущий вес письма и значение макроса, определенное нами для этого случая ({RelayBadDom}).
    R@MATCH                $: < @MATCH >$(arith + $@ $&{Weight} $@ $&{RelayBadDom} $)
    # Присваиваем макросу Weight полученное значение.
    R< @MATCH >$+                $: $(storage {Weight} $@ $1 $)

    # Еще раз проверяем внутренний макрос ${client_name}, теперь уже на принадлежность dial-up,adsl,etc-адресам.
    R$*                $: $(DialDomain $&{client_name} $)
    # В случае срабатывания проверяем еще и количество существующих получателей такого письма.
    R@MATCH                $: $(arith l $@ $&{nrcpts} $@ $&{Rcpts} $)
    # Если оно больше числа, определенного в макросе {Rcpts}, то складываем текущий вес письма и значение макроса {DialdDom}
    RFALSE                $: < FALSE >$(arith + $@ $&{Weight} $@ $&{DialdDom} $)
    # Присваиваем макросу Weight полученное значение.
    R< FALSE >$+                $: $(storage {Weight} $@ $1 $)

    # Теперь разберемся с письмами с одним Received.
    # Подаем на вход макрос $&{ReceivedCheck}.
    R$*                 $: < $&{ReceivedCheck} >
    # Очищаем эту переменную для следующего сообщения:
    R$*                 $: $(storage {ReceivedCheck} $) $1
    # И еще добавим метку и макрос ${client_name}
    R$*                 $: < ChRec >< $&{ReceivedCheck} > <$&{client_name}>
    #Списки исключений для почтовиков, не добавляющих свой Received: в заголовок письма (список составлен по ложным срабатываниям только моего почтовика )
    # Allow missing Received from some non-compliant-RFC mail servers
    #Возможно, ambar.mail.ru формирует тело сообщения в виде текстового файла нужного формата и сразу помещает его в очередь, поэтому рассылки приходят с единственным заголовком Received
    # Избавляем ambar от метки и вообще от всего, пусть идет себе дальше
    R< ChRec >$+< ambar.mail.ru >                $: @OK
    # Ну а эти господа используют MicrExchange, у них тоже Received не допросишься, вам эти домены не понадобятся (это местные уфимские почтовики), вряд ли вы будете им писать когда-либо, ну а мне приходится для них также делать исключение, так и таскаю их за собой в каждом check_eoh :
    R< ChRec >$+ < etc.bash.ru >                $: @OK
    R< ChRec >$+ < mail.airrb.ru >                $: @OK
    R< ChRec >$+ < mail.ufantc.ru >                $: @OK
    # Всех, кого нужно исключить, мы исключили, остальным метку сохраняем, но убираем ${client_name} - он нам больше не понадобится
    R< ChRec >$+< $+ >                $: < ChRec > $1
    # Если Received: - единственный, то макрос $&{ReceivedCheck} будет пустым, и мы складываем текущий вес письма и значение макроса, определенное нами для этого случая ({OneRec}).
    R< ChRec >< >                 $: < ChRec >$(arith + $@ $&{Weight} $@ $&{OneRec} $)
    # Присваиваем макросу Weight полученное значение.
    R< ChRec >$+                $: $(storage {Weight} $@ $1 $)

    # Последняя проверка.
    # Подаем на вход количество неопознанных получателей.
    R$*                $: < $&{nbadrcpts} >
    # Сравниваем с допустимым значением.
    R$*                 $: $(arith l $@ $&{nbadrcpts} $@ $&{Allowed_Unknown_Rcpts} $)
    # В случае превышения складываем текущий вес письма и значение макроса, определенное нами для этого случая ({NBadRcp}).
    RFALSE                $: < FALSE >$(arith + $@ $&{Weight} $@ $&{NBadRcp} $)
    # Присваиваем макросу Weight полученное значение.
    R< FALSE >$+                $: $(storage {Weight} $@ $1 $)

    # Сравниваем полученный вес письма с допустимым.
    R$*                 $: $(arith l $@ $&{Weight} $@ $&{Spam-Weight} $)
    R< FALSE >                $#error $: "554 Sorry, далее все, что вы хотите сказать по данному поводу."

    11. Проверяем MX.
    Взято отсюда - http://www.jaenicke.org/sendmail/rules.txt
    LOCAL_CONFIG
    Kgetmxrrs bestmx -z:
    Kbestmx bestmx
    Kgethostbyname dns -RA
    KBadMX regex -n -aOK ^(127\.[0-9]+\.[0-9]+\.[0-9]+|10\.[0-9]+\.[0-9]+\.[0-9]+|172\.20\.[0-9]+\.[0-9]+|192\.168\.[0-9]+\.[0-9]+)$
    Kstore macro
    KmatchIPv4Address regex -aMXTOIPV4 ^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\.|\.)$

    LOCAL_RULESETS

    SLocal_check_mail
    R $*                $: $>canonify $1
    R $* < @ $+. > $*                $1 < @ $2 > $3 strip trailing dot
    R $* < @ $+ > $*                $: $2 return host part

    R < @ >                $@ OK no further checking for empty sender

    R $*                $: $(store {FQDN} $@ $1 $) $1 save workspace for further processing
    R $*                $: $>CheckMX $1
    R $*                $: $&{FQDN}
    R $*                $: $>CheckMXtoIPAdress $1

    SCheckMX
    R $+                $: $(getmxrrs $1 $: $1 $) : get list of MX RRs
    R $+ : $*                $: $>resolve $1 : $2 resolve all entries
    R $* :                $: $1 strip trailing :
    R $* OK : OK $*                $1 OK $2 summarize known-good
    R $* OK $*                $@ OK at least one ok, proceed
    R $*                $@ $# error $@ 5.1.8 $: "550 all MX RRs resolve to RFC 1918 IP addresses"

    SCheckMXtoIPAdress
    R $+                $: $(bestmx $1 $: $1 $) get best MX RR
    R $*                $: $(matchIPv4Address $1 $) is it an IPv4 address?
    R $* MXTOIPV4                $@ $# error $@ 5.1.8 $: "550 MX RR pointing to IP addresses not allowed (RFC 2181, section 10.3)"
    R $*                $@ OK MX RR accepted

    Sresolve
    R : $*                $: $1 strip off leading :
    R $+ : $*                $: $(gethostbyname $1 $: $1 $) : $2 resolve first entry
    R $+ : $*                $: $(BadMX $1 $) : $>resolve $2 recur for remaining list

    12.1. Как сравнить две величины. Общее решение.

    28.01.2008.
    Эта задача вставала передо мной неоднократно, и я неоднократно "шерстила" по этому поводу sendmail-конфу, но вот только недавно обнаружила патч Joe Mamon за 2005г.
    Как пишет автор, этот патч позволяет использовать новое спец. преобразование compare:

    This patch introduces a new map type, compare. This map type can be used to compare strings. Basic usage is like this:
    Kcompare compare
    And in a ruleset:
    R$* $| $*                $: $(compare $1 $@ $2 $: $)
    RMATCH                $#OK
    R$*                $#error

    The map understands these arguments:
    -a : string to return on successfull match (default MATCH)
    -f : case sensitive search
    -n : successfull return is if strings do NOT match
    -T : string to return on unsuccessfull match (default blank)
    If the map is called with only one string the following arguments are relevant in this order
    -z : delimiting charachter to seperate the key value into 2 strings
    -k : string to use to seperate the key value into 2 strings
    -v : string to use to seperate the key value into 2 strings

    Currently, one can do something similar by storing the string into a macro with a macro map and then by trying to match the LHS with it.
    However that is a bit awkward and apparantly, more susceptible to mangling.

    27.12.2008. Обнаружила в конфиге sendmail'a вот такие правила:
    Strust_auth
    R$*                           $: $&{auth_type} $| $1
    # required by RFC 2554 section 4.
    R$@ $| $*                  $#error $@ 5.7.1 $: "550 not authenticated"
    R$* $| $&{auth_authen}                  $@ identical
    R$* $| <$&{auth_authen}>         $@ identical
    Здесь то, что подается на вход, сравнивается с $&{auth_authen}.
    И на основании этого примера мы теперь можем решить следующую задачку, про которую часто спрашивают, а именно:

    12.2 Частный случай. Сравниваем левую часть адреса отправителя и имя, которое он использовал для авторизации.

    29.10.2010.
    LOCAL_CONFIG
    Ksyslog syslog
    LOCAL_RULESETS
    SLocal_check_mail

    R<> $@ OK
    R$+                                    $:<all> $1
    R<all><$+>                                    $:<$1>
    R<all>$+                                    $:<$1>
    R$*                          $:< $&{auth_authen}> $1
    R<>$*                          $@ OK
    R<$+><$+@mydomain.ru>                         $:<$2>
    R<$+><$+@$+>                          $#error $@ 5.7.1. $: "550 User " $&f " not allowed to act as " $&{auth_authen}": alien sender email"
    R<$+><$+>                          $#error $@ 5.5.4 "Domain name required for sender address " $&f
    R<$&{auth_authen}>                         $@ identical
    R$*                         $#error $@ 5.7.1. $: "550 User " $&f " not allowed to act as " $&{auth_authen}

    Обсуждение здесь.

    13. Блокируем письмо, если адрес отправителя начинается с символов ("_" или "-") и если при этом выполняется одно из трех условий (кол-во получателей >=2 или доменное имя релея из diaup-сетки или среди получателей есть определенный пользователь).

    26.02.2008.
    Вы, верно, заметили такое спамерское новшество - адреса отправителей начинаются с дефиса или нижнего подчеркивания. Само по себе это, конечно, не криминал. Но мириться с 5-10 тысячами спам-сообщений в сутки с такими адресами отправителей тоже не хочется:
    <-ramen@aghinc.com>,
    <_caeiro@about-secrets.com>,
    <_karin@aeneascapital.com>,
    <_gh@ac-hotels.com>,
    <_koksmuts@adaevidencelibrary.com>,
    <-ganz@adhes.com>,
    <_nikolov_78@abvent.com>,
    <-chasity@adhesaplate.com>,
    <-rose@accomline.com>

    Я добавила две проверки. Одну, самую простую, я делаю на транзитных mx-ах. 4-5тысяч срабатываний в день. ПРоверяю в лоб наличие _ и - в первом символе адреса отправителя.
    LOCAL_CONFIG
    KSPA3 regex -a@MATCH ^[_-]
    LOCAL_RULESETS
    SLocal_check_mail
    R$*                                    $: $>3 $1
    R$+<@$+>                            $: $(SPA3 $1 $: $)
    R@MATCH                            $#error $: 554 Sorry, Your e-mail address looks like SPAM. If not, please contact the postmaster@domain.ru via another e-mail address.

    Вторая проверка реализована на основном mx-е, и она усложнена доп. проверками, потому что я боюсь ложных срабатываний. Около 1000 срабатываний в день.
    Блокирую такие адреса отправителей только в трех случаях:
    -если письмо предназначено пользователю, указанному в спец. преобразовании CheckRcpt2
    -если получательписьма не единичный (встроенный макрос nrcpts>=2)
    -если IP релея отправителя содержит цифры, расположенные в определенном порядке, или слова, указывающие на dialup-происхождение письма.

    LOCAL_CONFIG
    KSPA3 regex -a@MATCH ^[_-]
    #Список исключений для проверки SPAM78
    KNOSPAM78 regex -a@MATCH ispdial.com|trais.+tenet.odessa.ua|dialognauka
    #Заматчим релеи такого вида
    #relay=triband-del-59.178.98.134.bol.net.in [59.178.98.134]
    #relay=161.231.88.202.asianet.co.in [202.88.231.161]
    #relay=LAubervilliers-153-52-38-64.w217-128.abo.wanadoo.fr
    #relay=dial-89-230-67-82.rzeszow.mm.pl [89.230.67.82]
    KSPAM7 regex -a@MATCH [0-9]+[._-]+[0-9]+[._-]+[0-9]+.+\[.+\]
    KSPAM8 regex -a@MATCH ppp|customer|dhcp|dial|cable|modem|adsl|dynamic
    KSPAM78 sequence SPAM7 SPAM8
    #Список пользователей, почта для которых будет проверяться на спам
    KCheckRcpt2 regex -a@LIST2 ^user1|user2|user3$

    LOCAL_RULESETS
    SLocal_check_rcpt
    R$*                                    $: $>3 $1
    R$+<@$=w.>                            $: $(CheckRcpt2 $1 $)
    R@LIST2                           $: $(storage {Spam_Check} $@ 1 $)

    HFrom:                  $>CheckFrom
    SCheckFrom
    R$*                           $: $(storage {From} $@ $1 $)

    #Checking for SPA3 <_abcdef@some.ru> if nrcpts >= 2
    R$*                           $: $(arith l $@ $&{nrcpts} $@ 2 $)
    RFALSE                           $: $>EnvSenderCheck <$&f>

    #Checking for SPA3 <_abcdef@some.ru> for special users (Spam_Check=1)
    R$*                           $: <$&{Spam_Check}>

    # Clear the macros {Spam_Check} for the next message
    R<1>                           $: $(storage ${Spam_Check} $) <1>
    R<1>                           $: $>EnvSenderCheck <$&f>

    R$*                           $: $(NOSPAM78 $&_ $)
    R@MATCH                           $@ OK
    R$*                           $: $(SPAM78 $&_ $)
    R@MATCH                           $: $>EnvSenderCheck <$&f>

    SEnvSenderCheck
    # Check if matches to SPA3 (<_ABCDEF@SOME.RU>)
    #
    R<$+@$+>                  $: $(SPA3 $1 $)
    R@MATCH                           $: $(syslog syslog:EnvSenderCheck:1 @MATCH : <$&{f}> : $&_ : $&{nrcpts} $) @MATCH
    R@MATCH                   $#error $: 554 "Sorry, Your e-mail address looks like SPAM: If not, please contact the postmaster@domain.ru via another e-mail address" $&f
    01.03.2008. Уже не актуально.

    14. Еще одна проверочка Received: на наличие "from 207.228.33.220 (HELO mail.sppc.com)\n by anrb.ru with ESMTP (KPSGSLIVB BWMYF)\n id jN3Dbg-WGIsJO-10\n"

    28.02.2008.
    Вариация на старую тему. Около 1000 срабатываний в день.
    Заголовок такого письма имеет вид:
    Received: from [192.168.1.64] ([92.80.223.75])
    by mail.anrb.ru (8.14.2/8.14.2) with ESMTP id m1RA3X8T027249
    for < terrapin@anrb.ru >; Wed, 27 Feb 2008 15:03:52 +0500
    Received: from [66.7.148.135] (HELO mail.bohra.com)
    by anrb.ru with esmtp (3CF8Z6AQDW5 X0HO4)
    id T67FUJ-5KW3AK-TL
    for terrapin@anrb.ru; Wed, 27 Feb 2008 11:50:09 +0200
    С какой-такой радости посторонний релей сообщает в своем подзаголовке Received: ...by anrb.ru...
    Вот когда он начнет со мной smtp-диалог, вот тогда мой почтовик и запишет в своем Received, что письмо было принято by mail.anrb.ru (макрос $j). А до этих пор он ничего и ни от кого не принимал.

    Вот мы выловим это словосочетание плюс сделаем еще проверку на наличие нелюбимых мною доменов(ChHeader1) в Received и в HELO (макрос $&s).

    LOCAL_CONFIG
    ChHeader возьмите пожалуйста отсюда (т.е. возьмите BadDomain).
    KChHeader2 regex -a@YES by.yourdomain.ru.with.(esmtp|ESMTP)\(.*[A-Z].*\)
    LOCAL_RULESETS

    HReceived:                           $>+CheckReceived
    SCheckReceived

    R$*                           $: $(ChHeader $1 $)         
    R@YES                           $#error $: "554 Sorry, далее текст по смыслу."

    R$*                           $: $(ChHeader2 $1 $)         
    #R@YES                           $: $(syslog syslog:ChHeader2:@YES $) @YES
    R@YES                           $#error $: "554 Sorry, далее текст по смыслу. "

    R$*                           $: $(ChHeader $&s $)         
    R@YES                           $#error $: "554 Sorry, далее текст по смыслу. " $&s
    01.03.2008. Не актуально.

    15. Разрешаем писать на адреса некоторого домена только тем юзерам, у которых определенный IP.

    Вообще-то это повторение уже пройденного в первой части типовых задачек, но нужно было решение именно в таком виде, поэтому я его и написала еще раз.
    LOCAL_CONFIG
    LOCAL_RULESETS
    SLocal_check_rcpt
    # Является ли домен получателя ограниченным в правах (если да, то отправляем на проверку IP relay'a)
    R$*<$+@somedomain.ru>           $: $>CheckRelayIP
    ROK            $@ OK
    #Если письмо отправлялось напрямую через telnet, то адрес может быть без угловых скобок:
    R$+@somedomain.ru           $: $>CheckRelayIP

    SCheckRelayIP
    R$*           $: <$&{client_addr}>
    #Почта, отправленная с самого сервера
    R<127.0.0.1>           $@ OK
    #Единственные разрешенный IP, с которого можно принимать почту.
    R<1.2.3.4>           $@ OK
    R$*           $#error $: "554 Sorry, далее все, что вы хотите сказать по данному поводу."

    16. Как сказать sendmail'у, чтобы разалиасинг происходил до вызова milter'a.

    31.03.2008.
    Очень интересная задачка. Как водится, на ее решение я наткнулась случайно, когда искала информацию вот по этому вопросу. Боюсь, что решение Chris Adams может затеряться на бескрайних просторах sendmail-конфы, поэтому привожу его здесь. Тем более, что про него меня уже спрашивали.

    Итак, для чего это нужно. Представьте, что на вашем почтовом шлюзе стоит KAS+sendmail (но на месте антиспама Касперского может быть любой другой почтовый фильтр). Теперь представьте, что пришло письмо для adm@domain.ru. Почтовый шлюз проверит это письмо на спам, пометит тему соответствующей меткой (если письмо наберет определенный вес) и отправит на конечный сервер. Последний в свою очередь разалиасит адрес adm@domain.ru и разложит исходное письмо по нескольким ящикам (как заведено в приличных домах, письма для адм. адреса получают несколько человек). То есть разалиасинг происходит после того, как отработает milter, но перед конечной доставкой.
    Что в этом плохого?
    Поясню на примере моей почтовой системы. У нас всю почту для adm (помеченную спам-меткой или нет) получаю только я. Остальные предпочитают, чтобы их спам-почта либо прибивалась вся и сразу, либо прибивалась при достижении определенного спам-веса.
    Почтовый шлюз о почтовых алиасах конечной системы не знает и, в принципе, знать не должен.
    А значит, конечный почтовик проделает такую работу: так как шлюз не в курсе, что отдельные личности из списка рассылки не желают получать спам-почту, то спам-письмо письмо будет отправлено на конечный почтовик, а там уже
    либо разложено по ящикам,
    либо уничтожено локальным доставщиком почты (f.e. procmail),
    либо отправлено дальше, если в списке рассылки указан внешний получатель.

    Лишняя работа:
    -уничтожение письма с.п. procmail, так как это письмо могло вовсе не приходить данному получателю;
    -отправка спам-письма далее: я не знаю, как без помощи дополнительного фильтра остановить дальнейший релеинг письма, если его тема содержит метку "SPAM::". По-моему, средствами sendmail.cf это сделать невозможно. Но можно создать локального юзера, прописать в правилах procmail уничтожение почты, набравшей лишний вес, и затем форвард удаленному пользователю. На мой взгляд, это тягомотно.
    Можно было бы делать discard почте, пришедшей со шлюза и имеющей спам-метку в теме письма, но так как разалиасинг происходит перед конечной доставкой, то это письмо будет уничтожено и для тех, кто это заказывал, и для меня, хотя я этого не желаю.

    Простое, но некрасивое решение - просветить почтовый шлюз об алиасах конечной системы и порядке действий по такой схеме:
    -завести локальных одноименных (чтобы не запутаться) с участниками рассылки получателей шлюза и сделать их участниками алиаса adm;
    -в правилах procmail каждого участника рассылки указать, что делать с его почтой - удалять или пересылать на конечный сервер одноименному получателю.
    За долгое время общения с вами, дорогие коллеги :), я поняла, что это самое вами нелюбимое и даже презираемое решение:
    во-первых, это требует постоянной симметрии с конечным почтовиком в части локальных пользователей и алиасов;
    вo-вторых, лишний вызов procmail;
    в-третьих, какая-никакая секьюрность тем самым попирается, поскольку мы вынуждены списки почтовых пользователей хранить в местах, для этого не предназначенных.

    А вот решение от Chris Adams. Как пишет автор, оно не проверялось. Этот способ позволит разалиасить (выявить конечных получателей) алиас до вызова milter, таким образом письмо будет или отправлено конечным получателям или сразу уничтожено.
    Но сначала небольшое отсупление.
    У меня до сих пор нет четкого понимания того, когда именно вызывается milter. Поиск по sendmail-конфе дал такие ответы:
    Claus Assmann: "... It might make sense to avoid sending data to a milter if you can make this decision at connection time, i.e., before a milter is invoked..." [1]
    А это означает вызов milter после RCPT_TO.

    Per Hedeland wrote:
    > In article <1146663496.766526.83...@g10g2000cwb.googlegroups.com>
    > "Anatoly.Oresh...@pnpi.spb.ru" writes:

    > I don't remember if sendmail-rejected recipient addresses are passed to
    > the milter(s) (I think not, but someone will surely correct me if I'm
    > wrong on that), but in any case you don't have to worry about lack of
    > antispam scanning allowing for spam to be delivered to those recipients
    > - if the sendmail rules reject the recipient, it will be excluded from
    > delivery.


    Newsgroups: comp.mail.sendmail
    From: Jose Marcio Martins da Cruz
    Date: Wed, 03 May 2006 23:30:35 +0200
    Local: Thurs, May 4 2006 3:30 am
    Subject: Re: How to change envelope RCPT TO address before calling milter

    Jose Marcio Martins da Cruz:
    At RCPT command, sendmail calls the milter ***before*** it checks if the recipient is a valid address or not. So it pass it to the milter.
    [2]

    И, если опираться на высказывание Andrzej Adam Filip * Sendmail checks OS account existence for mailers with F=w flag set before sending reply to "RCPT TO:" * ([3]) и цитату из op.me "recipient validation happens after check_rcpt has been called" то получается, что sendmail вызывет milter сразу после RCPT_TO:, но перед проверкой достоверности получателя.

    D.Stussy: "...The Rulesets seem to be called BEFORE the corresponding milter call..."

    Ну, и как сказал Neil W Rickert, "...In the normal scheme of things, sendmail won't try to expand the alias until it is ready to deliver. The milter has finished its work before then." ([4])
    Стало быть, наша задача - разалиасить алиас до вызова milter. А так как все процитированные утверждения гуру указывают на то, что milter вызывается после check_rcpt, а именно на этом этапе check_rcpt мы можем вмешаться в анализ адреса получателя, то, "значит, нам туда дорога". То есть, наша задача должна решаться на этапе check_rcpt, что Chris Adams и продемонстрировал.

    Итак, само решение.
    dnl # helpful define for adding to comma separated lists
    define(`COMMAAPPEND', `define(`$1', ifdef(`$1', `$1`,$2'', `$2'))')

    dnl # pass the "alias_user" macro to the milter xxfi_envrcpt() function
    COMMAAPPEND(`confMILTER_MACROS_ENVRCPT',`{alias_user}')

    LOCAL_CONFIG
    # used to create macros to send to milter interface
    Kstorage macro

    # get access to the aliases file
    Kaliases implicit

    LOCAL_RULESETS
    SLocal_check_rcpt
    # clear the alias user storage and parse the recipient
    R$*                  $: $(storage {alias_user} $) $1
    R$*                 $: < ? > $>ParseRecipient $1

    # look for local users
    R< ? > $* < @ $=w >                 $: < ! > $1 @ $2
    R< ? > $* < @ $* >                 $: $1 < @ $2 >
    R< ? > $*                 $: < ! > $1

    # look up user in aliases - this is not recursive (split this out to
    # another ruleset if that is wanted)
    R< ! > $*                  $: < ? > $1
    R< ? > $+ + $* @ $+                 $: < $(aliases $1 $: @ $) > $1 + $2 @ $3
    R< ? > $+ @ $+                  $: < ! > < $(aliases $1 $: @ $) > $1 @ $2
    R< ? > $+ + $*                  $: < ! > < $(aliases $1 $: @ $) > $1 + $2
    R< ? > $*                  $: < ! > < $(aliases $1 $: @ $) > $1
    R< ! > < @ > $+                 $: $1
    # got a match - store it
    R< ! > < $+ > $+                  $: $(storage {alias_user} $@ $1 $) $2

    Но и у этого решения есть свои минусы.
    1. Это решение все-таки потребует прописать алиас на шлюзе, указав его участниками получателей конечного почтовика.
    2. Если среди участников рассылки есть внешние адреса (не принадлежащие конечному серверу), то фильтр такую почту скорее всего не проверит. Вернее, проверит, но только после некоторых па.
    Потому что, например, такой антиспам как Спамооборона, проверяет почту для четко определенного спец. файлом контингента и домена. Использование вышеупомянутого решения потребует перерегистрации ключа, чтобы указать внешний домен для проверки, и добавления внешнего адреса в список обслуживаемых e-mail адресов. А это увеличит кол-во обрабатываемых адресов.
    Не знаю, как разбирается с лицензированными получателями KAS.
    Nota Bene! Как меня заверил специалист от ДрВеб, антиспам VadeRetro не ведет файл с обслуживаемыми адресами, стало быть для него этой проблемы существовать не должно. Но это мы еще проверим. Тестирование VadeRetro в моих планах на ближайшее время значится.
    3. Лишний внутренний трафик. Если раньше проверенное письмо доставлялось на конечный сервер в единственном экземпляре, а уже на месте раскладывалось по ящикам, то теперь будет проведена предобработка на самом шлюзе, и на конечный сервер будет доставлено не одно письмо, а несколько.
    Вывод. В зависимости от почтовой конфигурации, объема adm-почты, соотношения спам:не_спам в adm-почте, а также других требований и потребностей админу остается взвесить плюсы и минусы одного и другого способа и принять правильное :) решение.

    Из минусов решения Chris Adams следуют безусловные плюсы в случае его использования на конечном почтовом сервере, а не на шлюзе.
    Как я уже говорила, используемый мною антиспам вынуждает прописывать все алиасы в файле обслуживаемых адресов несмотря на то, что все участники алиаса уже прописаны в этом файле. Получается, что файл обслуживаемых адресов содержит дубликаты, и около 15 алиасов занимают место в этом файле неоправданно, сокращая тем самым количество обрабатываемых адресов.
    Для того, чтобы это обойти, можно использовать это решение. Разалиасинг произойдет раньше, чем будет вызван антиспам, в итоге будут обработаны письма для конечных получателей, прописанных в файле mailboxes. Это позволит не прописывать алиасы в mailboxes, а место алиасов могут занять конкретные пользователи.
    Минус: Антиспам отработает вместо одного раза - 5 (в моем случае adm@anrb.ru). А это лишняя нагрузка. А со стабильностью у моего антиспама проблемы.
    Так что повторюсь, "...думайте сами, решайте сами, иметь или не иметь..."
    P.S. Если решение Chris Adams у вас заработает раньше, чем у меня, пож-та, дайте знать.

    16.A. Про нерациональность использования Milter.

    10.06.2008. Все оказалось не так просто. Спасибо Владимиру Васильеву.
    Во-первых, чтобы убедиться, что milter вызывается раньше, можно включить define(`confMILTER_LOG_LEVEL',18)
    Во-вторых, " ... Actually this is most likely. Here is a rough outline how sendmail sequences the milters and rulesets upto the DATA command:
    -------------------------------------------------------------------------
    without FEATURE(`delay_checks')FEATURE(`delay_checks)
    -------------------------------------------------------------------------
    1. call milters for connect call milters for connect
    check_relay ruleset
    -------------------------------------------------------------------------
    2. call milters for HELO call milters for HELO
    -------------------------------------------------------------------------
    3. call milters for MAIL call milters for MAIL
    check_mail ruleset
    -------------------------------------------------------------------------
    4. call milters for RCPT call milters for RCPT
    check_rcpt ruleset
    -------------------------------------------------------------------------
    5. check_rcpt ruleset
    check_mail ruleset
    check_relay ruleset
    -------------------------------------------------------------------------
    А вот и иллюстрация. Почта была отвергнута sendmail.cf в рулсете check_eoh по той причине, что посторонний пользователь приконнектился к моему серверу напрямую к 25 порту и попытался отправить письмо. Я этого не допускаю. Пусть пользуется своим сервером и отправляет письмо через удаленный сервер. Напрямую могут отправлять почту только мои клиенты.
    Вы видите, что milter был вызван на каждом этапе smtp-диалога (как меня поправили здесь, правильнее будет называть это обращением к функциям milter'a), а после того, как сработал отлуп в check_eoh, исполнение фильтра было оборвано.

    Nov 12 16:28:49 mail sendmail[13341]: mACBSnEK013341: Milter (drweb-filter): init success to negotiate
    Nov 12 16:28:49 mail sendmail[13341]: mACBSnEK013341: Milter: connect to filters
    Nov 12 16:28:49 mail sendmail[13341]: mACBSnEK013341: milter=drweb-filter, action=connect, continue
    Nov 12 16:28:52 mail sendmail[13341]: mACBSnEK013341: milter=drweb-filter, action=helo, continue
    Nov 12 16:28:53 mail sendmail[13341]: mACBSnEK013341: Milter: sender: <duncan@duncancumming.co.uk>
    Nov 12 16:28:53 mail sendmail[13341]: mACBSnEK013341: milter=drweb-filter, action=mail, continue
    Nov 12 16:28:53 mail sendmail[13341]: mACBSnEK013341: Milter: rcpts: <paradise@anrb.ru>
    Nov 12 16:28:53 mail sendmail[13341]: mACBSnEK013341: milter=drweb-filter, action=rcpt, continue
    Nov 12 16:28:53 mail sendmail[13341]: mACBSnEK013341: ruleset=check_eoh, arg1=10, arg2=368, relay=pppoe-6.kuvshinovo.tver.ru [84.42.20.213], reject=554 5.0.0 Some text: relaying denied.
    Nov 12 16:28:53 mail sendmail[13341]: mACBSnEK013341: from=<duncan@duncancumming.co.uk>, size=434, class=0, nrcpts=1, msgid=<04291436.20081112112630@anrb.ru>, proto=ESMTP, daemon=MTA, relay=pppoe-6.kuvshinovo.tver.ru [84.42.20.213]
    Nov 12 16:28:53 mail sendmail[13341]: mACBSnEK013341: Milter (drweb-filter): abort filter
    Nov 12 16:28:53 mail drweb-milter: [814923795] milter WARN [mACBSnEK013341]: message from <duncan@duncancumming.co.uk> is aborted
    Nov 12 16:28:53 mail sendmail[13341]: mACBSnEK013341: Milter accept: message
    Nov 12 16:28:53 mail sendmail[13341]: mACBSnEK013341: to=<paradise@anrb.ru>, delay=00:00:00, pri=30434, stat=Some text: relaying denied.

    И еще один пример. Очень интересный тем, что ...
    Nov 12 16:22:34 mail sendmail[9627]: mACBMX3o009627: Milter (drweb-filter): init success to negotiate
    Nov 12 16:22:34 mail sendmail[9627]: mACBMX3o009627: Milter: connect to filters
    Nov 12 16:22:34 mail sendmail[9627]: mACBMX3o009627: milter=drweb-filter, action=connect, continue
    Nov 12 16:22:37 mail sendmail[9627]: mACBMX3o009627: milter=drweb-filter, action=helo, continue
    Nov 12 16:22:37 mail sendmail[9627]: mACBMX3o009627: Milter: sender: <paradise@anrb.ru>
    Nov 12 16:22:37 mail sendmail[9627]: mACBMX3o009627: milter=drweb-filter, action=mail, continue
    Nov 12 16:22:37 mail sendmail[9627]: mACBMX3o009627: Milter: rcpts: <gatling@bk.ru>
    Nov 12 16:22:37 mail sendmail[9627]: mACBMX3o009627: milter=drweb-filter, action=rcpt, continue
    Nov 12 16:23:26 mail sendmail[9627]: mACBMX3o009627: from=<paradise@anrb.ru>, size=32269850, class=0, nrcpts=1, msgid=<001601c944b9$ef6ee2f0$9d01a8c0@bvk>, proto=ESMTP, daemon=MTA, relay=92.50.138.202.dynamic.ufanet.ru [92.50.138.202]
    ... в случае, если письмо проходит все проверки и находится в стадии непосредственной доставки, то есть макрос $&{deliveryMode} равен i, то мы уже можем увидеть обращения и к headers (заголовки письма), и разбор тела письма milter'ом.
    Nov 12 16:23:26 mail sendmail[9627]: mACBMX3o009627: Milter (drweb-filter): headers, send
    Nov 12 16:23:26 mail sendmail[9627]: mACBMX3o009627: milter=drweb-filter, action=header, continue
    Nov 12 16:23:26 mail sendmail[9627]: mACBMX3o009627: Milter (drweb-filter): headers, sent
    Nov 12 16:23:26 mail sendmail[9627]: mACBMX3o009627: milter=drweb-filter, action=eoh, continue
    Nov 12 16:23:26 mail sendmail[9627]: mACBMX3o009627: Milter (drweb-filter): body, send
    Nov 12 16:23:26 mail sendmail[9627]: mACBMX3o009627: milter=drweb-filter, action=body, continue
    Nov 12 16:23:26 mail sendmail[9627]: mACBMX3o009627: milter=drweb-filter, action=body, continue
    Nov 12 16:23:26 mail sendmail[9627]: mACBMX3o009627: milter=drweb-filter, action=body, continue
    Nov 12 16:23:26 mail sendmail[9627]: mACBMX3o009627: milter=drweb-filter, action=body, continue
    Nov 12 16:23:27 mail sendmail[9627]: mACBMX3o009627: milter=drweb-filter, action=body, continue
    Nov 12 16:23:27 mail sendmail[9627]: mACBMX3o009627: milter=drweb-filter, action=body, continue
    Nov 12 16:23:27 mail sendmail[9627]: mACBMX3o009627: milter=drweb-filter, action=body, continue
    Nov 12 16:23:27 mail sendmail[9627]: mACBMX3o009627: milter=drweb-filter, action=body, continue
    Nov 12 16:23:27 mail sendmail[9627]: mACBMX3o009627: milter=drweb-filter, action=body, continue
    Nov 12 16:23:27 mail sendmail[9627]: mACBMX3o009627: Milter (drweb-filter): body, sent
    Nov 12 16:23:27 mail drweb-milter: [809779218] milter INFO [mACBMX3o009627]: success save mail to /var/drweb/msgs/in/1/001904A1/
    Nov 12 16:23:35 mail sendmail[9627]: mACBMX3o009627: Milter add: header: X-Antivirus: Dr.Web (R) for Unix mail servers drweb plugin ver.4.44.2.0805030
    Nov 12 16:23:35 mail sendmail[9627]: mACBMX3o009627: Milter add: header: X-Antivirus-Code: 0x100000
    Nov 12 16:23:35 mail drweb-milter: [809779218] milter INFO [mACBMX3o009627]: processing message from <paradise@anrb.ru> is over
    Nov 12 16:23:35 mail sendmail[9627]: mACBMX3o009627: Milter accept: message
    Nov 12 16:23:36 mail sendmail[10078]: mACBMX3o009627: to=<gatling@bk.ru>, ctladdr=<paradise@anrb.ru> (1579/45), delay=00:00:59, xdelay=00:00:01, mailer=esmtp, pri=32389850, relay=mxs.mail.ru. [94.100.176.20], dsn=5.0.0, stat=Service unavailable
    Nov 12 16:23:36 mail sendmail[10078]: mACBMX3o009627: mACBNa3o010078: DSN: Service unavailable
    В-третьих, надо все это обдумать.

    20.11.2009. Еще одна иллюстрация. VadeRetro и DrWeb велено не проверять почту от постмастера:
    sender:postmaster@anrb\.ru scan=all:-drweb:-vaderetro
    При этом мы все равно видим обращения к milter. То есть для того, чтобы этих обращений вовсе не было, видимо, нужен патч milter-rrres Joe Maimon или milter-manager (спасибо Павлу Гришину за ссылку и подробную информацию). Жаль, что никак не дойдут руки использовать milter-manager по схеме: свой собств.фильтр -> VadeRetro -> Спамооборона-1024. Задумка тут такая. Мой собств. фильтр не злобный и отсекает явный спам, избавляя два послед. фильтра от лишней работы. Далее вступает VR, его качество фильтрации в этом сезоне меня не очень устраивает, поэтому следом должна отработать Спамооборона. Бесплатная версия не позволяет отделить почту от локальных пользователей, чтобы она не проверялась, поэтому milter-manager здесь будет очень кстати, т.к. избавит локальную почту от проверки, а значит, будет проверена только почта от внешних отправителей и только та почта, что не была отвергнута 2-мя предыд. фильтрами (возможно, можно будет не отдавать на проверку и ту почту, которая набрала большое кол-во баллов, но не попала в разряд безусловного спама у VR) а, значит, будет больше шансов уложиться в ограничение 1024 проверяемых писем в сутки.

    Jan 20 14:04:07 mail sendmail[15337]: n0K947hA015337: Milter (drweb-filter): init success to negotiate
    Jan 20 14:04:07 mail sendmail[15337]: n0K947hA015337: Milter: connect to filters
    Jan 20 14:04:07 mail sendmail[15337]: n0K947hA015337: milter=drweb-filter, action=connect, continue
    Jan 20 14:04:07 mail sendmail[15337]: n0K947hA015337: milter=drweb-filter, action=helo, continue
    Jan 20 14:04:07 mail sendmail[15337]: n0K947hA015337: Milter: sender: <postmaster@anrb.ru>
    Jan 20 14:04:07 mail sendmail[15337]: n0K947hA015337: milter=drweb-filter, action=mail, continue
    Jan 20 14:04:07 mail sendmail[15337]: n0K947hA015337: Milter: rcpts: <comestaie@mail.ru>
    Jan 20 14:04:07 mail sendmail[15337]: n0K947hA015337: milter=drweb-filter, action=rcpt, continue
    Jan 20 14:04:07 mail sendmail[15337]: n0K947hA015337: from=<postmaster@anrb.ru>, size=454, class=0, nrcpts=1, msgid=<809577913.20090120140116@anrb.ru>, proto=ESMTP, daemon=MTA, relay=rome.anrb.ru [1.3.4.1]
    Jan 20 14:04:07 mail sendmail[15337]: n0K947hA015337: Milter (drweb-filter): headers, send
    Jan 20 14:04:07 mail sendmail[15337]: n0K947hA015337: milter=drweb-filter, action=header, continue
    Jan 20 14:04:07 mail last message repeated 11 times
    Jan 20 14:04:07 mail sendmail[15337]: n0K947hA015337: Milter (drweb-filter): headers, sent
    Jan 20 14:04:07 mail sendmail[15337]: n0K947hA015337: milter=drweb-filter, action=eoh, continue
    Jan 20 14:04:07 mail sendmail[15337]: n0K947hA015337: Milter (drweb-filter): body, send
    Jan 20 14:04:07 mail sendmail[15337]: n0K947hA015337: milter=drweb-filter, action=body, continue
    Jan 20 14:04:07 mail sendmail[15337]: n0K947hA015337: Milter (drweb-filter): body, sent
    Jan 20 14:04:07 mail drweb-milter: [2294333468] milter INFO [n0K947hA015337]: success save mail to /var/drweb/msgs/in/0/00242100/
    Jan 20 14:04:07 mail drweb-maild: [229390] maild INFO start processing msg 00242100 ...
    Jan 20 14:04:07 mail drweb-maild: [229390] maild INFO CheckMsg: set skip for plugin vaderetro. from=<postmaster@anrb.ru>; to=<comestaie@mail.ru>
    Jan 20 14:04:07 mail drweb-maild: [229390] maild INFO CheckMsg: skip attach msg to plugin vaderetro for all rcpts.
    Jan 20 14:04:07 mail drweb-maild: [229390] maild INFO CheckMsg: set skip for plugin drweb. from=<postmaster@anrb.ru>; to=<comestaie@mail.ru>
    Jan 20 14:04:07 mail drweb-maild: [229390] maild INFO CheckMsg: skip attach msg to plugin drweb for all rcpts.
    Jan 20 14:04:07 mail drweb-maild: [229390] maild INFO msg 00242100 is accepted: send it by filter
    Jan 20 14:04:07 mail drweb-milter: [2294333468] milter INFO drweb-maild return pass action for msg 00242100
    Jan 20 14:04:07 mail drweb-milter: [2294333468] milter INFO [n0K947hA015337]: processing message from <postmaster@anrb.ru> is over
    Jan 20 14:04:07 mail sendmail[15337]: n0K947hA015337: Milter accept: message
    Jan 20 14:04:48 mail sendmail[15341]: n0K947hA015337: to=<comestaie@mail.ru>, ctladdr=<postmaster@anrb.ru> (737/45), delay=00:00:41, xdelay=00:00:41, mailer=esmtp, pri=120454, relay=mxs.mail.ru. [94.100.176.20], dsn=2.0.0, stat=Sent (OK id=1LPCUe-0001Jv-00)

    Еще ссылки по теме: "Последовательность исполнения команд в связке sendmail+milter":
    1. Вопрос с comp.mail.sendmail: Milters vs Sendmail access list vs DNSBLs. Can anyone tell me when these three items are usually called?
    Ответ Claus Assmann:
    "Simplified answer:
    1. access
    2. DNSBL
    3. milter
    Note that the access DB is used in several stages of the SMTP dialogue (just as milter), hence the above answer is not complete... "
    2. How to bypass milter со страницы "Спамооборона+sendmail".
    3. Небольшое обсуждение с полезными уточнениями на admin-форуме linux.org.ru
    4.

    17. Копирование транзитной почты для определенного домена в определенный ящик

    14.04.2008.
    На днях я замахнулась на святая святых - на старое, всем хорошо известное решение O. Koreshkov по копированию почты. Постановка задачи требовала копирование всей почты для/от определенного домена. Сделанные изменения носят скорее косметический характер, тем не менее один человек утверждает, что у него это заработало.
    Приношу свои извинения автору copymail за утверждение об имевшей место опечатке в первоисточнике. Ее нет и не могло быть. Кроме того, исполняю требование автора и публикую вот этот абзац с его страницы.
    Нижеизложенный материал не претендует на полноту, четкость, ясность или достоверность изложения и предоставляется автором "КАК ЕСТЬ". Автор не несет никакой отвественности за любое использование данного материала. Любое использование, копирование, цитирование, полностью или частично должно включать данный текст, ссылку на данный ресурс, а так же следующию строку без изменений:
    © 2001-2002, O. Koreshkov .

    А чуть-чуть переписанное решение имеет вид (изменения выделены):

    LOCAL_RULE_0
    # Send mail $={COPY} to copymail mailer
    R$* < @ $+ . > $*                                     $:$1 < @ $2 . > $3 $| $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 $| $5
    R$* < @ $+ . > $* $| $={COPY}                            $#copymail $@ localhost $: $1 < @ $2 . > $3
    R$* < @ $+ . > $* $| $*                            $: $1 <@ $2 . > $3


    А вот вариант копирования и по e-mail, и по домену, и по ip-адресу источника письма (тоже слегка переписано из оригинала, и уже проверено)
    #To: E-mail check
    R$+ < @ $+ . > $*                           $: $1 < @ $2 . > $3 $| $1 @ $2
    R$+ < @ $+ . > $* $| $={COPY}                  $#copymail $@ localhost $: $1 < @ $2 . > $3

    #To: Domain check
    R$+ < @ $+ . > $* $| $+ @ $={COPY}                  $#copymail $@ localhost $: $1 < @ $2 . > $3

    #From: All originating from some ip are copying
    R$* < @ $+ . > $* $| $*                   $: $1 <@ $2 . > $3 $| $&{client_addr}
    R$* < @ $+ . > $* $| $={COPY}                  $#copymail $@ localhost $: $1 < @ $2 . > $3

    #From: E-mail check
    R$* < @ $+ . > $* $| $*                   $: $1 <@ $2 . > $3 $| $&f
    R$* < @ $+ . > $* $| <$*>                  $: $1 <@ $2 . > $3 $| $4
    R$* < @ $+ . > $* $| $={COPY}                  $#copymail $@ localhost $: $1 < @ $2 . > $3

    #From: Domain check
    R$* < @ $+ . > $* $| $+ @ $={COPY}                            $#copymail $@ localhost $: $1 < @ $2 . > $3

    #The rest are welcome without copying
    R$* < @ $+ . > $* $| $*                   $: $1 <@ $2 . > $3

    P.S. Автор copymail предусмотрел вставку дополнительного подзаголовка в заголовок письма, извещающий получателя о том, что письмо было скопировано "due to business requirements". Я полностью поддерживаю автора и надеюсь, что морально-этическая сторона вопроса будет учтена теми, кто будет пользоваться этими решениями.
    Иначе, честное слово, уж очень хочется помыть руки. Тщательно. С мылом. Хозяйственным. И не один раз.


    P.S.2. Обратите внимание на это замечание многоуважаемого Z0termaNN'a:
    "...только этот способ намного более дорогой, чем addrcpt в milter, т.к. каждое сообщение обрабатывается 2 раза, а кроме того на каждое копирование производится запуск sendmail. такими приемами пользовались когда milterа не было, да и то не всегда."
    Причина "дороговизны" в особенностях рулсета, в котором решается данная задача.


    18. Анализ доменного имени релея для сообщений с адресов домена mail.ru

    21.04.2008.
    Пробегая мимо конференции fido7.ru.unix, увидела такой вопрос: "А вот как-бы сделать, чтобы сендмейл принимал почту с адресатами от домена, например, mail.ru только с хоста mxs.mail.ru? При этом остальные домены это затрагивать не должно. "
    Регистрация на этой конфе занудная, а эта задачка перекликается с той, что я решала почти два года назад, и решается на раз.
    LOCAL_CONFIG
    LOCAL_RULESETS
    SLocal_check_mail
    R< $+@mail.ru >               $: < $1@mail.ru > $| < $&{client_name} >
    R< $+@mail.ru > $| < mxs.mail.ru >            $@ OK
    R< $+@mail.ru > $| $+               $#error $@ 5.7.1 $:"554 Sorry, ваше объяснение причины отказа"


    19. Выводим в лог тему сообщения, если оно пришло с нашего mx-a.
    16.05.2008.
    HSubject:                  $>Check_Subject
    SCheck_Subject
    R$*                                     $: $1 <$&{client_addr}>
    R$*<212.193.134.3>                           $: $(syslog syslog:Subject: $1 - <$&{client_addr}> $)

    Зачем это нужно? Во время сбора сравнительной статистики по пропускам спама CO и VR, понадобилось выводить в лог тему сообщения, поступающих со второго mx'a.


    20. Отказываем письму, если в заголовке несколько тем.
    20.05.2008.
    Сегодня пришло письмо с таким заголовком:

    Return-Path: <angeliquehe@mail.ru>
    Received: from mx38.mail.ru (mx38.mail.ru [194.67.23.16])
            by mail.anrb.ru (8.14.2/8.14.2) with ESMTP id m4KANuMh004866
            for <paradise@anrb.ru>; Tue, 20 May 2008 16:23:59 +0600
    Received: from mail by mx38.mail.ru with local=20
            id 1JyOwJ-000Q00-00
            for paradise@anrb.ru; Tue, 20 May 2008 14:19:27 +0400
    X-ResentFrom: <12345@mail.ru>
    Received: from [83.31.177.157] (port=14844 helo=COMP4804)
            by mx38.mail.ru with asmtp=20
            id 1JyOvo-000PEb-00; Tue, 20 May 2008 14:18:56 +0400
    To: =?windows-1251?B?+/f44Q==?= <mihail-belashov@mail.ru>
    From: =?windows-1251?B?IC4gx+Xs6/8sIO3l5OLo5ujs7vHy/CDy?= <angeliquehe@=
    mail.ru>
    Subject: [SO:SPAM:: 16.40] =87=80=8A=8E=8D=9B =8E=81 =8E=81=8E=90=8E=92=85 =
    =87=85=8C=85=8B=9C =91=85=8B=9C=95=8E=87. =8D=80=87=8D=80=97=85=8D=88=9F
    Subject: =?windows-1251?B?3yDl9/nO1crCzsH1+8ne/uLS1u3g3tYgye343fff/SDv39n=
    348P1IMTT/tDQ/Q==?=
    Subject: =AE=B8=8D=8D=86=96=90=91=85=85=B8=85=B4=85=AD=AB=83=A0=B1=BE=AE=AD=
    =A1=8C=A1=AF=AA=BD=B7=8B=AC=9C=A8=91=86=8D=9B=B7=A3=B9=81=B1=B0
    Subject: =87=80=8A=8E=8D=9B =8E=81 =8E=81=8E=90=8E=92=85 =87=85=8C=85=8B=9C=
     =91=85=8B=9C=95=8E=87. =8D=80=87=8D=80=97=85=8D=88=9F
    MIME-Version: 1.0
    Content-Type: image/gif
    Content-Transfer-Encoding: binary
    X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.2180
    Message-Id: <E1JyOvo-000PEb-00.angeliquehe-mail-ru@mx38.mail.ru>
    Date: Tue, 20 May 2008 14:18:56 +0400
    X-Spam: Not detected
    X-Spam: Not detected
    X-Spam-Ystatus: hits=16.40
    X-Spam-Flag: YES
    X-Spam-Yversion: Spamooborona-2.1.0

    X-Antivirus: Dr.Web (R) for Mail Servers on mail host
    X-Antivirus-Code: 100000

    Когда я открыла письмо, то в поле Subject было это:
    ‡ЂЉЋЌ› ЋЃ ЋЃЋђЋ’… ‡…Њ…‹њ ‘…‹њ•Ћ‡. ЌЂ‡ЌЂ—…Ќ€џ
    Как видите, метки Спамообороны нет, хотя письмо было ей проверено, и присвоен спам-вес 16.40.
    TheBat! взял последнюю из тем и показал в поле Subject: Если пользователь откладывает с.п. почтовой программы спам-письма в отдельную папку, то это письмо при таком раскладе в нее не попадает.

    Как посчитать количество тем в заголовке письма?
    #Макрос, накапливающий число тем
    D{Subjects_count}0

    HSubject:                  $>Check_Subject

    SCheck_Subject
    R$*                           $: $(arith + $@ $&{Subjects_count} $@ 1 $)
    R$*                           $: $(storage {Subjects_count} $@ $1 $)
    R$*                           $: $(arith l $@ $&{Subjects_count} $@ 2 $)
    RFALSE                           $: $(syslog syslog:Subject:counter: $&{Subjects_count} $)
    RFALSE                           $:  $(storage {Subjects_count} $@ $1 $)

    Что делать дальше? Понаблюдав и приняв во внимание следующее, (эти правила "формально" сработают в случае форвардинга письма: в этом случае поле Subject вложенного письма, находящегося в теле основного, также посчитается, и количество тем будет больше одного, но все это для sendmail не будет иметь никакого значения) смело блокирую такие случаи:
    SCheck_Subject
    R$*                           $: $(arith + $@ $&{Subjects_count} $@ 1 $)
    R$*                           $: $(storage {Subjects_count} $@ $1 $)
    R$*                           $: $(arith l $@ $&{Subjects_count} $@ 2 $)
    RFALSE                           $: $(syslog syslog:Subject:counter: $&{Subjects_count} $) FALSE
    RFALSE                             $#error $: 554 Sorry, далее ваш текст.
    Scheck_eoh
    R$*                   $: $(storage {Subjects_count} $)

    Пока срабатываний немного.
    Вот фрагмент лога, когда письмо форвардится:
    May 23 14:28:18 mail sendmail[5703]: m4N8SA4P005703: from=<consiglio@anrb.ru>, size=15854, class=0, nrcpts=2, msgid=<167212467.20080523142404@anrb.ru>, proto=ESMTP, daemon=MTA, relay=[a.b.c.d]
    May 23 14:28:18 mail drweb-smf[5705]: [m4N8SA4P005703]: scan: the message(drweb.tmp.x89cp3) sent by consiglio@anrb.ru to rcpts is passed
    May 23 14:28:18 mail drweb-smf[5705]: [m4N8SA4P005703]: processing message from consiglio@anrb.ru is over
    May 23 14:28:18 mail sendmail[5703]: m4N8SA4P005703: Milter add: header: X-Antivirus: Dr.Web (R) for Mail Servers on mail host
    May 23 14:28:18 mail sendmail[5703]: m4N8SA4P005703: Milter add: header: X-Antivirus-Code: 100000
    May 23 14:28:18 mail sendmail[5746]: m4N8SA4P005703: to=<gatling@anrb.ru>, ctladdr=<consiglio@anrb.ru> (515/45), delay=00:00:00, xdelay=00:00:00, mailer=esmtp, pri=165854, relay=anrb.ru. [x.y.z.f], dsn=2.0.0, stat=Sent (m4N8h77n000375 Message accepted for delivery)
    May 23 14:28:19 mail sendmail[5746]: m4N8SA4P005703: syslog:Subject:counter:1.-.WG:ILA.Berlin.27.05.08.-.01.06.08
    May 23 14:28:19 mail sendmail[5746]: m4N8SA4P005703: syslog:Subject:counter:2.-.WG:ILA.Berlin.27.05.08.-.01.06.08
    May 23 14:28:19 mail sendmail[5746]: m4N8SA4P005703: ruleset=Check_Subject, arg1= WG: ILA Berlin 27.05.08 - 01.06.08, relay=[a.b.c.d], reject=554 5.0.0 Sorry, ...
    May 23 14:28:23 mail sendmail[5746]: m4N8SA4P005703: to=<paradev@mail.ru>, ctladdr=<consiglio@anrb.ru> (515/45), delay=00:00:05, xdelay=00:00:05, mailer=esmtp, pri=165854, relay=mxs.mail.ru. [194.67.23.20],
    dsn=2.0.0, stat=Sent (OK id=1JzSYi-000O0r-00)

    А вот фрагмент лога, когда письмо блокируется:
    Jul 21 13:52:38 mail sendmail[22490]: m6L7qYPI022490:syslog:Subject:counter:1.1.-.\317\360\340\351\361.\356\362.21.07.2008
    Jul 21 13:52:38 mail sendmail[22490]: m6L7qYPI022490:syslog:Subject:counter:2.2.-.\317\360\340\351\361.\356\362.21.07.2008
    Jul 21 13:52:38 mail sendmail[22490]: m6L7qYPI022490: ruleset=Check_Subject, arg1= \317\360\340\351\361 \356\362 21.07.2008, relay=be72.masterhost.ru [83.222.23.242], reject=554 5.0.0 Sorry, ...
    Jul 21 13:52:45 mail sendmail[22490]: m6L7qYPI022490: from=<php-sender-zapavto.ru@undeliverable.masterhost.ru>, size=348153, class=0, nrcpts=1, msgid=<20080721074707.97374.qmail@be72.masterhost.ru>, bodytype=8BITMIME, proto=SMTP, daemon=MTA, relay=be72.masterhost.ru [83.222.23.242]
    Jul 21 13:52:45 mail drweb-milter: [4207345699] milter WARN [m6L7qYPI022490]: message from <php-sender-zapavto.ru@undeliverable.masterhost.ru> is aborted
    Jul 21 13:52:45 mail sendmail[22490]: m6L7qYPI022490: to=<paradise@anrb.ru>, delay=00:00:07, pri=378153, stat=Sorry, ...

    25.10.2008. С учетом новой информации данная проверка будет выглядеть приблизительно так (пока не проверялось):

    SCheck_Subject
    R$*                           $: $1 <$&{deliveryMode}>
    # сразу завершаем рулсет на этапе непосредственной доставки сообщения
    R$*<i>                            $@ OK
    # в остальных случаях продолжаем, избавившись сначала от макроса $&{deliveryMode}
    R$*<$+>                            $: $1
    R$*                           $: $(arith + $@ $&{Subjects_count} $@ 1 $)
    R$*                           $: $(storage {Subjects_count} $@ $1 $)
    R$*                           $: $(arith l $@ $&{Subjects_count} $@ 2 $)
    RFALSE                             $#error $: 554 Sorry, далее ваш текст.

    29.01.2010. Небольшое обсуждение правомерности дублирования заголовков.

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

    14.10.2008.
    Вторая часть "Типовых задачек" разрослась, поэтому, сорри, эта задачка и остальные перемещены в третью часть.



    Обратная связь
    Страница создана 27 июня 2007г. Последнее обновление - 30 сентября 2010г.