Projects‎ > ‎

Courier Mail Server Setup

posted Dec 19, 2009, 9:55 AM by Philip Saxton   [ updated Nov 16, 2011, 7:16 PM ]

This document attempts to describe the process for setting up a full featured mail server using Debian GNU/Linux 5.0 (Lenny) and the Courier mail suite (version 0.60.0-2). Prior to the first section, the OS is a core install with no extra "collections" added. After installation sudo, less, nfs-client, ssh, screen, and mutt packages have been installed. These are not strictly necessary and are mentioned in the interest of full disclosure. The installation procedure is beyond the scope of this document. Courier-base is configured to use configuration directories rather than files as this is required to use the optional web admin module.

Sections "Configure authdaemond," "Setup SMTP" and "Setup POP3 and/or IMAP" are required for a basic mail server setup. Further sections are optional and extend the functionality of the mail server.

Why Courier

There are many different mail suites available for Linux users. There are many more recipes to follow to mangle parts from each of those mail suites together to form a single functional(?) mail server. After struggling through three or four of those recipes, I began to wonder why none of these mail suites were capable of doing what they were intended to, perform the whole gamut of functions desired using a single codebase. I decided to try creating a homologous server with Courier for little more reason than I liked the name and I remember seeing it in a lot of recipes often just used for the IMAP server. If you are looking for me to convince you that Courier is the be all/end all of mail servers, you should probably do some research to decide what fits your requirements. If you are looking to have a single suite to power all of your Internet communications needs that is relatively basic to setup, read on.

While writing this manual, I have found many things I like about Courier. Having a central "authdaemon" makes configuration of the individual modules a breeze and abstracts much of the parts I found confusing in many other recipes. Also, Courier has most of the pieces which other recipes seem to grab from every suite under the sun as standard modules: SMTP (MTA, MSA and MDA), POP3, IMAP, mail lists, calendaring, shared IMAP folders, webmail, webadmin, server side filtering, SSL, LDAP integration, and even a Fax<=>Mail gateway. Often there is little configuration required aside from installation as you can see in the sections below.

Configure authdaemond

authdaemond is the heart of the Courier mail system. It authenticates users for POP3, IMAP, and SMTP auth servers as well as routes mail to the correct box. There are several modules for authdaemond which provide Courier with a wide range of functions. authpam, authuserdb, and authpostgresql will be described in this document.

authdaemond is part of the base package of courier. To install:

# aptitude install courier-base;

authpam

The authpam module is the most basic and allows for mail to be delivered to system accounts. authpam is installed and activated by default. Creating new accounts is done by adding a login account to Debian on the mail system. All domains configured as local will have messages delivered to the corresponding system account. The biggest downside to this is that every mail user must be given a login acount and that different addresses, like jdoe@example.com and jdoe@another.com, are delivered to the same mailbox.

authuserdb

The authuserdb module uses integrated GDBM support to manage a small database of addresses for routing and authentication. The Courier website claims this is sufficient for up to several thousand mailboxes, beyond which a full SQL backed module such as authpostgresql is recommended.

Note: You must configure SMTP to accept and handle virtual mail seperately.

Setting up the authdaemonrc to use authuserdb involves editing the authdaemonrc configuration file and adding authuserdb to the module list. Userdb generates its database from files in the userdb directory. This directory must be root owned and have no group or world permissions. The Courier authdaemond will need to be restarted after this change.

# editor authdaemonrc;                     ## Find and change the following
    authmodulelist="authpam authuserdb"
# mkdir /etc/courier/userdb && chmod 0700 /etc/courier/userdb;
# /etc/init.d/courier-authdaemon restart;

Mailboxes may be added either through a command line utility or by editing the userdb configuration files directly. Once a user has been created, the `home' directory will need to be created and a maildir will need to be setup. Finally, run `makeuserdb' to add the new accounts to the userdb db.

Adding a mailbox from the command line:

# /usr/sbin/userdb example.com/xmpl@example.com \
>   set home=/var/mail/example.com/xmpl uid=1000 gid=1000;
# /usr/sbin/userdbpw -md5 | sudo /usr/sbin/userdb \
>   example.com/xmpl@example.com set systempw;
Password: pw
# mkdir /var/mail/example.com/xmpl;
# /usr/bin/maildirmake /var/mail/example.com/xmpl/Maildir;
# chown -R 1000:1000 /var/mail/example.com/xmpl;
# /usr/sbin/makeuserdb

Note: There is a shell script in "Appendix: Shortcuts" to simplify this process.

And directly editing a configuration files:

# editor userdb/example.com;
     xmpl@example.com systempw=$1$2whRdMzg$mZUtSRQoxXX7lQoJq8eSy/|home=/var/mail/example.com/xmpl|uid=1000|gid=1000
# mkdir /var/mail/example.com/xmpl;
# /usr/bin/maildirmake /var/mail/example.com/xmpl/Maildir;
# chown -R 1000:1000 /var/mail/example.com/xmpl;
# /usr/sbin/makeuserdb;

Note: Each record for userdb MUST occupy one line. The formatting on this document may break the lines, but in operation this will not work.

authpostgresql

The authpostgresql module integrates with the PostgreSQL database server to support many thousands of virtual mail users.

Note: A fully configured and running PostgreSQL instance is assumed.

Information for valid email addresses, their associated passwords and maildir locations is stored in a database table. First, an os user should be created to seperate the mail user database from other information kept in the db. A directory should be created for the courier schemas files to live.

# groupadd courierdb
# useradd -g courierdb courierdb
# mkdir /var/spool/courierdb
# chown courierdb:courierdb /var/spool/courierdb

Next, set up a database and table in Postgre:

# psql -U postgres template1         ## Configure postgres
= create user courierdb;
= create database courierdb with owner courierdb;
= \c courierdb courierdb
> CREATE TABLE mail_users (
     id serial NOT NULL,
     username character varying(64) NOT NULL,
     vhost character varying(64) NOT NULL,
     passwd character varying(64),
     maildir character varying(256),
     alias character varying(32)
 );
> \q;

Finally set up authentication rights for the courierdb user in Postgre.

# editor pg_hba.conf;             ## Add the following to the users list
     local courierdb courierdb        trust

Once the postgre user and password have been setup, courier just needs to be configured to use it.

# editor authdaemonrc;            ## Find and change the following
     authmodulelist="authpgsql"
# /etc/init.d/courier-authdaemon restart;
# editor authpgsqlrc
     PGSQL_HOST             localhost
     PGSQL_PORT             5432
     PGSQL_USERNAME         courierdb
     PGSQL_PASSWORD         # trusted
     PGSQL_DATABASE         courierdb
     PGSQL_USER_TABLE       mail_users
     PGSQL_CLEAR_PWFIELD    passwd
     PGSQL_LOGIN_FIELD      username || '@' || vhost

Setup SMTP

Install `courier-mta'. Configure which domains to accept mail for. Turn off DNS lookups and Ident authentication otherwise mail processing is too slow. Turn on SMTP authentication to allow mail to be sent away from the server. Restart the SMTP module to take the new settings.

# aptitude install courier-mta;
# cd /etc/courier;
# editor locals;
     localhost
     this.host
# editor esmtpacceptmailfor.dir/domains;
     this.host
# /usr/lib/courier/makeacceptmailfor;
# editor esmtpd;                           ## Find and change the following
     TCPDOPTS="-stderrlogger=/usr/sbin/courierlogger -noidentlookup -nodnslookup"
     ESMTPAUTH="LOGIN CRAM-MD5"
# /etc/init.d/courier-mta restart;

Note: `esmtpacceptmailfor.dir/*' contains all domains for which mail is accepted via SMTP. `locals' contains domains for which mail will be handled as system mail.  `hosteddomains/*' (which is discussed in "Configure Virtual Mail") contains domains which are to be handled as virtual. Domains appearing in `estmtpacceptmailfor.dir/*' which are not handled locally or as virtual will be accepted and relayed.

Test mail setup using telnet to send a message:

# telnet hostname 25;
> EHLO testing.example.com
250-hostname Ok.
250-XVERP=Courier
250-XEXDATA...
> MAIL From: <testing@example.com>
250 Ok.
> RCPT To: <localuser@this.host>
250 Ok.
> DATA
354 Ok.
> Date: Jan 1 1979 0:00:00
> From: testing@example.com
> To: localuser@this.host
> Subject: Testing mail delivery
>    
> Testing. Testing. 1, 2, 3.
> .
250 Ok. REALLYLONGMESSAGE.IDINHEX
> QUIT
221 Bye.

Note: `localuser' should be an actual login account on the machine. `this.host' should be a domain configured as local earlier in this step.

After issuing these commands, a message should arrive to localuser in ~/Maildir. Check this with:

localuser$ mutt -f ~/Maildir;

If mail has been received correctly, then the basic SMTP setup is complete.

Configure Virtual Mail

Note: Prior to this step you MUST have "Setup SMTP" and configured an authdaemond module capable of virtual mailboxes such as authuserdb or authpostgresql.

There are only two steps to setting up virtual mail. First, define the domains to handle as virtual mail. Next, define the addresses for those domains as found in the appropriate auth module section.

Define the domains by creating a file under the hosted domains directory and list each domain on a separate line. Don't forget that these domains must also be added to the `esmtpdacceptmailfor.dir/*' file for the smtp server to accept mail to these domains. Then, run `makehosteddomains' to compile the list into the hosteddomains.dat file.

# cd /etc/courier;
# editor esmtpdacceptmailfor.dir/domains
     example.com
     anotherexample.com
     .allsubdomains.com
# /usr/lib/courier/makeacceptmailfor;
# editor hosteddomains/domains;
     example.com
     anotherexample.com
     .allsubdomains.com
# /usr/lib/courier/makehosteddomains;

Once again, test the new setup with telnet as in the previous step and verify that mail is being properly delivered to virtual accounts.

Setup POP3 and/or IMAP

Install the courier-pop and courier-imap packages:

# aptitude install courier-pop courier-imap;

Done. Test POP3 using telnet as shown below.

# telnet hostname 110
+OK Hello there.
> USER xmpl@example.com
+OK Password required.
> PASS pw
+OK logged in.

And to test IMAP:

# telnet hostname 143
* OK [CAPABILITY IMAP4rev1 UIDPLUS CHILDREN NAMESPACE THREAD=ORDEREDSUBJECT THREAD=REFERENCES SORT QUOTA IDLE ACL ACL2=UNION] Courier-IMAP ready. Copyright 1998-2008 Double Precision, Inc.  See COPYING for distribution information.
> 100 LOGIN axmpl@anotherexample.com pw
100 OK LOGIN Ok.

Note: For more information on interacting with servers through telnet, check out the latest RFCs defining the protocols: SMTP - RFC 2821, POP3 - RFC 1939, IMAP - RFC 3501.

Option: Installing maildrop

maildrop is a mail delivery agent which allows global and per-user filtering of messages. Users can place custom filtering rules in their home directory in a file called `.mailfilter'. This program is also useful to efficiently interface the Courier SMTP process with spam and virus filtering such as SpamAssassin and ClamAV. To install and set Courier to use maildrop:

# aptitude install courier-maildrop;
# editor /etc/courier/courierd             ## Find and change the following
     DEFAULTDELIVERY="| /usr/bin/maildrop"
# editor /etc/courier/maildroprc;                      ## Add the following
     /Received: from .* id\s+(.*)/:h
     MESSAGE_ID=$MATCH1
     SYSLOG="logger -i -p mail.info -t maildrop -- $MESSAGE_ID"
     `$SYSLOG maildrop started`
# /etc/init.d/courier-mta restart;

Note: Mind the positioning of curly braces ({ and }) in maildroprc. Maildrop considers their placement to be syntax. See `man maildropfilter' for more info.

Note: When "syntax errors" are seen in the logs for maildrop, running `echo | maildrop -V 9` will generally lead to the solution.

Option: Integrating With SpamAssassin

Note: "Installing maildrop" is required before this option can be performed.

SpamAssassin must be installed and configured. Patch spamd to use authdaemon to allow per-mailbox filtering and settings. After SpamAssassin is installed, create the maildrop rules to use it.

# aptitude install spamassassin;
# editor /etc/default/spamassassin;        ## Find and change the following
     ENABLED=1
# cd /usr/share/perl5/Mail/SpamAssassin;
# wget htp://da.andaka.org/dl/AuthCourier.pm;
# vim /usr/sbin/spamd;                     ## Find and change the following
     use Mail::SpamAssassin::Timeout;
     use Mail::SpamAssassin::AuthCourier;
# /etc/init.d/spamassassin start;
# editor /etc/courier/maildroprc;                      ## Add the following
     import USER
     xfilter "spamc -u $USER"
     STARS=escape("*********")
     if (/^X-Spam-Level:.*$STARS.*/:h )
     {
       `$SYSLOG message rejected by SpamAssassin`
       exit
     }

Option: Integrating With ClamAV

Note: "Installing maildrop" is required before this option can be performed.

Install clamav. Copy the clampipe script from the documentation and change it to use reformail instead of formail. After setting up clamav, add an xfilter in maildrop to scan messages prior to accepting.

# aptitude install clamav;
# cp /usr/share/doc/clamav/examples/clampipe /usr/bin
# chmod +x /usr/bin/clampipe
# vim /usr/bin/clampipe                    ## Find and change the following
    open (FORMAIL, "|reformail -i 'X-Virii-Status: $status'")
# editor /etc/courier/maildroprc;                      ## Add the following
     xfilter "clampipe"
     if (/^X-Virii-Status: yes/:h)
     {
       `$SYSLOG message rejected by ClamAV`
       exit
     }

Option: Using SqWebMail

Very little official documentation is available regarding deployment of SqWebMail (see http://www.courier-mta.org/sqwebmail/).

First try: Install sqwebmail

# aptitude install sqwebmail

This seems to install apache2 and mysql. We will look at our options, because we want PostgresQL rather than MySQL and apache on a second machine. Most likely this means that we will be sharing our mailbox store via nfs. The test VM is too weak to be running mail and web daemons simultaneously, and we have plans for a stand-alone web server already.

Appendix: Shortcuts

authuserdb

addmailbox - shell script to add email users when using authuserdb:

#!/bin/sh
# Uses userdb to add an email address to authuserdb. Creates and sets the
# permissions for the home folder and Maildir.
# Contributed by DaeGlo <daeglo@daeglo.com>
SPOOL="/var/mail/virt"
if [ $# -eq 2 ] && [ $(id -u) -eq "0" ]; then
    USER=${1}
    DOM=${2}
    EMAIL=${1}\@${2}
      echo "Adding email address \"${EMAIL}\"";
      /usr/sbin/userdb ${DOM}/${EMAIL} set home=${SPOOL}/${DOM}/${USER} \
        uid=5000 gid=5000;
      /usr/sbin/userdbpw -md5 | /usr/sbin/userdb ${DOM}/${EMAIL} set systempw;
      mkdir -p ${SPOOL}/${DOM}/${USER};
      /usr/bin/maildirmake ${SPOOL}/${DOM}/${USER}/Maildir;
      chown -R 5000:5000 ${SPOOL}/${DOM}/${USER};
      /usr/sbin/makeuserdb;
else
    echo "Usage: $0 name domain
        where name@domain is the email address to add.
        Note: This script must be run as root.  ";
fi;

clamav

clampipe - perl script to use clamscan as a pipe which is required for maildrop

#!/usr/bin/perl
# Filters mail through clamav. Intented to be used as a maildrop xfilter,
# So it takes care to exit 0 on success, and nonzero on error. Adds a
# X-Virii-Status header.
# Contributed by Joey Hess <joeyh@debian.org> to be used with procmail
# Modified by DaeGlo <daeglo@daeglo.com> to NOT be used with procmail ;)
use strict;
use warnings;

$/=undef;
my $msg=<>;

open (CLAM, "| clamscan --quiet -")
        || die "cannot run clamscan: $!";
# The --mbox support is flakey and requires a From header as in a real
# mbox.
print CLAM "From foo\n";
print CLAM $msg;
close CLAM;
# Returns status of 1 for virii.
my $status= ($? >> 8 == 1) ? "yes" : "no";

open (FORMAIL, "|reformail -i 'X-Virii-Status: $status'")
        || die "cannot run reformail: $!!";
print FORMAIL $msg
        || die "cannot write to reformail: $!";
close FORMAIL
        || die "reformail failed: $!";

exit 0;

Appendix: Sources

Comments