28
2010
Creating a Mail Server on Ubuntu (Postfix, Courier, SSL/TLS, SpamAssassin, ClamAV, Amavis)
Note: this has been tested to work on the following versions of Ubuntu:
- Ubuntu 11.04
- Ubuntu 10.04
- Ubuntu 9.04
One of the most fragile and fragmented services I’ve had to configure on Ubuntu is a mail server. No matter which of the many guides I follow, each time I do it there’s always something not working.
This one is mostly for my benefit, but hopefully it’ll be useful to others, too. I’ve tried to make the guide easy to follow and as short as possible. Please comment if something isn’t clear.
Before we start, I have to give a huge amount of credit to Ivar Abrahamsen for his guide which is, by far, one of the best ones out there.
So let’s kick off…
We’ll be building a mail server made up of the following components:
- Postfix is the mail transfer agent (MTA) responsible for accepting new messages and storing them on your server as well as allowing authorised users to send e-mail.
- Courier sits in front of Postfix and provides an IMAP and POP3 interface for clients to connect to.
- SASL/TLS allows you to authenticate to the mail server securely.
- SpamAssassin will analyse your e-mails as they arrive and will filter out what it thinks is spam.
- ClamAV will scan e-mails for viruses before delivering it to your inbox.
- Amavis ties SpamAssasin and ClamAV together, and is itself hooked into Postfix.
- MySQL will be used to manage user accounts and e-mail forwarding.
Installation
First, switch to the root user unless, of course, you like typing sudo.
sudo su -
Next, make sure you have the required package sources configured in Aptitude.
vi /etc/apt/sources.list
For Ubuntu 10.04 (Lucid), I have the following configured as my repositories:
deb http://gb.archive.ubuntu.com/ubuntu/ lucid main restricted universe deb http://gb.archive.ubuntu.com/ubuntu/ lucid-updates main restricted universe deb http://gb.archive.ubuntu.com/ubuntu/ lucid-security main restricted universe
We’ll install all the software in one go:
apt-get update apt-get install -y mysql-server postfix postfix-mysql libsasl2-modules libsasl2-modules-sql libgsasl7 libauthen-sasl-cyrus-perl sasl2-bin libpam-mysql clamav-base libclamav6 clamav-daemon clamav-freshclam amavisd-new spamassassin spamc courier-base courier-authdaemon courier-authlib-mysql courier-imap courier-imap-ssl courier-pop courier-pop-ssl courier-ssl
During the installation of MySQL you will be prompted for the root user password, as shown:

Enter a secure password, and don’t forget it!
Similarly, during the installation of Courier you will be presented with the following configuration prompts:

Choose No

Choose OK

Choose Internet Site

Enter your mail server name (e.g. replace example.com with your own domain). Make sure you have this subdomain configured in your DNS records.

Choose OK
Now we’ll configure the mailname on the server. Using the same mailname as you used when configuring Courier, run the following command:
echo mail.example.com > /etc/mailname
I won’t walk you through the parameters we’re using when configuring Postfix as I want to keep this guide light. If you’re interested, you can find more information from the man pages.
mv /etc/postfix/main.cf /etc/postfix/main.cf.default vi /etc/postfix/main.cf
Copy/paste the following (change all instances of mail.example.com):
# See /usr/share/postfix/main.cf.dist for a commented, more complete version
myorigin = /etc/mailname
smtpd_banner = $myhostname ESMTP $mail_name
biff = no
append_dot_mydomain = no
readme_directory = no
mydestination =
relayhost =
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mynetworks_style = host
mailbox_size_limit = 0
virtual_mailbox_limit = 0
recipient_delimiter = +
inet_interfaces = all
message_size_limit = 0
# Encrypted authentication (SASL)
smtpd_sasl_auth_enable = yes
broken_sasl_auth_clients = yes
smtpd_sasl_security_options = noanonymous
smtpd_sasl_local_domain =
# Encrypted transfer (TLS)
smtpd_use_tls = yes
smtpd_tls_cert_file = /etc/ssl/private/mail.example.com.crt
smtpd_tls_key_file = /etc/ssl/private/mail.example.com.key
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
# Basic SPAM prevention
smtpd_helo_required = yes
smtpd_delay_reject = yes
disable_vrfy_command = yes
smtpd_helo_restrictions = permit_mynetworks, warn_if_reject reject_non_fqdn_hostname, reject_invalid_hostname, permit
smtpd_sender_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_non_fqdn_sender, reject_unknown_sender_domain, reject_unauth_pipelining, permit
smtpd_client_restrictions = reject_rbl_client sbl.spamhaus.org, reject_rbl_client blackholes.easynet.nl, reject_rbl_client dnsbl.njabl.org
smtpd_recipient_restrictions = reject_unauth_pipelining, permit_mynetworks, permit_sasl_authenticated, reject_non_fqdn_recipient, reject_unauth_destination, permit
smtpd_data_restrictions = reject_unauth_pipelining
# Force incoming mail to go through Amavis
content_filter = amavis:[127.0.0.1]:10024
receive_override_options = no_address_mappings
# Virtual user mappings
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
virtual_mailbox_base = /var/spool/mail/virtual
virtual_mailbox_maps = mysql:/etc/postfix/maps/user.cf
virtual_mailbox_limit_maps = mysql:/etc/postfix/maps/limit.cf
virtual_mailbox_limit_override = yes
virtual_maildir_limit_message = "The user you are trying to reach has a full inbox. Please try again at another time."
virtual_overquota_bounce = yes
virtual_uid_maps = static:5000
virtual_gid_maps = static:5000
virtual_alias_maps = mysql:/etc/postfix/maps/alias.cf
virtual_mailbox_domains = mysql:/etc/postfix/maps/domain.cfmv /etc/postfix/master.cf /etc/postfix/master.cf.default vi /etc/postfix/master.cf
Copy/paste the following (no changes required):
#
# Postfix master process configuration file. For details on the format
# of the file, see the master(5) manual page (command: "man 5 master").
#
# Do not forget to execute "postfix reload" after editing this file.
#
# ==========================================================================
# service type private unpriv chroot wakeup maxproc command + args
# (yes) (yes) (yes) (never) (100)
# ==========================================================================
smtp inet n - - - - smtpd
smtps inet n - - - - smtpd
-o smtpd_tls_wrappermode=yes
-o smtpd_sasl_auth_enable=yes
pickup fifo n - - 60 1 pickup
-o content_filter=
-o receive_override_options=no_header_body_checks
cleanup unix n - - - 0 cleanup
qmgr fifo n - n 300 1 qmgr
tlsmgr unix - - - 1000? 1 tlsmgr
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
proxywrite unix - - n - 1 proxymap
smtp unix - - - - - smtp
relay unix - - - - - smtp
-o smtp_fallback_relay=
showq unix n - - - - showq
error unix - - - - - error
retry unix - - - - - error
discard unix - - - - - discard
local unix - n n - - local
virtual unix - n n - - virtual
lmtp unix - - - - - lmtp
anvil unix - - - - 1 anvil
scache unix - - - - 1 scache
maildrop unix - n n - - pipe
flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
uucp unix - n n - - pipe
flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
ifmail unix - n n - - pipe
flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
bsmtp unix - n n - - pipe
flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient
scalemail-backend unix - n n - 2 pipe
flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension}
mailman unix - n n - - pipe
flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py
${nexthop} ${user}
amavis unix - - - - 2 smtp
-o smtp_data_done_timeout=1200
-o smtp_send_xforward_command=yes
-o disable_dns_lookups=yes
-o max_use=20
127.0.0.1:10025 inet n - - - - smtpd
-o content_filter=
-o local_recipient_maps=
-o relay_recipient_maps=
-o smtpd_restriction_classes=
-o smtpd_delay_reject=no
-o smtpd_client_restrictions=permit_mynetworks,reject
-o smtpd_helo_restrictions=
-o smtpd_sender_restrictions=
-o smtpd_recipient_restrictions=permit_mynetworks,reject
-o smtpd_data_restrictions=reject_unauth_pipelining
-o smtpd_end_of_data_restrictions=
-o mynetworks=127.0.0.0/8
-o smtpd_error_sleep_time=0
-o smtpd_soft_error_limit=1001
-o smtpd_hard_error_limit=1000
-o smtpd_client_connection_count_limit=0
-o smtpd_client_connection_rate_limit=0
-o receive_override_options=no_header_body_checks,no_unknown_recipient_checksAs all our mail users are going to be virtual (i.e. we’re not going to create physical user accounts for each user), we only need to create one mail directory and one user account.
groupadd virtual -g 5000 useradd -r -g "virtual" -G "users" -c "Virtual User" -u 5000 virtual mkdir /var/spool/mail/virtual chown virtual:virtual /var/spool/mail/virtual
Make sure that, if the UID or GID differs from 5000, you update the virtual_uid_maps and virtual_gid_maps values in /etc/postfix/main.cf, and MYSQL_UID_FIELD and MYSQL_GID_FIELD in /etc/courier/authmysqlrc (later in this guide).
Now we’ll create the database which will store the mail user configuration and forwarding rules.
mysql -uroot -p
Enter the password you created during the MySQL installation.
Copy/paste the following (change mailuserpassword, example.com and change the admin’s password to something more secure):
CREATE DATABASE mail; GRANT ALL ON mail.* TO mail@localhost IDENTIFIED BY 'mailuserpassword'; FLUSH PRIVILEGES; USE mail; CREATE TABLE IF NOT EXISTS `alias` ( `source` varchar(255) NOT NULL, `destination` varchar(255) NOT NULL default '', `enabled` tinyint(1) unsigned NOT NULL default '1', PRIMARY KEY (`source`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `domain` ( `domain` varchar(255) NOT NULL default '', `transport` varchar(255) NOT NULL default 'virtual:', `enabled` tinyint(1) unsigned NOT NULL default '1', PRIMARY KEY (`domain`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `user` ( `email` varchar(255) NOT NULL default '', `password` varchar(255) NOT NULL default '', `name` varchar(255) default '', `quota` varchar(255) default NULL, `enabled` tinyint(1) unsigned NOT NULL default '1', PRIMARY KEY (`email`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; INSERT INTO `alias` (`source`, `destination`, `enabled`) VALUES ('@localhost', 'admin@example.com', 1); INSERT INTO `alias` (`source`, `destination`, `enabled`) VALUES ('@localhost.localdomain', '@localhost', 1); INSERT INTO `domain` (`domain`, `transport`, `enabled`) VALUES ('localhost', 'virtual:', 1); INSERT INTO `domain` (`domain`, `transport`, `enabled`) VALUES ('localhost.localdomain', 'virtual:', 1); INSERT INTO `domain` (`domain`, `transport`, `enabled`) VALUES ('example.com', 'virtual:', 1); INSERT INTO `user` (`email`, `password`, `name`, `quota`, `enabled`) VALUES ('admin@example.com', ENCRYPT('changeme'), 'Administrator', NULL, 1);
Note that we’re encrypting the password. Some guides will recommend storing the password in clear text so that you can configure Postfix to support CRAM-* (e.g. CRAM-MD5) authentication methods. I think it’s much more secure to store these passwords encrypted and use SSL/TLS to encrypt your authentication requests. For that reason, we don’t need to store clear text passwords and we don’t need to provide CRAM-* support.
Now that the database is in place we can create the map files to tell Postfix how to communicate with it.
mkdir /etc/postfix/maps vi /etc/postfix/maps/alias.cf
Copy/paste the following (change mailuserpassword):
user=mail password=mailuserpassword dbname=mail table=alias select_field=destination where_field=source hosts=127.0.0.1 additional_conditions=and enabled = 1
vi /etc/postfix/maps/domain.cf
Copy/paste the following (change mailuserpassword):
user = mail password = mailuserpassword dbname = mail table = domain select_field = domain where_field = domain hosts = 127.0.0.1 additional_conditions = and enabled = 1
vi /etc/postfix/maps/limit.cf
Copy/paste the following (change mailuserpassword):
user = mail password = mailuserpassword dbname = mail table = user select_field = quota where_field = email hosts = 127.0.0.1
vi /etc/postfix/maps/user.cf
Copy/paste the following (change mailuserpassword):
user = mail password = mailuserpassword dbname = mail table = user select_field = CONCAT(SUBSTRING_INDEX(email,'@',-1),'/',SUBSTRING_INDEX(email,'@',1),'/') where_field = email hosts = 127.0.0.1 additional_conditions = and enabled = 1
Set restrictive read permissions as these files contain the MySQL mail user’s password.
chmod 700 /etc/postfix/maps/* chown postfix:postfix /etc/postfix/maps/*
The final part of configuring Postfix is to configure the authentication mechanism. SASL is a authentication layer that provides the ability to receive a user’s credentials in a variety of formats. In our case, we’ll be receiving credentials in PLAIN format (i.e. clear text). So, let’s configure SASL.
mkdir -p /var/spool/postfix/var/run/saslauthd mkdir /etc/postfix/sasl adduser postfix sasl vi /etc/postfix/sasl/smtpd.conf
Copy/paste the following (change mailuserpassword):
pwcheck_method: saslauthd auxprop_plugin: sql mech_list: plain login sql_engine: mysql sql_hostnames: 127.0.0.1 sql_user: mail sql_passwd: mailuserpassword sql_database: mail sql_select: SELECT password FROM user WHERE email='%u@%r' AND enabled = 1
chmod -R 700 /etc/postfix/sasl/smtpd.conf mv /etc/default/saslauthd /etc/default/saslauthd.default vi /etc/default/saslauthd
Copy/paste the following (no changes required):
# # Settings for saslauthd daemon # Please read /usr/share/doc/sasl2-bin/README.Debian for details. # START=yes DESC="SASL Authentication Daemon" NAME="saslauthd" MECHANISMS="pam" MECH_OPTIONS="" THREADS=5 OPTIONS="-r -c -m /var/spool/postfix/var/run/saslauthd"
mv /etc/pam.d/smtp /etc/pam.d/smtp.default vi /etc/pam.d/smtp
Copy/paste the following (change all instances of mailuserpassword):
#%PAM-1.0 #------------------------------------------------------------------------ # # /etc/pam.d/smtp # # Copyright (c) 2000-2003 Richard Nelson. All Rights Reserved. # Version: 2.0.1 # Time-stamp: <2003/05/06 12:00:00 cowboy> # # PAM configuration file used by SASL to authenticate a PLAIN password. # #------------------------------------------------------------------------ auth required pam_mysql.so user=mail passwd=mailuserpassword host=127.0.0.1 db=mail table=user usercolumn=email passwdcolumn=password crypt=1 account sufficient pam_mysql.so user=mail passwd=mailuserpassword host=127.0.0.1 db=mail table=user usercolumn=email passwdcolumn=password crypt=1
chmod 700 /etc/pam.d/smtp
Now let’s configure Courier.
I like to provide both IMAP and POP3 support, although personally I only use IMAP. In addition, we’ll be provide SSL support for securing authentication requests.
mv /etc/courier/authdaemonrc /etc/courier/authdaemonrc.default vi /etc/courier/authdaemonrc
Copy/paste the following (no changes required):
##VERSION: $Id: authdaemonrc.in,v 1.13 2005/10/05 00:07:32 mrsam Exp $ # # Copyright 2000-2005 Double Precision, Inc. See COPYING for # distribution information. # # authdaemonrc created from authdaemonrc.dist by sysconftool # # Do not alter lines that begin with ##, they are used when upgrading # this configuration. # # This file configures authdaemond, the resident authentication daemon. # # Comments in this file are ignored. Although this file is intended to # be sourced as a shell script, authdaemond parses it manually, so # the acceptable syntax is a bit limited. Multiline variable contents, # with the \ continuation character, are not allowed. Everything must # fit on one line. Do not use any additional whitespace for indentation, # or anything else. authmodulelist="authmysql" authmodulelistorig="authuserdb authpam authpgsql authldap authmysql authcustom authpipe" daemons=5 authdaemonvar=/var/run/courier/authdaemon DEBUG_LOGIN=0 DEFAULTOPTIONS="" LOGGEROPTS=""
mv /etc/courier/authmysqlrc /etc/courier/authmysqlrc.default vi /etc/courier/authmysqlrc
Copy/paste the following (change mailuserpassword):
MYSQL_SERVER localhost MYSQL_USERNAME mail MYSQL_PASSWORD mailuserpassword MYSQL_PORT 0 MYSQL_DATABASE mail MYSQL_USER_TABLE user MYSQL_CRYPT_PWFIELD password MYSQL_UID_FIELD 5000 MYSQL_GID_FIELD 5000 MYSQL_LOGIN_FIELD email MYSQL_HOME_FIELD "/var/spool/mail/virtual" MYSQL_MAILDIR_FIELD CONCAT(SUBSTRING_INDEX(email,'@',-1),'/',SUBSTRING_INDEX(email,'@',1),'/') MYSQL_NAME_FIELD name MYSQL_QUOTA_FIELD quota
mv /etc/courier/imapd /etc/courier/imapd.default vi /etc/courier/imapd
Copy/paste the following (no changes required):
##VERSION: $Id: imapd.dist.in,v 1.41 2008/06/21 16:01:23 mrsam Exp $ # # imapd created from imapd.dist by sysconftool # # Do not alter lines that begin with ##, they are used when upgrading # this configuration. # # Copyright 1998 - 2008 Double Precision, Inc. See COPYING for # distribution information. # # This configuration file sets various options for the Courier-IMAP server # when used with the couriertcpd server. # A lot of the stuff here is documented in the manual page for couriertcpd. # # NOTE - do not use \ to split long variable contents on multiple lines. # This will break the default imapd.rc script, which parses this file. ADDRESS=0 PORT=143 MAXDAEMONS=40 MAXPERIP=20 PIDFILE=/var/run/courier/imapd.pid TCPDOPTS="-nodnslookup -noidentlookup" LOGGEROPTS="-name=imapd" IMAP_CAPABILITY="IMAP4rev1 UIDPLUS CHILDREN NAMESPACE THREAD=ORDEREDSUBJECT THREAD=REFERENCES SORT QUOTA IDLE" IMAP_KEYWORDS=1 IMAP_ACL=1 IMAP_CAPABILITY_ORIG="IMAP4rev1 UIDPLUS CHILDREN NAMESPACE THREAD=ORDEREDSUBJECT THREAD=REFERENCES SORT QUOTA AUTH=CRAM-MD5 AUTH=CRAM-SHA1 AUTH=CRAM-SHA256 IDLE" IMAP_PROXY=0 IMAP_PROXY_FOREIGN=0 IMAP_IDLE_TIMEOUT=60 IMAP_MAILBOX_SANITY_CHECK=1 IMAP_CAPABILITY_TLS="$IMAP_CAPABILITY AUTH=PLAIN" IMAP_CAPABILITY_TLS_ORIG="$IMAP_CAPABILITY_ORIG AUTH=PLAIN" IMAP_DISABLETHREADSORT=0 IMAP_CHECK_ALL_FOLDERS=0 IMAP_OBSOLETE_CLIENT=0 IMAP_UMASK=022 IMAP_ULIMITD=65536 IMAP_USELOCKS=1 IMAP_SHAREDINDEXFILE=/etc/courier/shared/index IMAP_ENHANCEDIDLE=0 IMAP_TRASHFOLDERNAME=Trash IMAP_EMPTYTRASH=Trash:7 IMAP_MOVE_EXPUNGE_TO_TRASH=0 SENDMAIL=/usr/sbin/sendmail HEADERFROM=X-IMAP-Sender IMAPDSTART=YES MAILDIRPATH=Maildir
mv /etc/courier/imapd-ssl /etc/courier/imapd-ssl.default vi /etc/courier/imapd-ssl
Copy/paste the following (change mail.example.com):
##VERSION: $Id: imapd-ssl.dist.in,v 1.22 2009/08/12 22:25:49 mrsam Exp $ # # imapd-ssl created from imapd-ssl.dist by sysconftool # # Do not alter lines that begin with ##, they are used when upgrading # this configuration. # # Copyright 2000 - 2008 Double Precision, Inc. See COPYING for # distribution information. # # This configuration file sets various options for the Courier-IMAP server # when used to handle SSL IMAP connections. # # SSL and non-SSL connections are handled by a dedicated instance of the # couriertcpd daemon. If you are accepting both SSL and non-SSL IMAP # connections, you will start two instances of couriertcpd, one on the # IMAP port 143, and another one on the IMAP-SSL port 993. # # Download OpenSSL from http://www.openssl.org/ SSLPORT=993 SSLADDRESS=0 SSLPIDFILE=/var/run/courier/imapd-ssl.pid SSLLOGGEROPTS="-name=imapd-ssl" IMAPDSSLSTART=YES IMAPDSTARTTLS=YES IMAP_TLS_REQUIRED=0 COURIERTLS=/usr/bin/couriertls TLS_KX_LIST=ALL TLS_COMPRESSION=ALL TLS_CERTS=X509 TLS_CERTFILE=/etc/ssl/private/mail.example.com.pem TLS_TRUSTCERTS=/etc/ssl/certs TLS_VERIFYPEER=NONE TLS_CACHEFILE=/var/lib/courier/couriersslcache TLS_CACHESIZE=524288 MAILDIRPATH=Maildir
mv /etc/courier/pop3d /etc/courier/pop3d.default vi /etc/courier/pop3d
Copy/paste the following (no changes required):
##VERSION: $Id: pop3d.dist.in,v 1.16 2005/07/05 12:42:51 mrsam Exp $ # # pop3d created from pop3d.dist by sysconftool # # Do not alter lines that begin with ##, they are used when upgrading # this configuration. # # Copyright 1998 - 2004 Double Precision, Inc. See COPYING for # distribution information. # # Courier POP3 daemon configuration PIDFILE=/var/run/courier/pop3d.pid MAXDAEMONS=40 MAXPERIP=4 POP3AUTH="LOGIN" POP3AUTH_ORIG="PLAIN LOGIN CRAM-MD5 CRAM-SHA1 CRAM-SHA256" POP3AUTH_TLS="LOGIN PLAIN" POP3AUTH_TLS_ORIG="LOGIN PLAIN" POP3_PROXY=0 PORT=110 ADDRESS=0 TCPDOPTS="-nodnslookup -noidentlookup" LOGGEROPTS="-name=pop3d" POP3DSTART=YES MAILDIRPATH=Maildir
mv /etc/courier/pop3d-ssl /etc/courier/pop3d-ssl.default vi /etc/courier/pop3d-ssl
Copy/paste the following (change mail.example.com):
##VERSION: $Id: pop3d-ssl.dist.in,v 1.23 2009/08/12 22:25:49 mrsam Exp $ # # pop3d-ssl created from pop3d-ssl.dist by sysconftool # # Do not alter lines that begin with ##, they are used when upgrading # this configuration. # # Copyright 2000-2008 Double Precision, Inc. See COPYING for # distribution information. # # This configuration file sets various options for the Courier-IMAP server # when used to handle SSL POP3 connections. # # SSL and non-SSL connections are handled by a dedicated instance of the # couriertcpd daemon. If you are accepting both SSL and non-SSL POP3 # connections, you will start two instances of couriertcpd, one on the # POP3 port 110, and another one on the POP3-SSL port 995. # # Download OpenSSL from http://www.openssl.org/ SSLPORT=995 SSLADDRESS=0 SSLPIDFILE=/var/run/courier/pop3d-ssl.pid SSLLOGGEROPTS="-name=pop3d-ssl" POP3DSSLSTART=YES POP3_STARTTLS=YES POP3_TLS_REQUIRED=0 COURIERTLS=/usr/bin/couriertls TLS_STARTTLS_PROTOCOL=TLS1 TLS_KX_LIST=ALL TLS_COMPRESSION=ALL TLS_CERTS=X509 TLS_CERTFILE=/etc/ssl/private/mail.example.com.pem TLS_TRUSTCERTS=/etc/ssl/certs TLS_VERIFYPEER=NONE TLS_CACHEFILE=/var/lib/courier/couriersslcache TLS_CACHESIZE=524288 MAILDIRPATH=Maildir
We need to create SSL certificates for Courier to use when authenticating using SSL/TLS. You can either purchase these (to prevent “invalid” certificate warnings) or generate a self-signed certificate which is just as secure, and free.
Run the following (change mail.example.com):
# Remove Courier's default certificates rm -f /etc/courier/imapd.cnf rm -f /etc/courier/imapd.pem rm -f /etc/courier/pop3d.cnf rm -f /etc/courier/pop3d.pem # Generate a new PEM certificate (valid for 10 years) openssl req -x509 -newkey rsa:1024 -keyout "/etc/ssl/private/mail.example.com.pem" -out "/etc/ssl/private/mail.example.com.pem" -nodes -days 3650 chmod 640 "/etc/ssl/private/mail.example.com.pem" chgrp ssl-cert "/etc/ssl/private/mail.example.com.pem" # Generate a new CRT certificate (valid for 10 years) openssl req -new -outform PEM -out "/etc/ssl/private/mail.example.com.crt" -newkey rsa:2048 -nodes -keyout "/etc/ssl/private/mail.example.com.key" -keyform PEM -days 3650 -x509 chmod 640 "/etc/ssl/private/mail.example.com.crt" chmod 640 "/etc/ssl/private/mail.example.com.key" chgrp ssl-cert "/etc/ssl/private/mail.example.com.crt" chgrp ssl-cert "/etc/ssl/private/mail.example.com.key"
You will be prompted to input some information about the certificates you create. You can enter any information you want here except Common Name (CN) which must be your mailname (e.g. mail.example.com).
Next we’ll configure Amavis, the software that ties together SpamAssassin and ClamAV with Postfix.
adduser clamav amavis rm -f /etc/amavis/conf.d/15-content-filter-mode vi /etc/amavis/conf.d/15-content-filter-mode
Copy/paste the following (no changes required):
use strict; @bypass_virus_checks_maps = ( \%bypass_virus_checks, \@bypass_virus_checks_acl, \$bypass_virus_checks_re); @bypass_spam_checks_maps = ( \%bypass_spam_checks, \@bypass_spam_checks_acl, \$bypass_spam_checks_re); 1;
rm -f /etc/amavis/conf.d/50-user vi /etc/amavis/conf.d/50-user
Copy/paste the following (no changes required):
use strict; @local_domains_acl = qw(.); $log_level = 1; $syslog_priority = 'info'; $sa_kill_level_deflt = 6.5; $final_spam_destiny = D_DISCARD; $pax = 'pax'; 1;
mv /etc/default/spamassassin /etc/default/spamassassin.default vi /etc/default/spamassassin
Copy/paste the following (no changes required):
ENABLED=1 OPTIONS="--create-prefs --max-children 5 --helper-home-dir" PIDFILE="/var/run/spamd.pid" CRON=0
dpkg-reconfigure clamav-freshclam

Choose OK

Choose daemon

Choose a mirror closest to you.

Enter your proxy, if required. Usually you will leave this blank.

By default, ClamAV updates every hour. That’s excessive. Bring that down to once a day.

Choose No
Now restart everything.
/etc/init.d/saslauthd restart /etc/init.d/postfix restart /etc/init.d/courier-authdaemon restart /etc/init.d/courier-imap restart /etc/init.d/courier-imap-ssl restart
That’s it, you’re done!
You can test your setup by configuring your mail client to connect to your new mail server using admin@example.com as your username and the password you chose (“changeme” in the guide).
Errors will usually show up in /var/log/mail.log or post any problems you’re having in a comment and I’ll try my best to help.
For more information regarding the mail database, testing using Telnet, and more information regarding how all these services are stitched together, please see Flurdy’s guide.

Hi!
This is works for me. I have one question… How do I add more users?
Hi Kozley,
To add more users (mailboxes), simply add them to the database you created or use SQL to insert them directly.
Some examples…
Adding a new mailbox for helpdesk@example.com with a password of helpme
INSERT INTO `user` (`email`, `password`, `name`, `quota`, `enabled`) VALUES (‘helpdesk@example.com’, ENCRYPT(‘helpme’), ‘Example Helpdesk’, NULL, 1);
Adding support@example.com as an alias for helpdesk@example.com (e-mails sent to support will be forwarded to helpdesk):
INSERT INTO `alias` (`source`, `destination`, `enabled`) VALUES (‘support@example.com’, ‘helpdesk@example.com’, 1);
Adding a new mailbox for a new domain info@examplenewdomain.com:
INSERT INTO `user` (`email`, `password`, `name`, `quota`, `enabled`) VALUES (‘info@examplenewdomain.com’, ENCRYPT(‘helpme’), ‘Example Helpdesk’, NULL, 1);
INSERT INTO `domain` (`domain`, `transport`, `enabled`) VALUES (‘examplenewdomain.com’, ‘virtual:’, 1);
(Note that you need to add the new domain to the `domain` table).
Let me know if you have any more problems.
Gday,
Can you tell me how I I can forward mail using wildcards (if its even possible with this setup)?
E.g. I want something like all mail coming from an email address with ‘twitter.com’ in the address gets forwarded to twitter@mydomain.com
Cheers,
Richard
As far as I know, this isn’t possible without creating some form of content filter.
There may be scripts available to help you get started but I’ve not used anything like that myself.
No worries. Thanks Adam!
please help me .am in greate need
you also
Man, you saved me! Thanks very very very much…
I was trying to configure Postfix with all this stuff since 03/16
Very good article…
1. If i don’t want to use ssl/tls , spamassasin,calmvs and amvis then how will the setting will look like?
2. Is there no need for firewall setting?
Is different system have different gid and uid? If yes how to find them?
Hi Krish,
Sorry for the delay getting back to you. Are you still having problems? I’ll try my best to help you out.
Adam
Yes, Adam
I still have a problem . I’m getting frustated by searching internet and get all that same result.
I use above setting but still am confused why my server is not working.
By the way which user id and password while trying to login to the account created in the database.
Krish
when I try to restart postfix I get the following fail message:
———————————————————————————————————————–
* Stopping Postfix Mail Transport Agent postfix postfix: fatal: /etc/postfix/main.cf, line 74: missing ‘=’ after attribute name: “smtp inet n – – – – smtpd”
[fail]
———————————————————————————————————————–
this is related to the Master Process configuration section above.
——————————————————————————————————
#
# Postfix master process configuration file. For details on the format
# of the file, see the master(5) manual page (command: “man 5 master”).
#
# Do not forget to execute “postfix reload” after editing this file.
#
# ==========================================================================
# service type private unpriv chroot wakeup maxproc command + args
# (yes) (yes) (yes) (never) (100)
# ==========================================================================
smtp inet n – – – – smtpd
——————————————————————————————————————————-
I don’t know why no one else has noticed this.
@rabbel you forget to add # on first line on /etc/postfix/main.cf.
after you changes that and restart postfix the proble should be gone now ;)
and one more question how about squirrelmail, because they use auth plain and cram 5 , can this tutorial working on that.
Thanks sob for great articel.
I actually discovered I had copied configuration details to main.cf instead of to master .cf
When I corrected that. I stopped having the errors I mentioned.
Thanks for getting me to take a fresh look.
hola, I am trying to up a vmware with ubuntu 10.04 desckop mail server but have some problems with the virtual ip and some other configurations, does any one did it with a virtual machine and can say that this really works?
thanks, Joan
2 questions
1 How to I get thunderbird to get my mail. I have
admin for user name
admin@lbermudez.dyndns-free.com for email
used “changeme” and “mailuserpassword” for password
“thunderbird failed to find settings for your email account.” is the error i get.
I have posted more details at
http://ubuntuforums.org/showthread.php?p=11423216
http://www.linuxforums.org/forum/ubuntu-linux/184177-postfix-thunderbird-help.html
2 How do I add new user? I’m using ubuntu 11.10 and I need a step my step this is new for me.
Error here:
mv /etc/courier/imapd /etc/courier/imapd .default
will be:
mv /etc/courier/imapd /etc/courier/imapd.default
Thanks – that’s fixed.
Thanks a bunch. This is a great tutorial and it works. I tried flurdy’s before but didn’t work for me. I’ve found this one much better.
I’ve followed exactly the same configuration as the tutorial with no problems and no errors. Then I’ve sent an email from my gmail account and I can read it when I connect through telnet. I mean (let’s say my server is mail.example.com):
telnet mail.example.com 143 (WORKS OK)
openssl s_client -connect mail.example.com:993 (WORKS OK)
I can login and fetch the email I sent from my gmail account if I telnet to 143 or 993 ports.
Now I’m trying to retrieve my email from Thunderbird 8.0. This is my account config:
Server Name: mail.example.com
Port: 993
Connection security: SSL/TLS
Authentication method: Encrypted password
Then thunderbird says my server does not seem to support encrypted passwords and suggests to change to Normal password. If I do that, then thunderbird says Login Failed and invites me to enter another password.
Can you point me in the right direction? Also, cat /etc/hostname shows the Amazon EC2 private dns. Should I change it to mail.example.com?
Best Regards!
You should set Thunderbird to use “Normal password”, however, your credentials will still be sent encrypted by TLS/SSL to keep them protected.
Have a look in your log files, they’re usually quite verbose so should be able to give you an idea where login is failing. In particular, check out /var/log/mail.err. There is more info in Flurdy’s guide on how to enable more verbose logging for authentication modules if needed. Feel free to paste logs here if you want some more help. Just be careful to remove anything sensitive first.
The hostname in /etc/hostname should not affect your setup and I’d advise you don’t change it. The hostname in /etc/mailname, however, is more important and should be a publicly-resolvable FQDN (i.e. you should be able to ping the hostname from a machine outside the EC2 network).
You could try overriding the hostname just for Postfix by adding the following line to the top of /etc/postfix/main.cf
myhostname = mail.example.com
I doubt, however, that this is the cause of your login problems. Best to have a look at those logs. Good luck!
I reinstalled the whole thing and it still fails in Thunderbird, but if I use Outlook instead, I can get mail from my server and send mail to my server. So it has to be something related to Thunderbird. Weird.
But the big trouble now is when I try to send mail to gmail or hotmail, then I get the error “Relay access denied”.
The /var/log/mail.log file shows
postfix/smtpd[17958]: NOQUEUE: reject: RCPT from : 554 5.7.1 : Relay access denied from= to=” proto=ESMTP helo=
There is nothing related to the problem in /var/log/mail.err
Any ideas?
Thanks a lot.
I see. My machine is a EC2 Amazon instance and it seems there are some issues related to reverse dns and this error.
Thanks again for your tutorial. It’s very good.
Many thanks for this guide. I’ve been struggling to set up a fairly simple mail server for two days on my own, until finally giving up, and after a brief search for help, this post came up.
I’m not sure where I was going wrong, but after a clear out and re-install, and following your instructions, we’re all up and running nicely.
Cheers!
Thanks for your excelent tutorial.
Still, I have one question about what if I need that all users to be “real users”, with physical user accounts attached? (i.e. created by “adduser”)
Is anything I should change/remove?
Thank you verry much!
Have a nice day!
Hi, you have wrote a very good tutorial !
I’ve found that All spam is directly deleted without any warning…even false positive mails…
I’m just trying now to deliver all the spam in the spam-folder for every virtual user, which would be more safe.
Could you please give me any advice for this setup ?
Thanks a lot
Spacio
Hi Spacio,
That’s the behaviour expected using the configuration above. To tweak for your requirements, open up /etc/amavis/conf.d/50-user
Then, add the following line:
$spam_quarantine_to “spam\@mydomain.com”;
You’ll need to make sure that the ‘spam’ mailbox exists, too. Just add a row in the ‘user’ MySQL table.
Note that if a spam_quarantine_to value is provided, using final_spam_destiny = D_DISCARD will prevent the message arriving at the intended destination but a copy will be sent to the spam mailbox. I assume this is the behaviour you’re after.
Good luck!
Adam
Thanks Adam for this extra line of code, saved me hours of work!
[...] En este tutorial se explica de forma completa como preparar un servidor de correo completo con antivirus, antispam,… [...]
i followed the guide to the word with the exception of substituting some areas with my name. when i went to test the settings in thunderbird all the info came up the way it was set up but the password could not be recognized and i went through all the instances in which mailuserpassword had to be changed if i could get some assistance