A definitive guide to setting up your own Mail Server – Part 1

Setting up a mail server, in itself, is not that difficult a task, but there are integrations that can really mess up with your time and mind. Integrations such as SMTP authentication, setting up virtual users and virtual mailboxes, setting up spam-filtering and antivirus filtering can really be a pain if not configured properly. Hence, I decided why not share my own experiences in the form of a tutorial. May be this will help out someone trying to setup a mail server.

I have divided this tutorial into several parts, so that I can explain as we go about setting up the server, and of course going one step at a time, ensures that we are understanding what we are doing.

About the first part

This is first part of a series of tutorials on “setting up a mail server” and it will deal with setting up the most basic form of Postfix, while the later parts will deal with adding more functionality, like SMTP authentication, POP3 and IMAP access, spam and virus filtering, etc.

I am assuming that you have Ubuntu installed on your machine and its up and running and connected to the internet.

Where ever I refer to yourdomain.com, replace it with your actual domain name (in my case it is ovaistariq.net).

Now lets get started!

Getting started

Setting up DNS record

Before you go on and follow the steps required to set up the DNS record, make sure you are familiar with DNS configuration. If you are not then please first read a guide on setting up DNS. The following DNS related entries need to go into the DNS zone file. You may also ask your hosting support guys as to how to setup the following DNS entries.

Repeat the following steps:

  • Crete a dns entry for the MX record:

    @ MX 10 mail.yourdomain.com
  • Create a A/AAAA record for the hostname mail that points to the ip address of your machine on which mail server will be setup.

    mail A

    Here replace with the IP address of the machine on which mail server will be setup.

Setting up the hostname

Edit the file /etc/hostname, it should only have a single line that reads as follows:


Make sure that you have following entires in /etc/hosts file: localhost localhost.localdomain local

Setting up the mail server name

Edit the file /etc/mailname, it should only have a single line that reads as follows:


Setting up the mail aliases

Edit the file /etc/aliases and the following aliases:


Replace ovaistariq@gmail.com with your email address where you want emails to be delivered to whenever emails are sent to root@localhost.

The above aliases ensure that local email addresses postmaster, abuse, security, root are actually aliases of the local email address root.

Installing the required package

Now lets start installing the required packages.
The only package that we need right now is the Postfix package.

Postfix for sending and receiving emails

We would be using Postfix as our MTA, and Postfix would be sending and receiving emails.

$ sudo apt-get install postfix

Configuring Postfix to send and receive emails

Configuring Postfix isn’t much difficult either if you now the configuration settings. We won’t be using the dpkg-configure utility. Instead we will be editing the configuration files directly because that is much simpler and less error-prone.

Main configuration files

Postfix has the following main configuration files:

  • /etc/postfix/main.cf
    This file is the main configuration file that holds various configuration settings like the mail server name, the networks on which mail is allowed to be transmitted, setting that allows Postfix to relay emails to be sent to other servers, information about how it should authenticate the mail users, etc.
  • /etc/postfix/master.cf
    This file is the Postfix process configuration file that hold information such as which services are offered (say smtp service is offered as well as smtps), how mails are to be relayed, how Postfix will interface with other processes (say the amavis process for filtering spam and virus), etc.

The above mentioned files are very important for Postfix to work properly, so be extra careful when editing the above two files. Next we will be editing the above two files.

Editing configuration files

Let’s start by first editing the /etc/postfix/main.cf configuration file.
This file should only have the following content:

# See /usr/share/postfix/main.cf.dist for a commented, more complete version

# Debian specific:  Specifying a file name will cause the first
# line of that file to be used as the name.  The Debian default
# is /etc/mailname.
#myorigin = /etc/mailname

smtpd_banner = $myhostname ESMTP $mail_name
biff = no

# appending .domain is the MUA's job.
append_dot_mydomain = no

# Uncomment the next line to generate "delayed mail" warnings
#delay_warning_time = 4h

readme_directory = no

# See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for
# information on enabling SSL in the smtp client.

myhostname = mail.ovaistariq.net
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
myorigin = /etc/mailname
mydestination = localhost.localdomain, localhost
#mydestination =
relayhost =
mynetworks = [::ffff:]/104 [::1]/128
mailbox_command = procmail -a "$EXTENSION"
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all
inet_protocols = all
home_mailbox = Maildir/

# Extra params

# how long if undelivered before sending warning update to sender
delay_warning_time = 4h
# will it be a permanent error or temporary
unknown_local_recipient_reject_code = 450
# how long to keep message on queue before return as failed.
#maximal_queue_lifetime = 3d
# max and min time in seconds between retries if connection failed
minimal_backoff_time = 1000s
maximal_backoff_time = 8000s
# how long to wait when servers connect before receiving rest of data
smtp_helo_timeout = 60s
# how many error before back off.
smtpd_soft_error_limit = 3
# how many max errors before blocking it.
smtpd_hard_error_limit = 12

Now let’s edit the file /etc/postfix/master.cf.
This file should only have the following content:

# 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
#628       inet  n       -       -       -       -       qmqpd
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
#qmgr     fifo  n       -       -       300     1       oqmgr
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=
#       -o smtp_helo_timeout=5 -o smtp_connect_timeout=5
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}
# ====================================================================
# Recent Cyrus versions can use the existing "lmtp" master.cf entry.
# Specify in cyrus.conf:
#   lmtp    cmd="lmtpd -a" listen="localhost:lmtp" proto=tcp4
# Specify in main.cf one or more of the following:
#  mailbox_transport = lmtp:inet:localhost
#  virtual_transport = lmtp:inet:localhost
# ====================================================================
# Cyrus 2.1.5 (Amos Gouaux)
# Also specify in main.cf: cyrus_destination_recipient_limit=1
#cyrus     unix  -       n       n       -       -       pipe
#  user=cyrus argv=/cyrus/bin/deliver -e -r ${sender} -m ${extension} ${user}
# ====================================================================
# Old example of delivery via Cyrus.
#old-cyrus unix  -       n       n       -       -       pipe
#  flags=R user=cyrus argv=/cyrus/bin/deliver -e -m ${extension} ${user}
# ====================================================================
# 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}

That’s all of the initial configuration that we need for Postfix to start running. There will be more configuration settings to do when we setup anti-virus, anti-spam, authentication, user management, etc.

Make sure that connections to port 25 are allowed by the firewall on your server, if you have any. If you are using Ubuntu’s default Firewall UFW, then its as simple as $ ufw allow 25. You can check which ports are allowed by doing this, $ ufw status

Testing the configuration

Now let’s test out our mail server, by sending out an email to an email address on another domain, say ovaistariq@gmail.com. The tool that we will be using to do our testing is telnet.
If you don’t already have telnet installed, then you can do so as follows:

$ sudo apt-get install telnet

Sending a test email to an external email address

Start off by issuing the following command

$ telnet localhost 25

You should a response as follows:

Connected to localhost.
Escape character is '^]'.
220 mail.yourdomain.com ESMTP Postfix

Of course instead of mail.yourdomain.com you would see the name of your domain, in my case its mail.ovaistariq.net

Now lets initiate the hand shake with the mail server by issuing the following command

EHLO localhost

The response from the server should be something like follows:

250-SIZE 10240000
250 DSN

Next step is to tell the mail server the from email address (replace yourdomain.com in the following line with the name of your domain)


The response should be:

250 2.1.0 Ok

Next we tell the mail server who the recipient of the mail will be (replace ovaistariq@gmail.com with your own external email address)


The response should be:

250 2.1.0 Ok

Next we tell the mail server that we are ready to write down the email body


The response will be something like the following:

354 End data with .

Now enter the message body and end with a line with only a full stop

This is a test message and i am testing to see if i can send out email to external email address.

If you get a message the email has been queued as follows then all is well

250 2.0.0 Ok: queued as 5B708A841

Now lets issue the quit command to end our session with the mail server


But do we know that the email has been sent. Yes we can find out by looking at the logs.
Postfix logs all the activity in a file /var/log/mail.log. So a quick look and if you see a log entry similar to the following one, then it means the email has been sent successfully:

postfix/smtp[7194]: 0ACE6A84B: to=, relay=gmail-smtp-in.l.google.com[]:25, delay=0.62, delays=0/0.01/0.29/0.33, dsn=2.0.0, status=sent (250 2.0.0 OK 1285503898 n30si6563972weq.139)

Well this isn’t just the end of setting up your Mail Server, there is more to follow.

What’s coming?

This is just the first part of a series of tutorials, there are more interesting things to come, so keep tuned. Let me list down whats coming:

  • Setting up (Virtual) users and mailbox management, using MySQL as the backend
  • Setting up POP3 and IMAP access for email clients
  • Setting up Spamassassin, Pyzor and Razor for anti-spam related functionality
  • Setting up ClamAV to be used for mail anti-virus filtering
  • Setting up SMTP authentication using Cyrus SASL
  • Setting up mail white-listing and black-listing using Postgrey
  • Setting up RoundCube as the web email client
  • Setting up Postfix Admin as email and user management front end

So stay tuned, I won’t be taking too long to finish up this series of tutorials. I hope this first part was of help to you. See you soon, cheers till then!

Ovais is a storage architect with keen focus on reliability, efficiency and performance of OLTP databases, more specifically MySQL. He currently works at Uber on ensuring storage reliability and scalability. Previously, he helped different web properties scale their MySQL infrastructure. He also worked at Percona as a Senior MySQL consultant and at a few other startups in various capacities.