Setting up a Mail Server in Ubuntu

Versions: Hardy (8.04), Intrepid (8.10) and Jaunty (9.04)

Setting up a Mail Server in Linux may be sometimes not as easy as other services (eg. ftp, ssh, web, etc). I needed to set up a Mail server in few days, so I went through several tutorials, manuals, etc. I finished doing a combination of some methods (I explain later why they didn't fulfill my expectations) and added my personal way to do it. The result, these scripts.

If you are in not a hurry, and you are interested in knowing what the script do, please read the Tutorial (below).


These scripts have been tested in 4 servers and 1 virtual server (vmware). The whole installation process may take up to 3 minutes! (depending of your connection)

Download the automatic-interactive installation script (sh):

mailserver.tar.gz (v.03-08-2009)

To manage users: * (v.16-07-2009, included in mailserver.tar.gz)

To manage domains: * (v.02-06-2009, included in mailserver.tar.gz)

Install Instructions:

tar -xf mailserver.tar.gz
cd mailserver
sudo ./

(It works better in a clean installation of Ubuntu)

What you get:

A highly secured mail server for a medium-sized or small company.
  1. a SMTP server (Postfix) with password authentication (prevent spammers of using your server for sending mails)
  2. a POP3 (+ SSL) or/and IMAP (+ SSL) server (Dovecot)
  3. Virtual Domains ( so you can use user@domain1.tld and user@domain2.tld ) (Note: it is a kind of hybrid, please read the tutorial if you are interested).
  4. Encryption and Authentication methods (TSL, SASL, PAM)
  5. Spamassassin and ClamAV as mail filters


NOTE: If you are planning to setup a mail server only to be used in a local network (i.e. it would never receive or send mails from/to internet), then you can follow the "SMTP Server" and "POP3 and IMAP Server" sections only.

All commands here are run with root privileges using "sudo -s".

In this tutorial we will set up:

SMTP Server

For this setup, I followed some of the recommendations posted in HowtoForge.
Also, I recommend you to read the Postfix documentation for more specify setups and restrictions.

Lets start installing our Postfix SMTP server (version used: 2.5.5):

aptitude install postfix
We will need to modify postfix configuration file, located at:

# See /usr/share/postfix/ for a commented, more complete version

#The next 3 parameters are only to be used in your test server.
#once you are done, and want to move it to the real world, please remove them.
soft_bounce = yes
unknown_local_recipient_reject_code = 450
debug_peer_list =
debug_peer_level = 2

biff = no
append_dot_mydomain = no
readme_directory = no
relayhost =
recipient_delimiter = +
inet_interfaces = all
inet_protocols = all

mydomain = domain.tld
myhostname = mail.domain.tld
myorigin = $myhostname
mydestination = $myhostname
smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu)

# (change its values accordingly).
mynetworks =,

mailbox_command =
mailbox_size_limit = 102400000

#this value will change if you need virtual domains...
home_mailbox = Maildir/

alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases

Save it and run:

/init.d/postfix restart
To ensure there are no errors in the config file, run:

postfix reload
even after restarting postfix.

Lets try it. Type:

telnet localhost smtp
If you are using a server different from localhost, and the connection fails, check that your firewall is not blocking port 25 or check if the port is enabled:

nmap localhost
If the connection succeed you will see:

Trying Connected to localhost Escape character is '^]'. 220 smtp.mydomain.tld ESMTP Postfix (Ubuntu)
Then type:

ehlo localhost
It will display:

250-smtp.mydomain.tld 250-PIPELINING 250-SIZE 10240000 250-VRFY 250-ETRN 250-ENHANCEDSTATUSCODES 250-8BITMIME 250 DSN
Then just type "quit" to return to shell.

In case something goes wrong, check your logs at:

We are not done yet... a long way to go... so please relax...

POP3 and IMAP Server

In order to access our mails we will need a POP3 or IMAP server.
The main servers in this category are:

Dovecot , Courier and Cyrus

You will probably find plenty of tutorials for each of them.
When I followed HowtoForge procedure, the Courier part was not so clear and I couldn't make it work... so I tried Dovecot, and resulted quite easy to make it work properly.
For this part I followed a very well explained tutorial in the Ubuntu Community. If you have any question in this section (for example, POP3 and IMAP differences) I suggest you to look at it (because I will not cover that much here).

Lets install Dovecot (version used: 1.1.4):

aptitude install dovecot-pop3d dovecot-imapd
Then, we will modify Dovecot config file at:

Change the values according to this:
# pop3s and imaps are not ready yet... that will be covered in
# the Security section
protocols = pop3 imap
# this value will change if you need virtual domains... 
mail_location = maildir:~/Maildir (for maildir)

Change this lines to "yes" if you want more debug details:
auth_verbose = yes
auth_debug = yes
auth_debug_passwords = yes

ONLY If you don't need virtual domains (see Virtual Domains section in this document for explanation) then do the following to prepare the Maildir directory content for new users:

maildirmake.dovecot /etc/skel/Maildir maildirmake.dovecot /etc/skel/Maildir/.Drafts maildirmake.dovecot /etc/skel/Maildir/.Sent maildirmake.dovecot /etc/skel/Maildir/.Trash maildirmake.dovecot /etc/skel/Maildir/.Templates
And for the existing user (ONLY If you don't need virtual domains):

cp -r /etc/skel/Maildir /home/myuser/ chown -R myuser:usergroup /home/myuser/Maildir chmod -R 700 /home/myuser/Maildir
If you are going to follow the Virtual Domains setup, then create the default directory setup for each new user:

maildirmake.dovecot /etc/skel/
Testing our Dovecot Server:

/etc/init.d/dovecot restart
And in the same way we tested Postfix, type:

telnet localhost pop3
It will display:

Trying localhost... Connected to localhost. Escape character is '^]'. +OK dovecot ready
type "quit" to return to shell.

In case something goes wrong, check your logs at:

/var/log/mail.log /var/log/dovecot /var/log/auth.log /var/log/syslog
To add email accounts, just add users as it is done usually in Linux.

Until this part, your SMTP and POP / IMAP servers works fine but they lack in security, but not that much... your SMTP server will not allow to send mails from any other network that is not specified at the "mynetworks" parameter in your postfix configuration file. Also, Dovecot will not allow you to access without any type of encryption method unless you are in the same computer as your mail server.

If you don't need virtual domains, then you can skip to the Security section and you are done.

Virtual Domains

If you setup your mail server to handle different "virtual" domain names (e.g. mydomain.tld, otherdomain.tld, etc..) you will be able to use same "user" names as:
info@mydomain.tld and info@otherdomain.tld without having to change the aliases file. Other advantage of this approach is that you can have a well organized domain/users structure, like this:

mydomain.tld / info / help / sell / boss
otherdomain.tld / info / recruit / myself

For this section I followed another well explained tutorial in the Ubuntu Community which covers Dovecot as well. However, that article has 2 main withdraws:

1. It only covers how to setup a ClamAV filter and do not include Spamassassin (a must, I think).

2. If you want to go with virtual domains you will end up with very weak security (passwords stored in plain text files) or duplicating authentication procedures (not desired).

The reason is because It seems that PAM will only work with system accounts (the ones in /etc/password). However, if you use SASL (with sasldb) authentication you will be able to use it in Postfix, but not in Dovecot (bad thing...). I tried different workarounds and I lost so many time, that I gave up.

So, the only way I found to achieve virtual domains in combination with Dovecot, without having to use mysql (which is more complicated and it may overload your server), is using a "hybrid" method: using system users but with well organized directory structures.

My procedure may not be the best one, and it can be improved, but it worked for me and I'm happy with it. The main withdraw of my way to do it is that you have to modify 2 files every time you add a user, but it can be easily reduced with a shell script that I include later in this tutorial.

First, lets add these lines to you /etc/postfix/ :

#Virtual Mailboxes setup
virtual_mailbox_base = /home/users
virtual_mailbox_domains = /etc/postfix/vhosts
virtual_mailbox_maps = hash:/etc/postfix/vmaps
virtual_minimum_uid = 1000
virtual_uid_maps = hash:/etc/postfix/virtual_uids
virtual_gid_maps = static:5000

Then, modify "home_mailbox" with this value:
home_mailbox = /

Save your file and execute:

postfix reload
Remember to execute that command every time you modify (or

I choose "/home/users" as the base directory of the mailboxes, but you can change it to whatever you want.

Create the file: /etc/postfix/vhosts, for example:

mydomain.tld otherdomain.tld
So, every time you add a new domain, you need to add it here and create their directory under /home/user (in my case) as:

/home/user/mydomain.tld /home/user/otherdomain.tld
This vhost information will be later useful to bounce mails that are send to domains not listed here (so you can block all accounts inside a domain if the customer don't pay, for example)

Lets make a pause before continuing with the remaining files at the postfix file. We will need to manage the users.

Create the "vmail" user and group:

groupadd -g 5000 vmail useradd -u 5000 -g 5000 -s /usr/bin/false vmail
Create the /home/users directory:

mkdir /home/users
Change the owner of that directory to "vmail":

chown vmail.vmail /home/users
Then, we will need to edit the default settings for the new users:

Copy the default useradd config file, to the postfix directory (you can choose other location as well):

cp /etc/adduser.conf /etc/postfix/mailuser.conf
Now, edit mailuser.conf, modifying only (leave the rest as it is):
# Use: /usr/bin/false     if you don't want to allow ssh access
# Use: /usr/bin/passwd     to allow user to change password (with ssh server)
# Use: /bin/bash     to allow user to ssh access (with ssh server)

# Comment this line:
# DHOME=/home

# You can use group homes too. For example, you can create
# a group home like: "mydomain.tld" and let Linux to take care
# of the /usr/home/group/user structure. I didn't follow that
# path because It would complicate a little more all the setup

# All mail users ids over 5000: (Note: this is UID not GID)


# In group "vmail"

# To set all directories to "vmail" group: (optional)

To create new users, this time we will do all it manually, but they will be created as part of an automated script (included later in this document).

Lets create our first user (use very easy passwords for now, don't forget them):

adduser --home /home/users/mydomain.tld/info --conf /etc/postfix/mailuser.conf info400
For testing, we could use other account. Lets add another one:

adduser --home /home/users/otherdomain.tld/info --conf /etc/postfix/mailuser.conf info123
"info" is the virtual name, for example: info@mydomain.tld
"info400" can be anything, it is the username used to login into the server,
for example, it can be:

UserName             Comment
_________________    _____________________________________________________
info                 NOT RECOMMENDED: it will not allow other "info" user.
p9zTs41mK A hard to guess username
info01 If you want to control how many "test" users are
info5921 user with 4 random numbers
info.mydomain to easily keep track of what domain is using
info@mydomain.tld I personally don't recommend this one because
it will become: /home/mydomain.tld/info@mydomian.tld
and all the "virtual" domain setup is worthless.
If you still want to create it, you may need the
--force-badname parameter to support the "@".

We will need the user id (UID). Type:

grep "info400" /etc/passwd | cut -d : -f 3
It will return a number:

Keep that number, we will use it soon.

Now, lets continue with the postfix config file...

Create the file: /etc/postfix/vmaps, for example:

info400 0 info@mydomain.tld mydomain.tld/info/ info123 0 info@otherdomain.tld otherdomain.tld/info/
info400: is our system username.
0: is anything. You can write down the domain name or any note you want to do (just don't leave it blank)
The rest is as the usual configuration.

Because we are using "hash:/" (at we need to run:

postmap /etc/postfix/vmaps
Don't forget to run that command every time you modify the "vhosts" file.

Create the file: /etc/postfix/virtual_uids, for example:

info@mydomain.tld 5001 info@otherdomain.tld 5002
In this file we are giving access to the virtual user as the system user. This will prevent any possible "access denied" problem you may have when receiving email, and
ensuring that only the system user can have access to it.

As with the "vmaps" file, we will need to run "postmap" each time we modify this file:

postmap /etc/postfix/virtual_uids
Finally, we need to perform a change to the dovecot configuration file:
mail_location = maildir:~/
mail_privileged_group = vmail
valid_chroot_dirs = /var/spool/vmail
Here we finish with the Virtual domains configuration. Please check the "Scripts" section at the end to download the automated scripts for this configuration.

Take a deep breath and relax...

You can now test again your system.

Restart dovecot and postfix:

/etc/init.d/postfix restart /etc/init.d/dovecot restart
Download thunderbird and create 2 accounts (separated inbox).
For POP3 / IMAP username specify for example "info400", and in e-mail account: info@mydomain.tld for one user. For the other "info123" and info@otherdomain.tld respectively.

If you have a virtual machine or other computer in the same network you can try it as well, just remember to setup accordingly your "hosts" file settings.

Try to send a mail from one account to another. SMTP server setting: mail.domain.tld (or localhost), nothing else.

Reload your inbox and set the password you set when you created the user. If everything is correct, you should see now your email at your inbox.

If it didn't work, check again the configuration and the log files:
/var/log/mail.log /var/log/dovecot /var/log/auth.log /var/log/syslog
Because we haven't improve the server security, your SMTP and POP / IMAP servers still lack in security. Remember that your SMTP server will not allow to send mails from any other network that is not specified at the "mynetworks" parameter, and Dovecot will not allow you to access without any type of encryption method unless you are in the same computer as your mail server.


I order to make stronger the security, lets add first authorization and encryption methods to our server.

For this section I followed the HowToForge recommendations to enable TSL and SSL protocols and Postfix documentation for SASL authentication.

Access wikipedia if you want to know more about the differences between TSL and SSL.

First, we need to create keys and certificates for your server. In order to work without warnings to the client, you require a FQDN.

We will store those keys and certificated in /etc/postfix/sasl directory:

mkdir /etc/postfix/sasl cd /etc/postfix/sasl openssl genrsa -des3 -rand /etc/hosts -out smtpd.key 1024 chmod 600 smtpd.key openssl req -new -key smtpd.key -out smtpd.csr openssl x509 -req -days 3650 -in smtpd.csr -signkey smtpd.key -out smtpd.crt openssl rsa -in smtpd.key -out smtpd.key.unencrypted mv -f smtpd.key.unencrypted smtpd.key openssl req -new -x509 -extensions v3_ca -keyout cakey.pem -out cacert.pem -days 3650
Inside /etc/postfix/sasl directory, you should have:

cacert.pem cakey.pem smtpd.crt smtpd.csr smtpd.key
Now, lets setup TSL in Postfix. Edit the file and add these lines:
# TLS parameters
smtpd_use_tls = yes
smtpd_tls_auth_only = no
smtpd_tls_cert_file = /etc/postfix/sasl/smtpd.crt
smtpd_tls_key_file = /etc/postfix/sasl/smtpd.key
smtpd_tls_CAfile = /etc/postfix/sasl/cacert.pem
smtpd_tls_loglevel = 1
smtpd_tls_received_header = yes
smtpd_tls_session_cache_timeout = 3600s
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
smtp_tls_note_starttls_offer = yes
tls_random_source = dev:/dev/urandom

To enable SSL in Dovecot, we need to make some changes to dovecot.conf:
(if you don't have some lines, add them)
protocols = pop3 pop3s imap imaps
disable_plaintext_auth = no
shutdown_clients = yes
ssl_disable = no
ssl_cert_file = /etc/ssl/certs/ssl-cert-snakeoil.pem
ssl_key_file = /etc/ssl/private/ssl-cert-snakeoil.key

protocol imap {
  listen = *:143
  ssl_listen = *:993
  login_executable = /usr/lib/dovecot/imap-login
  mail_executable = /usr/lib/dovecot/imap
  imap_max_line_length = 65536
protocol pop3 {
  listen = *:110
  ssl_listen = *:995
  pop3_uidl_format = %08Xu%08Xv
  login_executable = /usr/lib/dovecot/pop3-login
  mail_executable = /usr/lib/dovecot/pop3

auth_executable = /usr/lib/dovecot/dovecot-auth

Restart postfix and dovecot and you will be able to choose TSL and SSL from thunderbird.
Remember that SSL listen in a different port, so if you want to try in Outlook, you need to change the port number.

If Dovecote was blocking the connection because of "plaintext" restriction (in remote connections), now you will be able to login.

The second part of this section is to enable SASL Authentication through PAM. This will let you to use a wide options of encryption methods, will enhance the login security and will force the users to authenticate in order to send an email (This is the best part!).

We will need to install additional SASL libraries (version used: 2.1.22):

aptitude install libsasl2-2 sasl2-bin libsasl2-modules
Lets add again some lines to the postfix config file:
#SASL Authorization
smtpd_sasl_auth_enable = yes
smtpd_sasl_local_domain = $myhostname
smtpd_sasl_security_options = noanonymous
smtpd_sasl_authenticated_header = yes
#We will use dovecot to authenticate, so we don't need to duplicate login information.
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
#support for some old clients:
broken_sasl_auth_clients = yes
smtpd_reject_unlisted_sender = yes
smtpd_delay_reject = yes
smtpd_helo_required = yes
disable_vrfy_command = yes

smtpd_client_restrictions = permit_sasl_authenticated,reject
smtpd_data_restrictions = reject_unauth_pipelining
smtpd_recipient_restrictions =


Before moving your server to production, I suggest you to look at the PostfixAntiUCE or AkadiaPostfixUCE for a large list of recommended restrictions.

Change these lines at the default SASL config file: /etc/default/saslauthd
OPTIONS="-c -m /var/spool/postfix/var/run/saslauthd -r"
And create the following directory:

mkdir -p /var/spool/postfix/var/run/saslauthd
Now, we need to change the authorization section at the Dovecot configuration file:
auth default {
      mechanisms = plain login
      passdb pam {
        args = dovecot
        #args = cache_key=%u dovecot
      userdb passwd {
      socket listen {
        client {
          path = /var/spool/postfix/private/auth
          mode = 0660
          user = postfix
          group = postfix
Check the Dovecot documentation for additional information.

Restart Dovecot, postfix and the saslauthd daemon:

/etc/init.d/postfix restart /etc/init.d/saslauthd restart /etc/init.d/dovecot restart
Try again with telnet:

telnet localhost smtp
If the connection succeed you will see:

Trying Connected to localhost Escape character is '^]'. 220 smtp.mydomain.tld ESMTP Postfix (Ubuntu)
Then type:

ehlo localhost
It will display:

If you see the line starting with "AUTH", then this means you can login
and your configuration is fine. "STARTTLS" as you can guess, means that TLS is enabled.

Now, try again to send an email from info@mydomain.tld to info@otherdomain.tld. You will see that it would fail. Why? because now you have to specify a username / password in order to send an email.
Go to SMTP server settings in thunderbird and check the option: "use name and password" and enter the user name (e.g., info400), also you may want to check the TLS option located below.

Try again. This time your email must go.

Dealing with SPAM and Virus

The final part of this tutorial is to add a filter to postfix to reject those undesired emails. For this section I practically copied all the procedure at the Ubuntu Community.

So, I recommend you to follow that tutorial (because it is very good explained).
NOTE: The only part that I will change is where it said:

Also add the following two lines immediately below the "pickup" transport service:
-o content_filter=
-o receive_override_options=no_header_body_checks

Which in my case it caused the entire filter to fail. So meanwhile just don't add this part.

In case that link doesn't work, or you require less details, keep reading...

Open one more time the "" and add these lines:
content_filter = scan:
receive_override_options = no_address_mappings
"scan" is our custom name for that filter.

Change the following line (this is to disable chroot, we changed a "-" for "n"):
smtp      inet  n       -       n       -       -       smtpd

Then add these lines in the "" at the same postfix directory:
scan      unix  -       -       -       -       2       smtp
        -o smtp_data_done_timeout=1200
        -o smtp_send_xforward_command=yes
        -o disable_dns_lookups=yes
        -o max_use=20 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_helo_restrictions=
        -o smtpd_end_of_data_restrictions=
        -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
If you don't know where to insert those files, please check the example posted in the Ubuntu Community tutorial.

Save the file. But wait!! We need to install a bunch of software in order to this filter to work:

1. ClamAV (Open Source Antivirus)
aptitude install clamav-daemon clamav 2. Spamassassin:
aptitude install spamassassin3. Amavis Wrapper:
aptitude install amavisd-new4. For better Spam detection:
aptitude install libnet-dns-perl libmail-spf-query-perl pyzor razor5. Compress / Uncompress utils:
aptitude install arj bzip2 cabextract cpio file gzip lha nomarch pax rar unrar unzip unzoo zip zoo ripole p7zip

All in one line:
aptitude install clamav-daemon clamav spamassassin amavisd-new libnet-dns-perl libmail-spf-query-perl pyzor razor arj bzip2 cabextract cpio file gzip lha nomarch pax rar unrar unzip unzoo zip zoo ripole p7zipIf you receive a message like:

Starting amavisd: The value of variable $myhostname is "mail", but should have been
a fully qualified domain name; perhaps uname(3) did not provide such.
You must explicitly assign a FQDN of this host to variable $myhostname
in /etc/amavis/conf.d/05-node_id, or fix what uname(3) provides as a host's network name!

Edit /etc/amavis/conf.d/05-node_id (requires a semicolon at the end):
$myhostname = "mail.domain.tld";

Edit /etc/amavis/conf.d/01-debian:
#disabled (non-free, no security support)
$unrar  = ['rar', 'unrar'];
$lha    = 'lha';
And delete $unrar=undef and $lha=undef lines.

Save it and restart amavisd:

/etc/init.d/amavis restart
Allow clamAV and amavis to intercommunicate:

adduser clamav amavis adduser amavis clamav
Edit /etc/default/spamassassin:
and start spamassassin:

/etc/init.d/spamassassin start
To enable antivirus detection in Amavis, uncomment in: /etc/amavis/conf.d/15-content_filter_mode
@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);
In order to prevent bouncing SPAM (we don't want that), change $final_spam_destiny
value in: /etc/amavis/conf.d/20-debian_defaults
$final_spam_destiny       = D_DISCARD;
Now, restart everything:
/etc/init.d/postfix restart /etc/init.d/saslauthd restart /etc/init.d/dovecot restart /etc/init.d/clamsmtp restart /etc/init.d/clamav-daemon restart /etc/init.d/amavis restart /etc/init.d/spamassassin restart
And check the mail.log file, so you will see that spamassassin has been loaded.
If you want to test your antivirus, follow the last part ("TEST") of the Ubuntu Community tutorial (

Final Notes

Finally all this works... (hopefully). I tested this configuration in 3 different computers with the same software versions.

If you haven't done it yet, also change your hostname accordingly.

Other possible additions to our mail server could be the following packages available at Ubuntu's repository:

whitelister - White listing (unmaintained?)
postgrey - Greylisting
bld-postfix - Black listing
spfquery - Sender Policy Framework
bogofilter - Bayesian spam filter


Its a complete groupware system,
but was too much for what I was requiring.
The web setup was easy,
but I couldn't make postfix to connect with MySql.
It seems good, but I didn't test it.
They list other alternatives systems as well.