The Problem:
I want to filter incoming email before passing it on to the Exchange server. Commercial solutions are expensive and not very flexible. A procmail based approach seemed like a good idea as I'm pretty familiar with procmail.
The Solution:
The solution is basically as follows:
- Configure sendmail to pass everything to procmail
- set up procmail filters to check every mail
- suspect mails get stored and a notice is sent to the mail-admin who can review the spam
- real mails get sent through
- suspect mails can get sent on if the filters have trapped one by mistake.
Sounds simple, eh? Well then you're a sendmail/procmail guru and you're just reading this page to find mistakes. (If you do find one, email me with it.)
If it doesn't sound simple, then I'll go through my solution step by step. It's simple in principle, but the devil is always in the details.
Configuring Sendmail
Some Sendmail Related Links: Sendmail (3rd Edition) - Brian Costales, Eric Allman Linux Sendmail Administration - Craig Hunt The first thing to do is get sendmail. Go to sendmail.org and download the latest version and follow the instructions. Eventually, you may get it to work.
Or you could get the rpm from RedHat, if you're a RedHat type. I use the most recent version built from source rather than the RPM supplied with the distribution. I tend to do this with most mission critical software - makes me happier about staying ahead of exploits.
For the filtering, there is enough information on the web to let you know how to do this, but most of it tends to make the assumption that you know exactly what every line in the sendmail.cf file does. Most of the methods I've seen just show you the ruleset extension below (in the sendmail.mc) file) and don't tell you what it's doing. It's important to know exactly what's going on, or you'll get mail loops.
The next step is to get sendmail to rewrite all incoming addresses and send them to a specific mail, then change them back before sending them on normally. To do this, you need to edit the sendmail.cf file. Well, actually you don't, but you need to specify a little rule in the .cf format which is bad enough. Your sendmail.mc should look like this:
divert(-1)
dnl This is the macro config file used to generate the /etc/sendmail.cf
dnl file. If you modify this file you will have to regenerate the
dnl /etc/sendmail.cf by running this macro config through the m4
dnl preprocessor:
dnl
dnl m4 /etc/sendmail.mc > /etc/sendmail.cf
dnl
dnl You will need to have the sendmail-cf package installed for this to
dnl work.
include(`/usr/lib/sendmail-cf/m4/cf.m4')
define(`confDEF_USER_ID',``8:12'')
OSTYPE(`linux')
define(`confPRIVACY_FLAGS',`noexpn, novrfy')
define(`ALIAS_FILE',`/etc/aliases')
define(`confFORWARD_PATH',`')
define(`confLOG_LEVEL',`14')
define(`MAIL_HUB',`mail.foo.com')
define(`SMART_HOST',`mail.foo.com')
FEATURE(`access_db')
FEATURE(`blacklist_recipients')
FEATURE(`virtusertable',`hash -o /etc/mail/virtusertable')dnl
MAILER(smtp)
MAILER(procmail)
LOCAL_CONFIG
CPprocmail
LOCAL_RULE_0
R$*<@foo.com.> $#procmail $@/etc/procmail/filter.rc $:$1@foo.com.procmail.
R$*<@foo.com> $#procmail $@/etc/procmail/filter.rc $:$1@foo.com.procmail.
R$*<@$*.procmail.> $1<@$2> Already filtered, map back
R$*<@$*.procmail> $1<@$2> Already filtered, map back
MAILER_DEFINITIONS
Mprocmail, P=/usr/bin/procmail, F=DFMmShun, S=11/31, R=21/31, T=DNS/RFC822/X-Unix,
A=procmail -m $h $g $u
The lines you want to pay attention to there are the lines after LOCAL_RULE_0.
These lines rewrite any incoming address from foo.com to foo.com.procmail. (with a final period). They then specify that the mailer for these addresses is the local procmail program and the filter specified in /etc/procmail/filter.rc.
There should be [TAB] characters after the first term in each of the lines beginning with R$, i.e. the first (and only the first) space in the line should actually be a [TAB] character. This is probably the single most asked question on this entire topic.
when procmail is finished with the message, it gets sent back with a foo.com.procmail. address, and this lets sendmail know that the mail has already been sent through procmail and filtered. Sendmail then changes the address back and hands the message on to the relay for delivery.
Procmail setup
Your procmail filter.rc file should be in the /etc/procmail directory.
################################################################
#
# procmail rules to filter mail on a gateway
# This code © dave o'brien 2002
# Released under GPL.
#
################################################################
PATH="/usr/bin:$PATH:/usr/local/bin"
SHELL="/bin/sh"
LOGFILE="/var/log/procmail.log"
NL="
"
LOGABSTRACT=all
#VERBOSE=yes
LINEBUF=8192
:0 H
* 32000^0
* 1^1 .
{
LINEBUF="$="
}
#Spamassassin (we run the spamd daemon all the time)
:0fw
| spamc -a
#Forward to recipients
:0
! -oi -f "$@"
#
################################################################
Some Procmail Related Links: The Procmail Companion - Martin McCarthy What the above filter file is doing should be pretty obvious if you know procmail, but basically, it sets up some environment variables, sends the mail to an external filter (SpamAssassin, that's the spamc line) and forwards it back to sendmail after processing. The email will have the SpamAssassin header added to it if it's spam. Optionally, you can have it send all spam to one mailbox.
I recommend you look at the Sendmail code in the sendmail.mc above and understand exactly what's going on (try testing some email addresses using sendmail in test mode). Then go buy the Unix System Administrator's Handbook and read the chapter on electronic mail, closely followed by the O'Reilly Sendmail Book (3rd Edition - Brian Costales, Eric Allman). Then install sendmail from source. *Now* you know whats going on. Sendmail is complex, but study pays dividends.