Setup Postfix Email Server

For saving money and taking the full control of the service, I decided to setup my own postfix email server on a Ubuntu virtual server. And this article recorded the process.

1. Prerequisites

There are a set of tasks that should be finished before we even get to Postfix.

1.1. Setup DNS

The DNS records should look like this:

HOSTNAME                    TTL    TYPE  PRIO  VALUE

# Where to find the server
mail.[DOMAIN_NAME]          57600  A           [IP-ADDRESS]

# If the request is related to email, then forward to mail sub-domain
[DOMAIN_NAME]               57600  MX    10    mail.[DOMAIN_NAME]

# Optional, only used for setting up MUA (mail user agent)
autoconfig.[DOMAIN_NAME]    57600  CNAME       mail.[DOMAIN_NAME]

# Optional, only used for setting up MUA
autodiscover.[DOMAIN_NAME]  57600  CNAME       mail.[DOMAIN_NAME]

The core of the DNS records is the A and the MX records. The A record defines the mail sub-domain pointing to the actual mail server, and the MX record redirects the mail request from the main domain to the sub-domain, so that we could use the domain name like user@[DOMAIN_NAME] instead of user@mail.[DOMAIN_NAME].

If there is an IPv6 address, we should also set up the AAAA record for the mail sub-domain.

1.2. Setup the Reverse DNS

After DNS records have been updated, go to the hosting server provider, and set the reverse DNS from the IP-Adress back to the domain name (mail.[DOMAIN_NAME]).

1.3. Firewall Setup

Enable the port 25 and 465.

This has to be done for both inbound and also outbound, otherwise either sending or recieving mails won’t work. Note that the outbound rules sometimes are disabled by hosting service providers, so we have to create a service ticket for them to enable the 2 ports for us.

1.4. Change the Hostname

Since the Postfix reads the hostname of the server to identify itself while communicating with other MTA (message transfer agent), it is important to change the hostname to match the hostname in the DNS record:

Use following command to see what the current hostname is:

hostname -f

If it is not the one configured in the DNS record, change it using the following command:

hostnamectl set-hostname mail.[DOMAIN_NAME]

2. Installation

Finally all the preparation work is done, we can install the Postfix now.

2.1. Basic Installation

Update the package manager and the installed packages first:

apt upgrade
apt update
reboot

And then install the postfix package:

apt install postfix

Then a dialog will be displayed asking us how we want to configure Postfix. In my case, I should set it to Internal Site, this is useful for most of the cases.

In the next step, I should enter my “System mail name”. Here I should make it [DOMAIN_NAME] instead of mail.[DOMAIN_NAME], because if I set it to the latter, I won’t be able to send/receive Emails from [DOMAIN_NAME] domain.

To verify the mail service, use following command:

postconf mail_version

If everything works fine, the version number will be printed to the standard output.

We could also check who is now listening to port 25:

ss -lnpt | grep master

The output should look like this:

LISTEN 0   100   0.0.0.0:25   0.0.0.0:*   users:(("master",pid=2633,fd=13))                     
LISTEN 0   100      [::]:25      [::]:*   users:(("master",pid=2633,fd=14))

If we compare the PID with the result from ps, we should find that it is the Postfix process.

2.2. Send/Receive Test Emails

To send Email, I can use the mail command in the mailutils package in Ubuntu:

apt install mailutils

Then write a short mail:

mail -a FROM:[USER]@[DOMAIN_NAME] user@example.com
Cc:
Subject: Test
This Email is sent from a newly setup mail server.

To send the Email, press Ctrl + D, and after a few seconds, the mail should be found in the mailbox.

To receive Email, use mail command:

mail

It will start an interactive CLI environment. Use ? and Enter for a short command instructions. Some useful commands are:

  • 1: Read the first mail
  • h: List the head of the mails
  • d 1: Delete first mail
  • q: Quit program

3. Setup TLS Encryption and IMAP

There are still 2 problems after all the setup:

  1. All the Emails are transmitted in Internet in clear text.
  2. We can’t use any mail client to connect to the server.

So this paragraph will provide solutions for these two problems.

3.1. Enable More Ports in Firewall

To setup TLS and IMAP, I have to enable more ports:

  • 80 and 443 – to sign the TLS signature using certbot
  • 587 – for encrypted SMTP
  • 465 – for encrypted SMTP (deprecated)
  • 143 – for non-encrypted IMAP
  • 993 – for encrypted IMAP

3.2. Install Nginx and Certbot and Request for SSL Certificate

apt install nginx
snap install --classic cerbot

As an alternative to install certbot from snap, we could also use:

pip install certbot certbot-nginx

Provide an Nginx site config like this and put it into /etc/nginx/sites-enabled, name it like mail.[DOMAIN_NAME]:

server {
    listen  80;
    listen  [::]:80;

    server_name  mail.[DOMAIN_NAME];

    root  /usr/share/nginx/html/;

    location ~/.well-known/acme-challenge {
        allow  all;
    }
}

Request a new certificate using certbot:

certbot certonly --nginx -d mail.[DOMAIN_NAME]

In this case, certbot won’t change the settings in the nginx, it just tries to get a new certificate.

After the interactive script, the certificate files will be saved:

  • Certificate file: /etc/letsencrypt/live/mail.[DOMAIN_NAME]/fullchain.pem
  • Key file: /etc/letsencrypt/live/mail.[DOMAIN_NAME]/privkey.pem

3.3. Setup SMTP

Edit the /etc/postfix/master.cf file, and add following two blocks into the file:

submission inet n       -       y       -       -       smtpd
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=encrypt
  -o smtpd_tls_wrappermode=no
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
  -o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject
  -o smtpd_sasl_type=dovecot
  -o smtpd_sasl_path=private/auth
smtps     inet  n       -       y       -       -       smtpd
  -o syslog_name=postfix/smtps
  -o smtpd_tls_wrappermode=yes
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
  -o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject
  -o smtpd_sasl_type=dovecot
  -o smtpd_sasl_path=private/auth

Edit the /etc/postfix/main.cf file, modify the # TLS parameters section:

# TLS parameters
smtpd_tls_cert_file = /etc/letsencrypt/live/mail.[DOMAIN_NAME]/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/mail.[DOMAIN_NAME]/privkey.pem
smtpd_tls_security_level = may
smtpd_tls_loglevel = 1
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache

smtp_tls_security_level = may
smtp_tls_loglevel = 1
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache

smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
smtp_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
smtp_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1

And then restart Postfix service:

systemctl restart postfix

After that, if I check the port which is listened by master, I can see there are not only port 25, but also 465 and 587 opened:

ss -lnpt | grep master

The result should be like:

LISTEN 0  100   0.0.0.0:25  0.0.0.0:*  users:(("master",pid=12881,fd=13))
LISTEN 0  100  0.0.0.0:465  0.0.0.0:*  users:(("master",pid=12881,fd=22))
LISTEN 0  100  0.0.0.0:587  0.0.0.0:*  users:(("master",pid=12881,fd=18))
LISTEN 0  100      [::]:25     [::]:*  users:(("master",pid=12881,fd=14))
LISTEN 0  100     [::]:465     [::]:*  users:(("master",pid=12881,fd=23))
LISTEN 0  100     [::]:587     [::]:*  users:(("master",pid=12881,fd=19))

3.4. Install and Setup Dovecot to Enable IMAP

To install Dovecot, simply run:

apt install dovecot-core dovecot-imapd dovecot-lmtpd

After that, edit Dovecot configruation file /etc/dovecot/dovecot.conf to enable IMAP. Add one line:

# Enable installed protocols
protocols = imap lmtp   # Add this line
!include_try /usr/share/dovecot/protocols.d/*.protocol

Edit /etc/dovecot/conf.d/10-mail.conf to config it using the Maildir instead of mbox directory structure:

mail_location = maildir:~/Maildir   # Modify this line
mail_privileged_group = mail        # This line should be already there, just check it

After that we want to add the user dovecot to the mail group:

adduser dovecot mail

Open the /etc/dovecot/conf.d/10-master.conf file and edit the service lmtp and service auth section:

service lmtp {
  unix_listener /var/spool/postfix/private/dovecot-lmtp {
    mode = 0600
    user = postfix
    group = postfix
  }

  # Create inet listener only if you can't use the above UNIX socket
  #inet_listener lmtp {
    # Avoid making LMTP visible for the entire internet
    #address =
    #port = 
  #}
}

service auth {
  # auth_socket_path points to this userdb socket by default. It's typically
  # used by dovecot-lda, doveadm, possibly imap process, etc. Users that have
  # full permissions to this socket are able to get a list of all usernames and
  # get the results of everyone's userdb lookups.
  #
  # The default 0666 mode allows anyone to connect to the socket, but the
  # userdb lookups will succeed only if the userdb returns an "uid" field that
  # matches the caller process's UID. Also if caller's uid or gid matches the
  # socket's uid or gid the lookup succeeds. Anything else causes a failure.
  #
  # To give the caller full permissions to lookup all users, set the mode to
  # something else than 0666 and Dovecot lets the kernel enforce the
  # permissions (e.g. 0777 allows everyone full permissions).
  unix_listener /var/spool/postfix/private/auth {
    mode = 0660
    user = postfix
    group = postfix
  }

  # Postfix smtp-auth
  #unix_listener /var/spool/postfix/private/auth {
  #  mode = 0666
  #}

  # Auth process is run as this user.
  #user = $default_internal_user
}

Edit /etc/postfix/main.cf file, and add following 2 lines at the bottom of the file:

mailbox_transport = lmtp:unix:private/dovecot-lmtp
smtputf8_enable = no

Edit /etc/dovecot/conf.d/10-auth.conf file, edit multiple places:

disable_plaintext_auth = yes    # Uncomment this line
auth_username_format = %n       # Uncomment and modify this line
auth_mechanisms = plain login   # Modify this line

Edit /etc/dovecot/conf.d/10-ssl.conf, edit multiple places:

ssl = required                    # Modify this line
ssl_cert = </etc/letsencrypt/live/mail.[DOMAIN_NAME]/fullchain.pem
                                  # Modify this line
ssl_key = </etc/letsencrypt/live/mail.[DOMAIN_NAME]/privkey.pem
                                  # Modify this line
ssl_prefer_server_ciphers = yes   # Uncomment and modify this line
ssl_min_protocol = TLSv1.2        # Uncomment and modify this line

Edit /etc/ssl/openssl.cnf file, and comment one line to disable FIPS:

#providers = provider_sect   # Comment this line

Edit /etc/dovecot/conf.d/15-mailboxes.conf file, and edit it. This tells dovecot to create default folders automatically. Besides, it will also avoid to create 2 different folders for the \Sent usage (previously there are “Sent” and “Sent Messages”):

  mailbox Drafts {
    auto = create
    special_use = \Drafts
  }
  mailbox Junk {
    auto = create
    special_use = \Junk
  }
  mailbox Trash {
    auto = create
    special_use = \Trash
  }
  mailbox Sent { 
    auto = create
    special_use = \Sent
  }

And finally restart everything that I have configured:

systemctl restart postfix dovecot

And check whether dovecot is up and running:

ss -lnpt | grep dovecot

The result should be like:

LISTEN 0   100   0.0.0.0:143   0.0.0.0:*   users:(("dovecot",pid=18756,fd=36))
LISTEN 0   100   0.0.0.0:993   0.0.0.0:*   users:(("dovecot",pid=18756,fd=38))
LISTEN 0   100      [::]:143      [::]:*   users:(("dovecot",pid=18756,fd=37))
LISTEN 0   100      [::]:993      [::]:*   users:(("dovecot",pid=18756,fd=39))

4. Use MUA (Mail User Agent) to Connect to the Server

4.1. Create User for Mail

Postfix will use the system users as Email users. So create a user like this:

useradd -d /home/[UNIX_USERNAME] -s /bin/false [UNIX_USERNAME]
mkdir /home/[UNIX_USERNAME]
chown [UNIX_USERNAME]:[UNIX_USERGRP] /home/[UNIX_USERNAME]
passwd [UNIX_USERNAME]

4.2. Setup MUA

Using following data to setup the Mail Client:

Name: [MAIL_NAME]
EMail Address: [UNIX_USERNAME]@[DOMAIN_NAME]

# IMAP Mail Server
Host: mail.[DOMAIN_NAME]
Port: 143
User Name: [UNIX_USERNAME]
Security: STARTTLS
Authentication Method: Normal password

# SMTP Server
Host: mail.[DOMAIN_NAME]
Port: 587
User Name: [UNIX_USERNAME]
Security: STARTTLS
Authentication Method: Normal password

5. Setup SPF

SPF or DKIM is a way to verify the ownership of the mail server, so that some famous mail service provider can ensure that our mail server is not a spammer. Since SPF is easier than DKIM, I have only setup SPF.

To do this, simply add a DNS record:

HOSTNAME        TTL   TYPE   PRIO   VALUE
[DOMAIN_NAME]   A                   v=spf1 mx ~all

And it is done.