Gentoo Wiki


Complete Virtual Mail Server

Getting Started

Basic Mail Setup

Enhanced Mail Services

Anti-Spam Configuration

Anti-Virus Configuration

Log Analyzer

Wrapping it Up


Courier-imap and Authentication Services

Courier-imap will be used to provide both IMAP and POP3 services. To start with, we will only setup the basic services and deal with enhancements like SSL and SMTP authentication after the basics work. Many will not be interested in IMAP as most mail servers will only offer POP3 services (connect, get your mail and get off) but I have included both for sake of completeness.

IMAP however has some neat advantages. Basically you keep all your messages on the server. When you 'check' your mail, you read them while it is on the server. This has the great advantage that if you say have 2 systems, both accessing the same mailbox (maybe at work and at home) you'll be accessing the same mailbox. Never have the problem that you 'forgot' an e-mail at home or such. (firewall setups etc are of course a limitation). Also, generally webmail likes IMAP. And thus, using IMAP for your mailbox allows you to have your e-mail handy even without an email client.

This all of course comes at a price. Primarly, disk space on your server. If you have lots of mailboxes, all those e-mails will be stored for a long time (if you don't use really really small quota's but we gotta keep up with at least gmail right? ;). It will be easier however to archive (backup) all e-mail however. Where you really be paying however is bandwidth. Pop will use bandwith for a message once, since it's gone from the server. With IMAP, theoretically, everytime you view a message it has to be retrieved. Luckly Mozilla Thunderbird (and Suite) can do some fancy caching for you there. Speed-wise, it won't really be a problem to have IMAP. As long as there aren't big attachments, even modem connections work extremly well. You do need spam filters however server side. If you get all those big spam messages, with big attachments, your client might wanna scan it for it's on Junk filter (like thunderbird can) and then, it'll want to open all those nasty big messages, using up all your precious bandwidth.

Basic Installation

Start by emerging courier-imap and courier-authlib onto your mail server.

Code: emerging courier-imap
  # emerge courier-imap courier-authlib

Note: Courier-imap uses courier-authlib for authentication. As you will see in the next section about SMTP authentication postfix cannot talk directly with authlib and will use cyrus-sasl to provide the authentication services. Sasl can either use postgres directly as source or go through authlib. For a clearer picture of this see the next section.

Important to realize here is that:

a. courier-imap/pop3 and postfix are different servers providing different services

b. courier-imap is for retrieving stored email on a server (as is pop3)

c. postfix-smtp is for sending (and/or relaying) email

To make things easier for your users, it may be best to let them log in with a username instead of an email address, in this case select username for the PGSQL_LOGINFIELD, otherwise you can select email for this option.

We also need to let the authentication module know how it is going to validate passwords via our Postgres database.

File: /etc/courier/authlib/authpgsqlrc
PGSQL_PORT              5432
PGSQL_USERNAME          postfix
// comment out PGSQL_PASSWORD if you used localhost in PGSQL_HOST and you have trust local connections in 
// pg_hba.conf
PGSQL_PASSWORD          $password  

PGSQL_DATABASE          postfix

PGSQL_USER_TABLE        mailbox

// Ensure that PGSQL_CRYPT_PWFIELD is NOT commented and clear IS commented


//ATTENTION: the uid field should return a integer value equal to the unix user
//owner of filesystem directory, if not you will have autentication problems
//with chdir failing to execute
//here you can use any pgsql valid expression for column
//example if you have a unix postfix user with uid 200 running the postfix process
//you can set uid something like this
//PGSQL_UID_FIELD  200 as uid
PGSQL_UID_FIELD         uid

//see note above for uid
PGSQL_GID_FIELD         gid

PGSQL_LOGIN_FIELD       username

// Note: The username field does not work as the setup describes (with the test data provided)
// this needs to be email.   

PGSQL_HOME_FIELD        homedir

PGSQL_NAME_FIELD        name

//ATTENTION: maildir here should point to an correct path to the maildir folder
//if your system use relative paths or anything you may translate it by
//concating an string  expression
//example if all yours users maildir are located in /var/mailsystem/
//you can set maildir something like this
//PGSQL_MAILDIR_FIELD '/var/mailsystem/' || maildir as maildir


Authdaemond now needs to be linked to the postgres authentication module using the authmodulelist parameter. I commented out the existing definition and added a new one that pointed exclusively to the authpgsql module that we just configured.

File: /etc/courier/authlib/authdaemonrc
##NAME: authmodulelist:2
# The authentication modules that are linked into authdaemond.  The
# default list is installed.  You may selectively disable modules
# simply by removing them from the following list.  The available
# modules you can use are: authuserdb authpam authshadow authpgsql 
# authcustom

#authmodulelist="authpgsql authpam authuserdb authshadow authcustom"

Note: If isn't being built, even though you emerged courier-authlib with the 'postgres' USE flag, verify that you DO NOT have vpopmail installed. If vpopmail is installed, the courier-authlib ebuild will not build the MySQL or PostgreSQL auth modules.


The easiest and quickest way to test if authdaemond is working right is by using the authtest program that comes with it. Just run authtest followed by a username in your database and see what comes out, e.g.:

Code: Testing using authtest
# authtest username
Authentication succeeded.

     Authenticated: username  (uid 1000, gid 1000)
    Home Directory: /home/vmail/
             Quota: 10240
Encrypted Password: $1$16117118$ajxN3QRilmP5zLVHjTkE31
Cleartext Password: (none)
           Options: (none)

Another testing methodology is by using telnet. I started by making a telnet connection and confirming that I could log the user in. If you inserted the data I had above, then your password is set to “secret”. We will be testing both POP3 and IMAP so make sure both servers are running.

Tip: If you have trouble with this test when courier can't locate the maildir (probably because you skipped the postfixadmin-part), you don't need to create a maildir manually in /home/vmail. Simply send your a mail and everything should be working.

Tip: You may want to recheck the homedir in the database: '/home/vmail/' instead of '/home/vmail'. The trailing '/' is required!

Tip: Don't forget to execute "authdaemond stop" and "authdaemond start" if you changed something in the authentication configuration.

FIXME: In the mailbox table, the maildir field must also contain the ".maildir/" folder tacked onto the end: for example, "". 06:33, 1 November 2006 (UTC)

<- This is not required, but the maildair field should not be empty and also end with a '/' and it is probably a good idea to make these unique.

You will also need to go and check your /etc/courier-imap/pop3d & imapd and edit the last few lines (which are incorrect)

Shell: Edit /etc/courier-imap/pop3d & imapd
# MAILDIRPATH - directory name of the maildir directory.

MAILDIRPATH=.maildir   <--- change this line

#Hardwire a value for ${MAILDIR}

Shell: Starting POP3/IMAP Services
# /etc/init.d/courier-pop3d start
 * Starting courier-pop3d...                                     [ ok ]
# /etc/init.d/courier-imapd start
 * Starting courier-imapd...                                     [ ok ]

For initial testing, I used telnet to verify that I was able to login. I ran into a number of problems at this point, so found using telnet much easier and faster than using a mail client.

Shell: Testing
# telnet 110

+OK Hello there.
user username
+OK Password required
Pass secret
+OK logged in

If you have something that looks like the above, then you have successfully logged in to the POP3 service.

Note: If your PGSQL_LOGIN_FIELD is set to email, you will need to log in as in stead of username in reference to the example data in the database

Changing Logging Levels

Some of the problems I ran into at this point were incorrectly encoded passwords, inability to read the homedir, etc. To assist in diagnosing these problems, I found increasing the log levels in authdaemonrc and pop3d was key to getting the right information.

File: /etc/courier/authlib/authdaemonrc
# Dump additional diagnostics to syslog
# DEBUG_LOGIN=0   - turn off debugging
# DEBUG_LOGIN=1   - turn on debugging
# DEBUG_LOGIN=2   - turn on debugging + log passwords too
# ** YES ** - DEBUG_LOGIN=2 places passwords into syslog.
# Note that most information is sent to syslog at level 'debug', so
# you may need to modify your /etc/syslog.conf to be able to see it.


File: /etc/courier-imap/pop3d

These settings will put debug level information in the /var/log/messages file. Just be sure not to forget to return them to 0 when you get things running.

Once the telnet test passed, I used MS Outlook to define both an IMAP and POP3 account and confirm that I was able to log into the mail server and send/receive messages. We now have a mail server with POP3 and IMAP services utilizing encrypted passwords.

Generating Passwords

The following will help you generate encoded passwords that are compatible with the courier-imap algorithm. Just pop your password in the $clearpass variable, dump this file as a .php into your web servers .htdocs directory and point your browser at it to get the encrypted result. // Notice: This is exactly what $CONF['encrypt'] = md5crypt; does in postfixadmin

Code: Encrypting Passwords
 function randltr() {
   $retval = 'a';
   $rand = rand() % 64;
   if ($rand < 26) $retval = $rand + 'a';
   if ($rand > 25) $retval = $rand - 26 + 'A';
   if ($rand > 51) $retval = $rand - 52 + '0';
   if ($rand == 62) $retval = ';';
   if ($rand == 63) $retval = '.';

 function mkpasswd3(&$clearpass, &$crypted) {
   srand ((double)microtime()*1000000);

   $salt = '$1$';
   for ($i = 0; $i < 5; $i++) $salt .= randltr();
   $salt .= '0';

   $crypted = crypt($clearpass, $salt);

   if (strlen($crypted) > 0) return(true);

 $clearpass = 'secret';
 $crypted = '';

 if (mkpasswd3($clearpass, $crypted)) printf("%s -> %s\n", $clearpass, $crypted);
 else echo("Ohoh");

The same is available as handy command line tool:

Code: Encrypting Passwords as command line tool
 // This version requires php to have been build with the CLI option (cli use 
 // flag). Simply put it somewhere in your path as md5crypt or md5pass and make
 // it executable.
 // You can pipe a cleartext password into the program and it will output a md5
 // hashed version. (Don't just use echo as it adds a newline!)
 // $ printf "secret" | md5pass
 // $1$71914186$nqzUppxptM9u.JF4V0qyw0
 // If you want a more verbose method similar to the one above, turn on the
 // -v command line option, however, this will break the piping mode.
 $verbose = false;
 $cli_opt_error = false;
 if ( $argc > 1 ) {
   if ( $argc > 2 || $argv[1] != "-v" ) $cli_opt_error = true;
   else $verbose = true;

 if ( $cli_opt_error ) {
   fprintf( STDERR, "No or only one argument allowed\n-v : verbose\n\n" );

 function randltr() {
   $retval = 'a';
   $rand = rand() % 64;
   if ($rand < 26) $retval = $rand + 'a';
   if ($rand > 25) $retval = $rand - 26 + 'A';
   if ($rand > 51) $retval = $rand - 52 + '0';
   if ($rand == 62) $retval = ';';
   if ($rand == 63) $retval = '.';

 function mkpasswd3(&$clearpass, &$crypted) {
   srand ((double)microtime()*1000000);

   $salt = '$1$';
   for ($i = 0; $i < 5; $i++) $salt .= randltr();
   $salt .= '0';

   $crypted = crypt($clearpass, $salt);

   if (strlen($crypted) > 0) return(true);

 // In verbose mode ask user to specify a password (breaks piping mode!)
 if ($verbose) fprintf( STDOUT, "Enter plaintext to hash: " );
 fscanf( STDIN, "%s", &$clearpass);
 $crypted = '';

 // In verbose mode be verbose (again, breaks piping mode)
 if ($verbose) printf ("Hashed plaintext '%s' -> ", $clearpass );

 // Write error message to STDERR, se we can see it and it doesn't end up in
 // the database or other inconvenient location.
 if (mkpasswd3($clearpass, $crypted)) printf("%s", $crypted);
 else fprintf( STDERR, "Ohoh, failed to generate hash...\n");

 // In verbose mode, add a newline.
 if ($verbose) printf("\n");

SSL Support

While it is not necessary, supporting an SSL connection to your POP3 and IMAP servers is a pretty good idea and simple to offer. We will start by creating a couple of certificates (assuming you do not want to go out and pay for a set of signed certificates).

We will make the necessary changes to the POP3 and IMAP configuration files and then call the utilities to create the certificates.

Shell: SSL Certificates
# nano -w /etc/courier-imap/pop3d.cnf
# nano -w /etc/courier-imap/imapd.cnf
// Change the C, ST, L, CN, and email parameters to match your server.
// Note that C (country) is a maximum of 2 characters.

# mkpop3dcert
# mkimapdcert


Start the services and you are ready to test.

Shell: SSL POP3/IMAP Services
# /etc/init.d/courier-pop3d-ssl start
* Starting courier-pop3d over SSL...                             [ ok ]

# /etc/init.d/courier-imapd-ssl start
* Starting courier-imapd over SSL...                             [ ok ]

Using Externally Signed Certificates

For those people wanting to use a third party signed certificate, or even a certificate you've had your own CA sign, the above steps will not suffice. It is a fairly easy task, however, to get courier-imap-ssl working with your certificate. You need to combine the certificate, key and DH (diffie-hellman signature) together forming a single pem file and can be located anywhere.

Shell: Combining Certificate, Key, & DH
# cat mail.key mail.crt > mymail.pem
# openssl gendh 1024 >> mymail.pem
# chmod 600 mymail.pem
# chown root:root mymail.pem

This is to cryptic, a few more thing would be more helpfull, maybe with an example obtaining and using a cacert cert.

The last step is to edit the /etc/courier-imap/imapd-ssl file and change the path to the appropriate location, and if you have a chained certificate, add the path in TLS_TRUSTCERTS :

Shell: nano -w /etc/courier-imap/imapd-ssl
# TLS_CERTFILE - certificate to use.  TLS_CERTFILE is required for SSL/TLS
# servers, and is optional for SSL/TLS clients.  TLS_CERTFILE is usually
# treated as confidential, and must not be world-readable.

# TLS_TRUSTCERTS=pathname - load trusted certificates from pathname.
# pathname can be a file or a directory. If a file, the file should
# contain a list of trusted certificates, in PEM format. If a
# directory, the directory should contain the trusted certificates,  
# in PEM format, one per file and hashed using OpenSSL's c_rehash
# script. TLS_TRUSTCERTS is used by SSL/TLS clients (by specifying
# the -domain option) and by SSL/TLS servers (TLS_VERIFYPEER is set


You can test the setup using Mozilla-Thunderbird or another email client of your choice. To test at this point, I simply fired up outlook and used it to setup secure POP3 and IMAP accounts. Ensure you can connect with both accounts and send/receive mail (this is where a second email account becomes really handy).

Tip: Some email clients are not complete in the TLS implementation, to help these clients out you can change the value of TLS_STARTTLS_PROTOCOL in /etc/courier-imap/imapd-ssl from TLS1 to SSL3
Retrieved from ""

Last modified: Fri, 03 Oct 2008 11:03:00 +0000 Hits: 24,149