Introduction
This documents the way Alejandro Forero Cuervo prefers to configure email servers.
The system is designed with the basic goal of allowing a power user, someone receiving lots of email probably through many different mailing lists, to handle things efficiently.
This is just a draft, I'm still improving this document.
Features
- IMAP based access.
- Virus control with ClamAV.
- Spam control with SpamAssassin:
- Individual per-user configuration files and databases (since SpamAssassin automatically learns from messages it sees). I prefer this over a global database since I believe it is more likely to produce correct results in the long run.
- Messages way too likely to be spam are copied to a global spam folder (in case the administrator wants to look at them). Likely-spam messages are sent to the user's "spam" folder. Regular messages are sent to the inbox.
- In order to re-train the spam system, users simply need to copy messages to their "learn-as-ham" or "learn-as-spam" folder.
- Users can define their own rules to automatically filter their messages into specific folders, using Sieve.
To do
Our system isn't perfect. Far from it. Here are some things it misses which we would like to have:
- Automatic expiration of messages
- Make it possible for assign a date to each folder to have messages on the expire automatically. This is possible with Cyrus 2.2, but we're using Cyrus 2.1 (since 2.2 is not available in Debian stable as of the time of this writing).
- Use DomainKeys and SMTP auth
- Our current document does not yet explain how to configure DomainKeys nor SMTP Auth.
Postfix
http://www.loadtr.com/resimuploads/52191c2a7c7bdda441df3b565050997b.jpg
master.cf
Define the mfilter service:
smtp inet n - - - - smtpd
pickup fifo n - - 60 1 pickup
cleanup unix n - - - 0 cleanup
qmgr fifo n - - 300 1 qmgr
rewrite unix - - - - - trivial-rewrite
bounce unix - - - - 0 bounce
defer unix - - - - 0 bounce
trace unix - - - - 0 bounce
verify unix - - - - 1 verify
flush unix n - - 1000? 0 flush
proxymap unix - - n - - proxymap
smtp unix - - - - - smtp
relay unix - - - - - smtp
showq unix n - - - - showq
error unix - - - - - error
local unix - n n - - local
virtual unix - n n - - virtual
lmtp unix - - n - - lmtp
anvil unix - - n - 1 anvil
mfilter unix - n n - - pipe
flags=Rq user=cyrus argv=/var/spool/cyrus/bin/mfilter_transport ${user} ${extension}SpamAssassin
Training
Root's ~/.fetchmailrc:
poll localhost protocol imap user cyrus password PWPWPWPW fetchall no rewrite
Avoid encryption since we're connecting to localhost. :-)
~cyrus/bin/sa-learn-pending:
for user in $(getent passwd | cut -f1 -d:); do
if groups $user | grep mailusers >/dev/null; then
for type in ham spam; do
fetchmail --folder user.$user.learn-as-$type --silent --mda "( echo -n 'From %F ' ; date '+%a %b %e %R:%S %Y' ; /bin/cat ; echo ) >> /tmp/mbox.$$";
if test -f /tmp/mbox.$$; then
su $user -c "sa-learn --$type --mbox" </tmp/mbox.$$;
rm /tmp/mbox.$$;
fi
done
fi
done
If you figure out how to suppress the fetchmail: Server CommonName mismatch: freaks-unidos.net != localhost errors (that still only receives unencrypted imap connections through the loopback interface), let me know.
Make a crontab for user root that runs this script. I choose to run it once every day, but you can pick a different interval.
11 2 * * * ~cyrus/bin/sa-learn-pending 2>/dev/null >/dev/null
Here are a few notes:
- The crontab dumps the output of the sa-learn-pending command. We shouldn't do that. But then, the CommonName mismatch error would make things very verbose (and I don't want to just grep it out, that adds more complexity).
- The sa-learn-pending scripts does this:
- For every user in the mailusers group:
- Fetch all learn-as-ham into a mbox folder using fetchmail and then learn all of them. Do the same for the learn-as-spam messages.
- For every user in the mailusers group:
- The --mda parameter in sa-learn-pending isn't very reliable; it would be best to use a program to deliver messages to the mbox with better error reporting. If you figure out one to use instead, let me know. I'll use it for the time being since losing messages there (before the training) isn't that bad (we're erasing them anyway!).
Filter script
~cyrus/bin/mfilter_transport, what a sexy script:
#!/bin/sh
USER=$1
MAILBOX=$2
EX_OK=0
EX_TEMPFAIL=75
EX_UNAVAILABLE=69
VIRUS_RETURN=$EX_OK;
/usr/bin/spamc -u $USER >/tmp/filter.$$ || { echo "Unable to save mail: /tmp/filter.$$"; rm -f /tmp/filter.$$; exit $EX_TEMPFAIL; }
CLAMAV=$(/usr/bin/clamdscan --disable-summary --stdout - </tmp/filter.$$)
if echo $CLAMAV | grep -q FOUND; then
MAILBOX=virus;
USER=cyrus;
FORCE_EXIT=$EX_OK;
elif echo $CLAMAV | grep -q ERROR; then
echo $CLAMAV;
rm -f /tmp/filter.$$;
exit $EX_TEMPFAIL;
elif egrep -q "^X-Spam-Level: \*{12,}" /tmp/filter.$$; then
MAILBOX=spam;
USER=cyrus;
FORCE_EXIT=$EX_UNAVAILABLE;
elif grep -q "^X-Spam-Flag: YES" /tmp/filter.$$; then
MAILBOX=spam;
fi;
/usr/sbin/cyrdeliver -a "$USER" -e -m "$MAILBOX" "$USER" </tmp/filter.$$
RET=$?;
rm -f /tmp/filter.$$;
test $FORCE_EXIT && exit $FORCE_EXIT
exit $RET;
Usage
This section explains how to use the email system from an end-user's point of view.
Filtering mails
Right now setting up filter is rather difficult: it assumes knowledge of Sieve as well as the capability of login into the machine (eg. using an SSH client or some other similar method) and running commands on it.
Create your Sieve rules
Write your rules into ~/lists.script (you could use any other name but make sure to use it in the steps below, when applying your script to the server).
The following is an example:
require ["fileinto"]; if header :contains "list-post" "<mailto:users@subversion.tigris.org>" { fileinto "INBOX.subversion-users"; stop; }
Mutt
Mutt is my favorite email client. :-)
Configuration
Highlighting messages
I want to highlight messages coming from an address from which I had previously received ham. I made the following script:
#!/bin/sh # I use two sed processes voluntarily (to easily handle both "From: # foo@bar.com" as well as "From: foo <foo@bar.com>"). ADDRESS=$(grep ^From: | head -1 | sed 's/^From: *//' | sed 's/^.*<\(.*\)>.*$/\1/') # Add it unless it is already there. grep $ADDRESS ~/.mutt.scores.rc || echo "score '~f $ADDRESS' 10" >>~/.mutt.scores.rc
It reads a message from its standard input, extracts the email address it comes from and adds it to the .mutt.scores.rc file unless it is already there. The next time Mutt reads it, it will give a greater score to messages coming from it.
To highlight the messages I just add the following to ~/.muttrc
source "/home/azul/mutt.scores.rc"; color index brightwhite default '~n 10-';
Note that you could also color messages based on the X-Spam-Level header (eg. make it so messages with a high spam score are shown in a color that is slightly more difficult to read), but that slows down the process of displaying messages significantly. An option would be to use the X-Label header, but that seems too complicated (and it would make it difficult to use that header for other purposes).
Marking messages as spam or ham
I define two key bindings (in ~/.muttrc:
macro index S "s=learn-as-spam\n" "learn message as spam and delete it"; macro index H "C=learn-as-ham\nsimaps://azul@freaks-unidos.net/INBOX.read\n|~/bin/mutt-from-score >/dev/null\n" "learn message as ham and move it to the read folder";
Last update: 2007-03-01 (Rev 10750)