Home » Ubuntu Linux » Ubuntu Setup Mail Server

Ubuntu Setup Mail Server

(Postfix, Courier, SSL/TLS, SpamAssassin, ClamAV, Amavis)
This guide is now compatible with Ubuntu 13.04
For earlier versions: Creating a Mail Server on Ubuntu (Postfix, Courier, SSL/TLS, SpamAssassin, ClamAV, Amavis)

Once again, credit where credit due: Thanks again to Ivar Abrahamsen for his guide which is, by far, one of the best ones out there.

Getting Started

This guide is intended to be a reference for setting up a server quickly. For that reason, I have intentionally omitted information which explains each step. Please feel free to ask any questions in the comments and I’ll try to answer you as quickly as possible.

There are several configuration variables that you will need to replace in certain configuration files. These occurrences are clearly marked during the guide. However, for your reference, here are the variables used:

mail.example.com
The hostname for your mail server. This can be anything you like, however, it should match the public hostname as specified by your DNS records if you want to expose the server over the Internet.
rootpassword
The password for the MySQL root user. You should pick something unique and secure; but something you can remember.
mailpassword
The password for the MySQL mail user. You should pick something unique and secure; you don’t even have to remember it beyond this tutorial.
adminpassword
The password for the administrator e-mail account that you’ll create later in the guide.

Installation

sudo su -
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

Virtual User

Note: All e-mail messages will be received by a single ‘virtual’ user. That is, only one system account needs to be created and we’ll manage mailboxes using the virtual user features of Postfix.

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

Note that we are forcing the user ID to 5000 as this value is referenced by configuration files later. If you need to use a different UID make sure you update the affected configuration files, too.

Postfix

mv /etc/postfix/main.cf{,.dist}
vi /etc/postfix/main.cf

Copy/paste:
Replace mail.example.com

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
 
# SMTP Authentication (SASL)
 
smtpd_sasl_auth_enable = yes
broken_sasl_auth_clients = yes
smtpd_sasl_security_options = noanonymous
smtpd_sasl_local_domain =
 
# Encrypted transfer (SSL/TLS)
 
smtp_use_tls = yes
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_sender_restrictions = permit_sasl_authenticated, permit_mynetworks, reject
smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject
 
# 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_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.cf
mv /etc/postfix/master.cf{,.dist}
vi /etc/postfix/master.cf

Copy/paste:

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
submission inet n       -       -       -       -       smtpd
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
# When relaying mail as backup MX, disable fallback_relay to avoid MX loops
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
#
# ====================================================================
# Interfaces to non-Postfix software. Be sure to examine the manual
# pages of the non-Postfix software to find out what options it wants.
#
# Many of the following services use the Postfix pipe(8) delivery
# agent.  See the pipe(8) man page for information about ${recipient}
# and other message envelope options.
# ====================================================================
#
# maildrop. See the Postfix MAILDROP_README file for details.
# Also specify in main.cf: maildrop_destination_recipient_limit=1
#
maildrop  unix  -       n       n       -       -       pipe
  flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
#
# See the Postfix UUCP_README file for configuration details.
#
uucp      unix  -       n       n       -       -       pipe
  flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
#
# Other external delivery methods.
#
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_checks

Virtual Maps

mkdir /etc/postfix/maps
vi /etc/postfix/maps/alias.cf

Copy/paste:
Replace mailpassword

user = mail
password = mailpassword
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:
Replace mailpassword

user = mail
password = mailpassword
dbname = mail
table = domain
select_field = domain
where_field = domain
hosts = 127.0.0.1
additional_conditions = AND `enabled` = 1
user = mail
password = mailpassword
dbname = mail
table = domain
select_field = domain
where_field = domain
hosts = 127.0.0.1
additional_conditions = AND `enabled` = 1

Copy/paste:
Replace mailpassword

user = mail
password = mailpassword
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
chmod 700 /etc/postfix/maps/*
chown postfix:postfix /etc/postfix/maps/*

SASL Authentication (SSL/TLS)

usermod -aG sasl postfix
mkdir -p /etc/postfix/sasl
vi /etc/postfix/sasl/smtpd.conf

Copy/paste:
Replace mailpassword

pwcheck_method: saslauthd
auxprop_plugin: sql
mech_list: plain login
sql_engine: mysql
sql_hostnames: 127.0.0.1
sql_user: mail
sql_passwd: mailpassword
sql_database: mail
sql_select: SELECT `password` FROM `user` WHERE `email` = "%u@%r" AND `enabled` = 1
mkdir -p /var/spool/postfix/var/run/saslauthd
mv /etc/default/saslauthd{,.dist}
vi /etc/default/saslauthd

Copy/paste:

START=yes
DESC="SASL Authentication Daemon"
NAME="saslauthd"
MECHANISMS="pam"
MECH_OPTIONS=""
THREADS=5
OPTIONS="-r -c -m /var/spool/postfix/var/run/saslauthd"
vi /etc/pam.d/smtp

Copy/paste:
Replace mailpassword

auth    required   pam_mysql.so user=mail passwd=mailpassword host=127.0.0.1 db=mail table=user usercolumn=email passwdcolumn=password crypt=1
account sufficient pam_mysql.so user=mail passwd=mailpassword host=127.0.0.1 db=mail table=user usercolumn=email passwdcolumn=password crypt=1
chmod 700 /etc/postfix/sasl/smtpd.conf
chmod 700 /etc/pam.d/smtp

Courier

mv /etc/courier/authdaemonrc{,.dist}
vi /etc/courier/authdaemonrc

Copy/paste:

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{,.dist}
vi /etc/courier/authmysqlrc

Copy/paste:
Replace mailpassword

MYSQL_SERVER localhost
MYSQL_USERNAME mail
MYSQL_PASSWORD mailpassword
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{,.dist}
vi /etc/courier/imapd

Copy/paste:

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{,.dist}
vi /etc/courier/imapd-ssl

Copy/paste:
Replace mail.example.com

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{,.dist}
vi /etc/courier/pop3d

Copy/paste:

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{,.dist}
vi /etc/courier/pop3d-ssl

Copy/paste:
Replace mail.example.com

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

Note: In the next step you will be prompted to input some information about the certificate you create. You can enter any information you want here except Common Name (CN) which must match mail.example.com.

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
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.*
chgrp ssl-cert /etc/ssl/private/mail.example.com.*

Amavis

rm -f /etc/amavis/conf.d/50-user
vi /etc/amavis/conf.d/50-user

Copy/paste:

use strict;
 
$log_level = 1;
$syslog_priority = 'info';
$sa_kill_level_deflt = 6.5;
$final_spam_destiny = D_DISCARD;
$pax = 'pax';
 
@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);
@local_domains_acl = qw(.);
 
1;

SpamAssassin

mv /etc/default/spamassassin{,.dist}
vi /etc/default/spamassassin

Copy/paste:

ENABLED=1
OPTIONS="--create-prefs --max-children 5 --helper-home-dir"
PIDFILE="/var/run/spamd.pid"
CRON=0

ClamAV

dpkg-reconfigure clamav-freshclam

MySQL Database

mysql -uroot -p

Enter rootpassword.

Copy/paste:
Replace mailpassword

CREATE DATABASE `mail`;
GRANT ALL ON `mail`.* TO "mail"@"localhost" IDENTIFIED BY "mailpassword";
 
FLUSH PRIVILEGES;
USE `mail`;
 
CREATE TABLE IF NOT EXISTS `alias` (
  `source` VARCHAR(255) NOT NULL,
  `destination` VARCHAR(255) NOT NULL DEFAULT "",
  `enabled` TINYINT UNSIGNED NOT NULL DEFAULT 1,
  PRIMARY KEY (`source`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
CREATE TABLE IF NOT EXISTS `domain` (
  `domain` VARCHAR(255) NOT NULL DEFAULT "",
  `transport` VARCHAR(255) NOT NULL DEFAULT "virtual:",
  `enabled` TINYINT UNSIGNED NOT NULL DEFAULT 1,
  PRIMARY KEY (`domain`)
) ENGINE=InnoDB 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 NULL,
  `quota` INT UNSIGNED DEFAULT NULL,
  `enabled` TINYINT UNSIGNED NOT NULL DEFAULT 1,
  PRIMARY KEY (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Create default data. This will:

Permit messages sent to the localhost domain
Permit messages sent to the localhost.localdomain domain
Permit messages sent to the example.com domain
Create a mailbox for admin@example.com with the password adminpassword
Forward messages to the localhost.localdomain domain to the localhost domain
Forward messages to the localhost domain to admin@example.com
Copy/paste:
Replace example.com and adminpassword

INSERT INTO `domain` (`domain`) VALUES ("localhost"), ("localhost.localdomain"), ("example.com");
INSERT INTO `user` (`email`, `password`, `name`) VALUES ("admin@example.com", ENCRYPT("adminpassword"), "Administrator");
INSERT INTO `alias` (`source`, `destination`) VALUES ("@localhost.localdomain", "@localhost"), ("@localhost", "admin@example.com");

Finishing Up

Reboot Services

service saslauthd restart
service postfix restart
service courier-authdaemon restart
service courier-pop restart
service courier-pop-ssl restart
service courier-imap restart
service courier-imap-ssl restart

Create Your Mail Directory

You will not be able to login to your mailbox(es) until you create the required folder structure. There are two ways to do this:

Send an e-mail to your new e-mail address from an existing e-mail account. Postfix will create the required directories for you.
Create the directories yourself:

mkdir -p /var/spool/mail/virtual/example.com/admin/{new,tmp,cur}
chown -R virtual:virtual /var/spool/mail/virtual/example.com/admin/

Leave a Reply

Your email address will not be published. Required fields are marked *

*
*

*