Homepage of Lars E. Pettersson

Mailserver

After some thought I have decided to build myself a mailserver. The purpose of this server is to give me a consistent way of accessing my mail. So no matter where I am, I should be able to access my mail somehow.

Updates

July 5, 2006 -- Configuring Postfix to use TLS and SMTP AUTH

First make a certificate

mkdir /etc/postfix/tls/
make -C /etc/pki/tls/certs SERIAL=1 /etc/postfix/tls/server.pem

where SERIAL=1 is a unique number, not used before. Then make saslauthd use pam

sed -i s/MECH=.*/MECH=pam/ /etc/sysconfig/saslauthd

Start saslauthd

chkconfig --level 345 saslauthd on
service saslauthd start

Add what methods to use by saslauthd by adding mech_list: plain login to /usr/lib/sasl2/smtpd.conf

echo "mech_list: plain login" >> /usr/lib/sasl2/smtpd.conf

At the end of /etc/postfix/main.cf add

# Where to find the server certificate we generated earlier.
#
# make -C /etc/pki/tls/certs SERIAL=1 /etc/postfix/tls/server.pem
#
smtpd_tls_cert_file = /etc/postfix/tls/server.pem
smtpd_tls_key_file = $smtpd_tls_cert_file

# Note that we do not need to set smtpd_tls_CAfile. In postconf.5 it is
# stated that, "This is needed only when the CA certificate is not
# already present in the server certificate file."

# Enable use of TLS.
#
smtpd_use_tls = yes

# Reduce the time Postfix will sit idle after a client issues STARTTLS.
#
smtpd_starttls_timeout = 60s

# Renegotiate TLS sessions every hour.
#
smtpd_tls_session_cache_timeout = 3600s

# Enable SMTP AUTH.
#
smtpd_sasl_auth_enable = yes

# Don't allow anonymous logins.  DO NOT add noplaintext here, or
# authentication with saslauthd will become impossible.
#
smtpd_sasl_security_options = noanonymous

# Some clients send malformed AUTH commands.
#
broken_sasl_auth_clients = yes

# Only allow AUTH when a TLS session is active, to reduce the
# possibility for password and message body snooping.
#
smtpd_tls_auth_only = yes

At smtpd_recipient_restrictions in /etc/postfix/main.cf add permit_sasl_authenticated

smtpd_recipient_restrictions =
        reject_non_fqdn_recipient
        reject_unknown_recipient_domain
        permit_sasl_authenticated             <------------
        permit_mynetworks
        reject_unauth_destination
        reject_unlisted_recipient
            ... and on it goes ...
July 27, 2004

To get all a bit more compact I exchanged clamassassin with the following procmail snippet (placed in $HOME/.procmailrc)

# ------------------------------------------------------------------------
#
# Idea taken from procmail mailing list:
# From: Dallman Ross
# To: procmail at lists.RWTH-Aachen.DE
# Subject: Procmail and ClamScan
# Date: 21 Jul 2004 14:26:07 +0200
#
# Changed it to to work as clamassassin did.
#
# look for possible viral transporters before calling clamscan
:0
*  9876543210^0  ^Content-Type:.*(attachment|multipart)
*  9876543210^0  ^FROM_MAILER
{
# clamdscan not working as it does not allow streams (-) at the moment.
# CS_OUT=`clamdscan --mbox --no-summary --stdout -`
        CS_OUT=`clamscan --mbox --no-summary --stdout -`
        CS_EXIT = $?
                                                                                
        # look for any clamscan problems ( exit code > 1 )
        :0 fw h
        *          -1^0
        * $  $CS_EXIT^0
        | formail -I "X-Virus-Status: Failed" \
                        -I "X-Virus-Report: clamscan error $CS_EXIT"
                                                                                
        # capture right side of var; isolate virus name
        :0 D
        * CS_OUT ?? : \/.* FOUND$
        * MATCH  ?? ^^\/.* ()
        * MATCH  ?? ^^\/.*[^ ]
        {
#               LOG = "$NL Clamscan identified $MATCH $NL"
                # attach an X-header telling us what matched
                :0 fw h
                | formail -I "X-Virus-Status: Yes" \
                        -I "X-Virus-Report: $MATCH FOUND"
                                                                                
        }
}
# ------------------------------------------------------------------------
June 6, 2004

I have now switched to postfix instead of sendmail. This as postfix is a bit easier to administer, and also because it is said to be more (?) secure. More information on my up-coming postfix page. Stay tuned!

I have not yet moved spamassassin and clamav to be run from postfix. Clamav could be moved without problems, but I like to retain spamassassin in the procmail setup. This as the Bayesian system then works per user, not per mailserver, which, I think, will give better results.

Mailserver components

The mailserver uses a couple of programs; fetchmail, sendmail, procmail, clamav, spamassassin, dovecot, and squirrelmail.

fetchmail
fetches mail from a couple of mail-ISP's that I use.
sendmail
takes care of delivering the mail to the user.
procmail
makes sure that the mail ends up in the correct place, and do some filtering for viruses and spam via clamav and spamassassin.
clamav
scans for MS-Windows viruses (not that they effect Linux, but when accessing the mailserver via a MS-Windows client, it feels better if all viruses have been removed, they are also quite annoying to read on a Linux machine, better get rid of them...)
spamassassin
scans for spam messages.
dovecot
works as the POP3, PO3S, IMAP, and IMAPS server.
squirrelmail
takes care of the webmail system.

fetchmail

For fetchmail I use the ~/.fetchmailrc file. At the moment it looks like this.

# Call procmail directly from fetchmail using:
#options mda "/usr/bin/procmail -d %T"
defaults protocol pop3
nokeep
fetchall
set syslog

#
poll server1.se
username "name@server1.se" password "password1"

#
poll server2.se
username "name2@server2.se" password "password2"

#
poll server3.se proto imap
username "name3" password "password3" ssl folder INBOX,INBOX.spam

sendmail

Default install on Fedora Core 1.

Procmail

Procmail have a couple of important tasks to do.

  1. Deliver incoming mail to the ~/Maildir directory in a maildir format. I.e. a directory consisting of three directories named cur/ new/ and tmp/, where tmp/ is a temporary storage, new/ is for new messages, and cur/ is for read messages. Each message is a separate file. Normally sendmail delivers to /var/spool/$USERNAME in a mbox format, a single file consisting of several mails. Maildir is safer and faster and also what is recommended when running dovecot.
  2. Virus scanning with clamav.
  3. Spam scanning with spamassassin.
  4. Filtering using procmail rules.

If you happen to have old mail in mbox-format you have to transfer these into a maildir format. The tool I used was mb2md, see http://batleth.sapienti-sat.org/projects/mb2md/ for more information.

My ~/.procmailrc looks like this at the moment:

# $HOME/.procmailrc
#
# Version: 27/4-2004
#

# Maildir delivery
#
# (maildir = one file for each message, no locking needed for delivery)
#
# (The following lines are needed as sendmail only can handle mbox delivery.
#  Procmail will take care of the maildir delivery with these lines.)
#
DEFAULT=$HOME/Maildir/
#
# Change to this directory
#
MAILDIR=$DEFAULT

# Logging
#
#VERBOSE=no
LOGFILE=$HOME/.procmail.d/log_`date +%Yw%W`

# Backup
#
# (do not forget to prune this directory with a cron entry...)
#
:0 c
$HOME/.mail/

# ---------------------------------------------
# Check for viruses
#
# Use clamassassin, it is way faster than clamfilter.pl (due to perl?)
#
# $ time /usr/local/bin/clamfilter.pl < testbrev > /dev/null
#
# real    0m0.448s
# user    0m0.380s
# sys     0m0.030s
# $ time /usr/local/bin/clamassassin < testbrev > /dev/null
#
# real    0m0.042s
# user    0m0.010s
# sys     0m0.030s

# From http://www.everysoft.com/clamfilter.html
# Check for viruses
#
#:0fw
#| /usr/local/bin/clamfilter.pl

# From http://drivel.com/clamassassin/
# Check for viruses
#
:0fw
| /usr/local/bin/clamassassin

# Work around procmail bug: any output on stderr will cause the "F" in "From"
# to be dropped.  This will re-add it. Not needed in procmail 3.23pre
#
:0
* ^^rom[ ]
{
  LOG="*** Dropped F off From_ header! Fixing up. "
  
  :0 fhw
  | sed -e '1s/^/F/'
}
# ---------------------------------------------

# ---------------------------------------------
# Pipe the mail through spamc
#
# The condition line ensures that only messages smaller than 250 kB
# (250 * 1024 = 256000 bytes) are processed by SpamAssassin. Most spam
# isn't bigger than a few k and working with big messages can bring
# SpamAssassin to its knees. (This test is probably not needed as
# spamc itself has a size limit of 250k, but testing here is probably
# a bit faster than starting spamc just to bail out from it.)
#
# Ignore messages already consider spam, and mail from the home.rpz domain.
#
:0fw
* < 256000
* !^X-Spam-Status: Yes
* !^X-Spam-Flag: YES
* !^From:.*\.home\.rpz
| /usr/bin/spamc

# The next stanza protects against errors. If spamassassin returns an
# error it is passed back to the mail transfer agent and improves
# robustness of mail delivery.
#
:0e 
{ 
  EXITCODE=$? 
}

# Work around procmail bug: any output on stderr will cause the "F" in "From"
# to be dropped.  This will re-add it. Not needed in procmail 3.23pre
#
:0
* ^^rom[ ]
{
  LOG="*** Dropped F off From_ header! Fixing up. "
  
  :0 fhw
  | sed -e '1s/^/F/'
}

# All mail tagged as spam (eg. with a score higher than the set threshold),
# or as virus, is moved to Junk_viruses, or Junk, JunkJunk, or /dev/null,
# depending on the level of spaminess.
#
:0
* ^X-Spam-Status: Yes|\
        ^X-Spam-Flag: Yes|\
        ^X-Virus-Found: Yes|\
        ^X-Virus-Status: Yes
{
        # Junk the viruses
        #
        :0
        * ^X-Virus-Found: Yes|\
                ^X-Virus-Status: Yes
        .Junk_viruses/

        # Mails with a score of 20 or higher are almost certainly spam
        # (with 0.05% false positives according to rules/STATISTICS.txt).
        # Let's erase them.
        #
        :0 h
        * ^X-Spam-Level: \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
        /dev/null

        # Mails with a score of 15 or higher are almost certainly spam
        # (with 0.05% false positives according to rules/STATISTICS.txt).
        # Let's put them in a different maildir.
        #
        :0
        * ^X-Spam-Level: \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
        .JunkJunk/

        # All mail tagged as spam (eg. with a score higher than the set
        # threshold) is moved to "Junk".
        #
        :0
        .Junk/
}

# ------------------------------------------------------------------------
#
# -- Foreign languages --
#
# http://www.professional.org/procmail/furrin.rc
# http://info.ccone.at/INFO/Mail-Archives/procmail/Feb-2003/msg00544.html
# April 13, 2004 - Lars E. Pettersson
#

# Initialize some variables
#
SPAMVAL=""
SPAMMISHNESS=""
SPAMNOTES=""

INCLUDERC=$HOME/.procmail.d/foreign.rc

# Lastly, emit collected spam notes and if spam, toss it.
# any actual spam will have defined a spamnotes line.

:0
* ! SPAMNOTES ?? ^^^^
{
         LOG="${SPAMNOTES}${SPAMVER}"
}

:0
* ISSPAM ?? ^^(1|yes)^^
.Junk/

# ------------------------------------------------------------------------

# ------------------------------------------------------------------------
#
# -- Mailing lists --
#
# http://www.professional.org/procmail/listname_id.rc
# http://article.gmane.org/gmane.mail.procmail/10021
# March 12, 2004 - Lars E. Pettersson
#

INCLUDERC=$HOME/.procmail.d/listname_id.rc

:0
* ! LISTNAME ?? ^^^^
.lists.$LISTNAME/

# ------------------------------------------------------------------------

# Everything not processed yet goes into to the normal inbox

My intention is to move the MAILDIR and DEFAULT part to the /etc/procmailrc file so that all users get a ~/Maildir folder (so that dovecot and squirrelmail works without problems.)

Notice the file naming convention used. To get mail into the maildir folder $MATCH, beeing a subfolder to the folder lists, we need to call it ".lists.$MATCH/". Here the dots are needed for the IMAP server, and the trailing dash to deliver to a maildir directory. If you forget the trailing dash the mail will be placed in a mbox-file, that the IMAP-server can not handle. If you forget the dots, the IMAP-server may have problems accessing your mails.

clamav

You can find clamav from http://www.clamav.net/. I am using the crash-hat yum repository from http://crash.fce.vutbr.cz/yum-repository.html to always have the latest version of the program. I did not change anything in the clamav-package. Make sure that the clamd and freshclam daemons are started with each reboot (using ntsysv or equivalent.)

To run clamdscan from procmail you need an extra file setting up temp files etc. There exist a number of these scripts. I first chose clamfilter.pl from http://www.everysoft.com/clamfilter.html but later changed to clamassassin that can be found at http://drivel.com/clamassassin/. The reason for the change was that clamassassin was way faster than clamfilter (around ten times faster due to not having to start perl.) I placed the script in /usr/local/bin, changed clamscan to clamdscan to use the clamd server, and changed some paths to point to the correct directory. For some reason I also had to change the call to clamdscan into

cat ${MSGTMP} | ${CLAMSCAN} --disable-summary --stdout --mbox - > ${LOGTMP} \
  2> /dev/null

spamassassin

I am here using the spamassassin package from Fedora without any alterations.

I had razor and pyzor activated for a while, but stopped using them due to the extra time for scanning that they produced and that the number of positive spams found was very low. I have not yet tried dcc.

dovecot

This is also a package from Fedora. In the configuration file, /etc/dovecot.conf, I added the protocols I wanted to serve to the protocols line. I set up the *_listen lines so that I only have the secure variants of POP and IMAP from my Internet interface, and both secure, and non-secure variants on the LAN. I also changed the default mail environment into "default_mail_env = maildir:~/Maildir" (this is actually not needed.)

squirrelmail

Squirrelmail comes from Fedora. To interface it with dovecot I changed a couple of things in /etc/squirrelmail/config.php:

$imap_server_type       = 'courier';
$optional_delimiter     = '.';
$default_folder_prefix  = '';

You may now access your mail via the webmail. To be on the safe side, use only secure http.