Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 53

Exploring the World of Personal Email Servers

If you would like to have your own email server, this is the right place for a tutorial,
based on the steps below I managed to create a working Email Server and learn a lot
of how it works in the backend.

I understand that this may appear as a challenging undertaking. Nonetheless,


depending on your specific goals, you may find that not all steps need to be
followed.

Hope you learn something from this as I did.

A list with all the points that need to be touched in order for the server
to be operational.

1. Setting up a basic Postfix SMTP server


2. Set up Dovecot IMAP server and TLS encryption
3. Create Virtual Mailboxes with PostfixAdmin (MariaDB/MySQL, PostgreSQL)
4. Creating SPF and DKIM record to get through spam filters
5. Setting Up DMARC to protect your domain reputation
6. 7 Effective Tips to Stop Your Email From Being Marked as Spam
7. Install Roundcube Webmail on Ubuntu (MySQL/MariaDB, PostgreSQL)
8. How to Host Multiple Mail Domains in PostfixAdmin
9. Blocking Email Spam with Postfix
10. Blocking Email Spam with SpamAssassin
11. Setting Up Amavis and ClamAV on Ubuntu Mail Server
12. How to Secure Email Server Against Hacking with Self-hosted VPN Server
13. How to Bypass Email Blacklists
14. (optional) Enable and Configure Postscreen in Postfix to Block Spambots
15. Automatic IP and Domain Warm-up For Your Email Server

In this post I will exaplain the first step from this list.

Postfix History:

Postfix stands as a cutting-edge message transport agent (MTA), commonly referred


to as an SMTP server, and serves dual roles.

Firstly, it facilitates the transfer of email messages from a mail client or mail user
agent (MUA) to a remote SMTP server.

Secondly, it functions to receive emails from other SMTP servers.

Developed by Unix and security expert Wietse Venema, Postfix is not only user-
friendly but also meticulously crafted with a focus on security and modularity. Each
module operates at the minimum privilege level necessary to fulfill its function.
Postfix seamlessly integrates with Unix/Linux systems, abstaining from duplicating
functionalities already present in Unix/Linux. It exhibits reliability under various
conditions, whether simple or challenging.

Originally conceived as a superior alternative to Sendmail, the traditional SMTP


server on Unix, Postfix surpasses it in terms of security and ease of configuration.
Notably, it maintains compatibility with Sendmail. Thus, by uninstalling Sendmail and
adopting Postfix, your existing scripts and programs will seamlessly persist.

This tutorial is dedicated to guiding you through the configuration of Postfix for a
single domain.

Choosing the Right Hosting Provider for your email server

Discovering a suitable VPS (Virtual Private Server) provider for email hosting can be a
challenging task. Numerous hosting companies, often impose restrictions such as
blocking port 25. Consequently, users resort to setting up SMTP relays to circumvent
this block, incurring additional costs.

You can use Kamatera VPS, as a standout choice for hosting mail servers due to
several key advantages:

1. Unrestricted Port 25: Kamatera doesn't block port 25, eliminating the need for
complex workarounds.

2. Clean IP Address: Kamatera's IP addresses are not listed on any email blacklist,
providing assurance against potential deliverability issues.

3. PTR Record Editing: Users can edit PTR records, enhancing email deliverability
and avoiding potential blacklistings.

4. No Newsletter Limits: Kamatera imposes no hourly or daily limits on sending


newsletters to subscribers, provided it complies with anti-spam policies. Permission-
based email practices are emphasized.

5. Multiple IP Addresses: Users can order multiple IP addresses for a single server,
facilitating the distribution of email traffic across multiple IPs for improved
deliverability.

I personaly have used AWS with a combination of a domain from cloudns.ph so my


email server was completely free as that was the goal that I was aiming for this being
just a personal project.
Things To Do Before Installing Postfix

To make Postfix perform better and get the most out of Postfix, you need to properly
set up your Ubuntu server.

Set A Correct Hostname for Ubuntu Server

In its default configuration, Postfix employs your server's hostname to establish its
identity during interactions with other Message Transfer Agents (MTAs). Hostnames
come in two forms: a single word and a Fully Qualified Domain Name (FQDN).

The single-word form is prevalent on personal computers, often naming Linux home
computers as "linux", "debian", "ubuntu", and the like. On Internet-facing servers,
it is recommended to utilize FQDN on mail servers. FQDN comprises two
components: a node name and a domain name. For example:

mail.yourdomain.com

mail is the nodename, yourdomain.com is the domain name. FQDNs will appear in
the smtpd banner. Some MTAs reject messages if your Postfix does not provide
FQDN in smtpd banner. Some MTAs even query DNS to see if FQDN in the smtpd
banner resolves to the IP of your mail server.

Enter the following command to see the FQDN form of your hostname.

hostname -f

If your Ubuntu server doesn’t have an FQDN yet, you can use "hostnamectl" to set
one.

sudo hostnamectl set-hostname your-FQDN-here

A common FQDN for mail server is mail.yourdomain.com. as the example provided


above. I would recommend a reboot after this change.

Set Up DNS Records for Your Mail Server

You will need to go to your DNS hosting service (usually your domain register like
NameCheap, GoDaddy, AWS Route53) to set up DNS records
MX record

An MX record tells other MTAs that your mail server mail.yourdomain.com is


responsible for email delivery for your domain name.

MX record @ mail.yourdomain.com

Again a common name for the MX host is mail.yourdomain.com. You can specify
more than one MX record and set priority for your mail servers. A lower number
means higher priority. Here we only use one MX record and set 0 as the priority
value. (values can range from 0 – 65535)

Note that when you create the MX record, you should enter @ or your apex domain
name in the name field. An apex domain name is a domain name without any sub-
domain.

A record

An A record maps an FQDN to an IP address.


The format should be:
mail.yourdomain.com your_server_public_ipv4_address_here

PTR record

A Pointer Record, commonly known as a PTR record, establishes a mapping between


an IP address and a Fully Qualified Domain Name (FQDN). It functions as the
counterpart to the A record and is integral to the process of reverse DNS (rDNS)
lookup.

Employing a PTR record for the reverse resolution of an IP address can be


instrumental in combating spam. Numerous Mail Transfer Agents (MTAs) stipulate
that email acceptance is contingent upon the server being genuinely responsible for
a specific domain. It is highly advisable to configure a PTR record for your email
server to enhance the likelihood of your emails being delivered to the recipient's
inbox rather than being relegated to the spam folder.

To examine the PTR record associated with an IP address, utilize the following
command:

dig -x enter_ip_here +short

or

host enter_ip_here

The PTR record is not under the purview of your domain registrar; rather, it is
overseen by the entity that assigns your IP address. IP addresses are allocated by
your hosting provider, not your domain registrar. Consequently, it becomes
imperative to configure the PTR record for your IP address within your hosting
provider's control panel. The designated value for this PTR record should align with
your mail server's hostname, typically formatted as mail.your-domain.com.

A noteworthy point: Gmail conducts a check on the A record of the hostname


specified in the PTR record. Gmail will only accept your email if the hostname
resolves to the same IP address; otherwise, the email will be rejected.

Once the aforementioned steps are completed, we can proceed to configure Postfix.

Installing Postfix

On your ubuntu server, run the following two commands.

sudo apt-get update


sudo apt-get install postfix -y

You will be asked to select a type for mail configuration. Normally, you will want to
select the second type: Internet Site.

 No configuration: means the installation process will not configure any parameters.
 Internet Site: means using Postfix for sending emails to other MTAs and receiving
email from other MTAs.
 Internet with smarthost: means using postfix to receive email from other MTAs, but
using another smart host to relay emails to the recipient.
 Satellite system: means using smart host for sending and receiving email.
 Local only: means emails are transmitted only between local user accounts.

Next, enter your domain name for the system mail name, i.e. the domain name after
@ symbol. For example, my email address is szaky@szkcorp.cloudns.ph, so I entered
szkcorp.cloudns.ph for the system mail name. You should enter - yourdomain.com
(this is an example). This domain name will be appended to addresses that don’t
have a domain name specified.

Note: that if you enter a sub-domain like mail.your-domain.com, you will be able to
receive emails destined for @mail.your-domain.com addresses, but not be able to
receive emails destined for @your-domain.com addresses so be carefull.

Once installed, Postfix will be automatically started and a /etc/postfix/main.cf file will
be generated. Now we can check Postfix version with this command:

postconf mail_version

On Ubuntu 22.04, the Postfix version is 3.6.4, and Ubuntu 20.04 ships with version
3.4.10.

mail_version = 3.6.4
The ss (Socket Statistics) utility tells us that the Postfix master process is listening on
TCP port 25.

sudo ss -lnpt | grep master

Postfix ships with many binaries under the /usr/sbin/ directory, as can be seen with
the following command.

dpkg -L postfix | grep /usr/sbin/

Output:

/usr/sbin/postalias
/usr/sbin/postcat
/usr/sbin/postconf
/usr/sbin/postdrop
/usr/sbin/postfix
/usr/sbin/postfix-add-filter
/usr/sbin/postfix-add-policy
/usr/sbin/postkick
/usr/sbin/postlock
/usr/sbin/postlog
/usr/sbin/postmap
/usr/sbin/postmulti
/usr/sbin/postqueue
/usr/sbin/postsuper
/usr/sbin/posttls-finger
/usr/sbin/qmqp-sink
/usr/sbin/qmqp-source
/usr/sbin/qshape
/usr/sbin/rmail
/usr/sbin/sendmail
/usr/sbin/smtp-sink
/usr/sbin/smtp-source

Open TCP Port 25 (inbound) in Firewall

The inbound TCP port 25 needs to be open, so Postfix can receive emails from other
SMTP servers. Ubuntu doesn’t enable a firewall by default. If you have enabled the
UFW firewall, you need to open port 25 (inbound) with the following command.

sudo ufw allow 25/tcp

Then we can scan open ports on the mail server with an online port scanner. Enter
your mail server’s public IP address and select scan all common ports.
You can see from the above screenshot that TCP port 25 is open on my mail server.

Checking If TCP Port 25 (outbound) is blocked

The outbound TCP port 25 needs to be open, so Postfix can send emails to other
SMTP servers. The outbound TCP port 25 is controlled by your hosting provider, we
can install the telnet utility to check if it’s open or blocked.

sudo apt install telnet

Run the following command on your mail server.

telnet gmail-smtp-in.l.google.com 25

If it’s not blocked, you would see messages like below, which indicates a connection
is successfully established. (Hint: Type in quit and press Enter to close the
connection.)

Trying 74.125.68.26...
Connected to gmail-smtp-in.l.google.com.
Escape character is '^]'.
220 mx.google.com ESMTP y22si1641751pll.208 - gsmtp

If port 25 (outbound) is blocked, you would see something like:


Trying 2607:f8b0:400e:c06::1a...
Trying 74.125.195.27...
telnet: Unable to connect to remote host: Connection timed out

In such a scenario, your Postfix faces a limitation in sending emails to other SMTP
servers. It becomes necessary to liaise with your Internet Service Provider (ISP) or
hosting provider and request the opening of the outbound port 25. Should your
request be denied, you have alternative options: either establish an SMTP relay to
circumvent the port 25 block or opt for a VPS solution, which does not impose
restrictions on port 25. ( I went with the SMTP relay in the end)

A common question will arise: "Can I change port 25 to another port to bypass
blocking?" The answer is no. Port changes are effective only when you have control
over both the server-side and client-side. In the context of Postfix sending emails, it
functions as the SMTP client, while the recipient's mail server operates as the SMTP
server. Since you lack control over the recipient's SMTP server, altering the port is not
a feasible solution. SMTP servers are designed to listen on port 25 for email
reception, and this standard expectation cannot be altered. Failure to connect to port
25 of the recipient's SMTP server will impede your ability to send emails.

Sending Test Email

As a matter of fact, we can now send and receive email from the command line. If
your Ubuntu server has a user account called user1, then the email address for this
user is user1@yourdomain.com. You can send an email to root user
root@yourdomain.com. You can also send emails to Gmail, yahoo mail or any other
email service.

When installing Postfix, a sendmail binary is placed at /usr/sbin/sendmail, which is


compatible with the traditional Sendmail SMTP server. You can use Postfix’s sendmail
binary to send a test email to your Gmail account like this:

echo "test email" | sendmail your-account@gmail.com

In this simple command, sendmail reads a message from standard input and make
“test email” as the message body, then send this message to your Gmail account.
You should be able to receive this test email in your Gmail inbox (or spam folder).
You can see that although we didn’t specify the from address, Postfix automatically
append a domain name for the from address. That’s because we added our domain
name in system mail name when installing Postfix.

Note: The From: domain name is determined by the myorigin parameter in Postfix,
not by the myhostname parameter.
You can try to reply to this test email to see if Postfix can receive email messages. It’s
likely that emails sent from your domain are labeled as spam. Don’t worry about it
now. We will solve this problem in later parts of this tutorial series.

The inbox for each user is located at /var/spool/mail/<username> or


/var/mail/<username> file. If you are unsure where to look for the inbox, use this
command.

postconf mail_spool_directory

The Postfix mail log is stored at /var/log/mail.log.

Still Can’t Send Email?

If port 25 (outbound) is not blocked, but you still can’t send emails from your own
mail server to your other email address like Gmail, then you should open the mail log
(/var/log/mail.log) with a command-line text editor, such as Nano.

sudo nano /var/log/mail.log

For example, some folks might see the following lines in the file.

host gmail-smtp-in.l.google.com[2404:6800:4003:c03::1b] said: 550-5.7.1


[2a0d:7c40:3000:b8b::2] Our system has detected that 550-5.7.1 this message does not meet
IPv6 sending guidelines regarding PTR 550-5.7.1 records and authentication. Please review
550-5.7.1 https://support.google.com/mail/?p=IPv6AuthError for more information

This means your mail server is using IPv6 to send the email, but you didn’t set up
IPv6 records. You should go to your DNS manager, set AAAA record for mail.your-
domain.com, then you should also set PTR record for your IPv6 address. (PTR record
is managed by the organization that gives you an IP address.)

To save a file in Nano text editor, press Ctrl+O, then press Enter to confirm. To exit,
press Ctrl+X.

Using the mail program to Send and Read Email

Now let’s install a command-line MUA (mail user agent).

sudo apt-get install mailutils

To send email, type

mail -a FROM:your-account@yourdomain.com username@gmail.com

user@mail:~$ mail -a FROM:xiao@linuxbabe.com username@gmail.com


Cc:
Subject: 2nd test email
I'm sending this email using the mail program.

Enter the subject line and the body text. To tell mail that you have finished writing,
press Ctrl+D and mail will send this email message for you.

To read incoming emails, just type mail.

mail

Here’s how to use the mail program to manage your mailbox.

 To read the first email message, type 1. If only parts of the message is displayed,
press Enter to show the remaining part of the message.
 To display message headers starting from message 1, type h.
 To show the last screenful of messages, type h$ or z.
 To read the next email message, type n.
 To delete message 1, type d 1.
 To delete message 1, 2 and 3, type d 1 2 3.
 To delete messages from 1 to 10, type d 1-10.
 To replay to message 1, type reply 1.
 To exit out of mail, type q.

Messages that have been opened will be moved from /var/mail/<username> to


/home/<username>/mbox file. That means other mail clients can’t read those
messages. To prevent this from happening, type x instead of q to exit out of the mail.

How To Increase Attachment Size Limit

By default, the attachment cannot be larger than 10MB, which is indicated by the
message_size_limit parameter.

postconf | grep message_size_limit

Output:

message_size_limit = 10240000

This parameter defines the size limit for emails originating from your own mail server
and for emails coming to your mail server.

To allow attachment of 50MB in size, run the following command.

sudo postconf -e message_size_limit=52428800


When postconf command is invoked with the -e (edit) option, it will try to find the
parameter (message_size_limit) in the Postfix main configuration file
(/etc/postfix/main.cf) and change the value. If the parameter can’t be found, then it
adds the parameter at the end of the file.

Note that the message_size_limit should not be larger than the mailbox_size_limit,
otherwise Postfix might not be able to receive emails. The default value of
mailbox_size_limit is 51200000 bytes (about 48MB) in the upstream Postfix package.
On Ubuntu, the default value is set to 0, as can be seen with

postconf | grep mailbox_size_limit

Output:

mailbox_size_limit = 0

This means that the mailbox has no size limit, which is great.

Restart Postfix for the changes to take effect.

sudo systemctl restart postfix

When sending an email with large attachments from your mail server, you should
also beware of the receiving server’s attachment size limit. For example, You will not
be able to send an attachment larger than 25MB to a Gmail address.

Setting the Postfix Hostname

By default, Postfix SMTP server uses the OS’s hostname. However, the OS hostname
might change, so it’s a good practice to set the hostname directly in Postfix
configuration file. Open the Postfix main configuration file with a command-line text
editor, such as Nano.

sudo nano /etc/postfix/main.cf

Find the myhostname parameter and set mail.yourdomain.com as the value. It’s not
recommended to use the apex domain yourdomain.com as myhostname. Technically
you can use the apex domain, but it will create problems in later parts of this tutorial
series.

myhostname = mail.yourdomain.com

Save and close the file. (To save a file in Nano text editor, press Ctrl+O, then press
Enter to confirm. To exit, press Ctrl+X.) Restart Postfix for the change to take effect.

sudo systemctl restart postfix


Creating Email Alias

There are certain required aliases that you should configure when operating your
mail server in a production environment. You can add email alias in the /etc/aliases
file, which is a special Postfix lookup table file using a Sendmail-compatible format.

sudo nano /etc/aliases

By default, there are only two lines in this file.

# See man 5 aliases for format


postmaster: root

The first line is a comment. The second line is the only definition of an alias in this
file. The left-hand side is the alias name. The right-hand side is the final destination
of the email message. So emails for postmaster@your-domain.com will be delivered
to root@your-domain.com. The postmaster email address is required by RFC 2142.

Normally we don’t use the root email address. Instead, the postmaster can use a
normal login name to access emails. So you can add the following line. Replace
username with your real username.

root: username

This way, emails for postmaster@your-domain.com will be delivered to


username@your-domain.com. Now you can save and close the file. Then rebuild the
alias database with the newaliases command

sudo newaliases

Using IPv4 Only

By default, Postfix uses both IPv4 and IPv6 protocols, as can been seen with:

postconf inet_protocols

Output:

inet_protocols = all

If your mail server doesn’t have a public IPv6 address, it’s better to disable IPv6 in
Postfix to prevent unnecessary IPv6 connections. Simply run the following command
to disable IPv6 in Postfix.

sudo postconf -e "inet_protocols = ipv4"


Then restart Postfix.

sudo systemctl restart postfix

Upgrading Postfix

If you run sudo apt update, then sudo apt upgrade, and the system is going to
upgrade Postfix, you might be prompted to choose a configuration type for Postfix
again. This time you should choose No configuration to leave your current
configuration file untouched.

Congrats if you followed all steps until now. Now you have a basic Postfix email
server up and running. You can send plain text emails and read incoming emails
using the command line.

In the next part of this tutorial series, we will learn how to install Dovecot IMAP server
and enable TLS encryption, which will allow us to use a desktop mail client like
Mozilla Thunderbird to send and receive emails.
Welcome to part 2 of our tutorial series on building a secure email server from
scratch on Ubuntu. In part 1, we guided you through the setup of a fundamental
Postfix SMTP server. In this installment, our focus shifts to configuring the email
server for seamless sending and receiving through desktop email clients like Mozilla
Thunderbird or Microsoft Outlook.

Enabling the ability to send emails via a desktop client involves activating the
submission service in Postfix. On the receiving end, we'll install Dovecot, an open-
source IMAP server, on your Ubuntu server to facilitate the retrieval of emails using
a desktop email client. Ensuring the security of our communications, we'll also delve
into the installation of a TLS certificate. Let's dive in!

Open Ports in Firewall

Ubuntu doesn’t enable firewall by default. If you have enabled the UFW firewall, then
you need to run the following command to open email related ports in firewall.

sudo ufw allow 80,443,587,465,143,993/tcp

If you use POP3 to fetch emails (I personally don’t), then also open port 110 and 995

sudo ufw allow 110,995/tcp

Securing Email Server Traffic with TLS Certificate

When we configure our desktop email clients, It’s always a good idea to enable TLS
encryption to prevent hackers from snooping on our emails. We can easily obtain a
free TLS certificate from Let’s Encrypt. Issue the following commands to install Let’s
Encrypt client (certbot) on Ubuntu server from the default software repository.

sudo apt update

sudo apt dist-upgrade

sudo apt install certbot

If you don’t have a web server running yet, I recommend you install one (Apache or
Nginx), because it’s easier to obtain and install TLS certificate with a web server than
using other methods. And in a later tutorial, I will show you how to set up webmail,
which requires running a web server.
If you use Nginx web server, then install the Nginx plugin. (The following command
will install Nginx web server if it’s not already installed on your system.)

sudo apt install python3-certbot-nginx


Obtaining TLS Certificate with Nginx Web Server

You need to have an Nginx virtual host for mail.your-domain.com before obtaining
Let’s Encrypt TLS certificate. Create the virtual host file:

sudo nano /etc/nginx/conf.d/mail.your-domain.com.conf

Next, paste the following text into the file.

server {
listen 80;
listen [::]:80;
server_name mail.your-domain.com;

root /usr/share/nginx/html/;

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

Save and close the file. Make sure the /usr/share/nginx/html/ directory exists on your
server.

sudo mkdir -p /usr/share/nginx/html/

Reload Nginx for the changes to take effect.

sudo systemctl reload nginx

Once the virtual host is created and enabled, run the following command to obtain
Let’s Encrypt certificate with Nginx plugin.

sudo certbot certonly -a nginx --agree-tos --no-eff-email --staple-ocsp --email


you@example.com -d mail.your-domain.com

Where:

 -a nginx: Use the Nginx plugin for authentication


 --agree-tos: Agree to terms of service.
 --no-eff-email: Don’t receive emails from EFF foundation.
 --staple-ocsp: Enables OCSP Stapling. A valid OCSP response is stapled to the
certificate that the server offers during TLS.
 --email: Enter your email address, which is used for important notifications and
account recovery.
 -d: domain, aka your mail server hostname.
You should see the following which means the certificate is successfully obtained.
You can also see the directory under which your cert is stored.

Enable Submission Service in Postfix

To send emails from a desktop email client, we need to enable the submission
service of Postfix so that the email client can submit emails to Postfix SMTP server.
Edit the master.cf file.

sudo nano /etc/postfix/master.cf

In submission section, uncomment or add the following lines. Please allow at least
one whitespace (tab or spacebar) before -o. In postfix configurations, a preceding
whitespace character means that this line is continuation of the previous line. (By
default the submission section is commented out. You can copy the following lines
and paste them into the file, so you don’t have to manually uncomment or add new
text.)

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
The above configuration enables the submission daemon of Postfix and requires TLS
encryption. So later on our desktop email client can connect to the submission
daemon in TLS encryption. The submission daemon listens on TCP port 587.
STARTTLS is used to encrypt communications between email client and the
submission daemon.

Microsoft Outlook mail client only supports submission over port 465. If you are
going to use Microsoft Outlook, then you also need to enable submission service on
port 465 by adding the following lines in the file.

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
Save and close the file.

Hint: The SMTP protocol is used when an email client submits emails to an SMTP
server.

Next, we need to specify the location of TLS certificate and private key in Postfix
configuration file. Edit main.cf file

sudo nano /etc/postfix/main.cf

Edit the TLS parameter as follows. Remember to replace mail.your-domain.com


with your real hostname.

#Enable TLS Encryption when Postfix receives incoming emails


smtpd_tls_cert_file=/etc/letsencrypt/live/mail.your-domain.com/fullchain.pem
smtpd_tls_key_file=/etc/letsencrypt/live/mail.your-domain.com/privkey.pem
smtpd_tls_security_level=may
smtpd_tls_loglevel = 1
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache

#Enable TLS Encryption when Postfix sends outgoing emails


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

#Enforce TLSv1.3 or TLSv1.2


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

Your Let’s Encrypt certificate and private key are stored under
/etc/letsencrypt/live/mail.your-domain.com/ directory.
Save and close the file. Then restart Postfix.

sudo systemctl restart postfix

If you run the following command, you will see Postfix is now listening on port 587
and 465.

sudo ss -lnpt | grep master

Installing Dovecot IMAP Server

Enter the following command to install Dovecot core package and the IMAP daemon
package on Ubuntu server.

sudo apt install dovecot-core dovecot-imapd

If you use POP3 to fetch emails, then also install the dovecot-pop3d package.

sudo apt install dovecot-pop3d

Check Dovecot version:

dovecot –version

Sample output:

2.3.16 (7e2e900c1a)

Enabling IMAP/POP3 Protocol

Edit the main config file.

sudo nano /etc/dovecot/dovecot.conf

Add the following line to enable IMAP protocol.

protocols = imap
If you use POP3 to fetch emails, then also add POP3 protocol.

protocols = imap pop3

Save and close the file.

Configuring Mailbox Location

By default, Postfix and Dovecot use mbox format to store emails. Each user’s emails
are stored in a single file /var/mail/username. You can run the following command to
find the mail spool directory.

postconf mail_spool_directory

Sample output:

mail_spool_directory = /var/mail

However, nowadays it’s almost always you want to use the Maildir format to store
email messages. The config file for mailbox location is /etc/dovecot/conf.d/10-
mail.conf.

sudo nano /etc/dovecot/conf.d/10-mail.conf

The default configuration uses mbox mail format.

mail_location = mbox:~/mail:INBOX=/var/mail/%u

Change it to the following to make Dovecot use the Maildir format. Email messages
will be stored under the Maildir directory under each user’s home directory.

mail_location = maildir:~/Maildir

We need to add the following line in the file. (On Ubuntu 18.04 and 20.04, this line is
already in the file.)

mail_privileged_group = mail

Save and close the file. Then add dovecot to the mail group so that Dovecot can read
the INBOX.

sudo adduser dovecot mail

Using Dovecot to Deliver Email to Message Store


Although we configured Dovecot to store emails in Maildir format, by default, Postfix
uses its built-in local delivery agent (LDA) to move inbound emails to the message
store (inbox, sent, trash, Junk, etc), and it will be saved in mbox format.

We need to configure Postfix to pass incoming emails to Dovecot, via the LMTP
protocol, which is a simplified version of SMTP, so incoming emails will saved in
Maildir format by Dovecot. LMTP allows for a highly scalable and reliable mail
system. It also allows us to use the sieve plugin to filter inbound messages to
different folders.

Install the Dovecot LMTP Server.

sudo apt install dovecot-lmtpd

Edit the Dovecot main configuration file.

sudo nano /etc/dovecot/dovecot.conf

Add lmtp to the supported protocols.

protocols = imap lmtp

Save and close the file. Then edit the Dovecot 10-master.conf file.

sudo nano /etc/dovecot/conf.d/10-master.conf

Change the lmtp service definition to the following.

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

Next, edit the Postfix main configuration file.

sudo nano /etc/postfix/main.cf


Add the following lines at the end of the file. The first line tells Postfix to deliver
incoming emails to local message store via the Dovecot LMTP server. The second
line disables SMTPUTF8 in Postfix, because Dovecot-LMTP doesn’t support this email
extension.

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

Save and close the file.

Configuring Authentication Mechanism

Edit the authentication config file.

sudo nano /etc/dovecot/conf.d/10-auth.conf

Uncomment the following line.

disable_plaintext_auth = yes

It will disable plaintext authentication when there’s no SSL/TLS encryption. Then find
the following line,

#auth_username_format = %Lu

Uncomment it and change its value to %n.

auth_username_format = %n

By default, when Dovecot tries to find or deliver emails for a user, it uses the full
email address. Since in this part, we only set up canonical mailbox users (using OS
users as mailbox users), Dovecot can’t find the mailbox user in full domain format
(username@your-domain.com), so we need to set auth_username_format = %n to
drop the domain part, then Dovecot should be able to find the mailbox user. This
also allows us to use the full email address (username@your-domain.com) to log in.

Next, find the following line.

auth_mechanisms = plain
This line only enables the PLAIN authentication mechanism. LOGIN is another
authentication mechanism you probably want to add to support older email clients.

auth_mechanisms = plain login

Save and close the file.

Configuring SSL/TLS Encryption

Next, edit SSL/TLS config file.

sudo nano /etc/dovecot/conf.d/10-ssl.conf

Change ssl = yes to ssl = required to enforce encryption.

ssl = required

Then find the following lines.

ssl_cert = </etc/dovecot/private/dovecot.pem
ssl_key = </etc/dovecot/private/dovecot.key

By default, Dovecot uses a self-signed TLS certificate. Replace them with the
following values, which specify the location of your Let’s Encrypt TLS certificate and
private key. Don’t leave out the < character. It’s necessary.

ssl_cert = </etc/letsencrypt/live/mail.your-domain.com/fullchain.pem
ssl_key = </etc/letsencrypt/live/mail.your-domain.com/privkey.pem

Find the following line.

#ssl_prefer_server_ciphers = no

It’s a good practice to prefer the server’s order of ciphers over client’s. So
uncomment this line and change the value to yes.
ssl_prefer_server_ciphers = yes
If you use Ubuntu 20.04 or Ubuntu 22.04, disable insecure SSLv3, TLSv1 and TLSv1.1 by adding the
following line.

ssl_min_protocol = TLSv1.2

If you are using Dovecot version 2.2.x (as in Ubuntu 18.04), you should add the
following line to disable insecure TLS.
ssl_protocols = !SSLv3 !TLSv1 !TLSv1.1

Save and close the file.

Disable the FIPS Providers in OpenSSL on Ubuntu 22.04

Ubuntu 22.04 ships with OpenSSL 3.0, which features a FIPS provider. However, it
won’t work with Dovecot. We need to diable the FIPS provider.

sudo nano /etc/ssl/openssl.cnf

Find the following line (line 54).

providers = provider_sect

Add a # character to comment it out.

#providers = provider_sect

Save and close the file.

If you don’t disable the FIPS provider in OpenSSL, Dovecot would produce the
following error.

imap-login: Error: Failed to initialize SSL server context: Can't load SSL certificate:
error:25066067:DSO support routines:dlfcn_load:could not load the shared library:
filename(libproviders.so)

Configuring SASL Authentication

Edit the following file.

sudo nano /etc/dovecot/conf.d/10-master.conf


Change service auth section to the following so that Postfix can find the Dovecot authentication
server. Please be careful about the syntax. Every opening bracket should be terminated by a closing
bracket.
service auth {
unix_listener /var/spool/postfix/private/auth {
mode = 0660
user = postfix
group = postfix
}
}
Save and close the file.

Auto-create Sent and Trash Folder

Edit the below config file.

sudo nano /etc/dovecot/conf.d/15-mailboxes.conf

To auto-create a folder, simply add the following line in the mailbox section.

auto = create

Example:

mailbox Trash {
auto = create
special_use = \Trash
}

Some common folders you will want to create includes: Drafts, Junk, Trash and
Sent. The Sent folder will be created under the user’s home directory when the user
send the first email. The Trash folder will be created when the user deletes an email
for the first time, etc. After you save and close all above config files, restart Postfix
and Dovecot.

sudo systemctl restart postfix dovecot

Dovecot will be listening on port 143 (IMAP) and 993 (IMAPS), as can be seen
with:

sudo ss -lnpt | grep dovecot

If there’s a configuration error, dovecot will fail to restart, so it’s a good idea to check
if Dovecot is running with the following command.

systemctl status dovecot

Configure Desktop Email Client

Now open up your desktop email client such as Mozilla Thunderbird. Go to Edit ->
Account Settings -> Account Actions -> Add Mail Account to add a mail account.

 In the incoming server section, select IMAP protocol, enter mail.your-domain.com as


the server name, choose port 143 and STARTTLS. Choose normal password as the
authentication method.
 In the outgoing section, select SMTP protocol, enter mail.your-domain.com as the
server name, choose port 587 and STARTTLS. Choose normal password as the
authentication method.
 Hint 1: You can also use port 993 with SSL/TLS encryption for IMAP,
and use port 465 with SSL/TLS encryption for SMTP. You should NOT
use port 25 as the SMTP port in mail clients to submit outgoing emails.
 Hint 2: If you use Microsoft 365 Outlook email client, then you
shouldn’t enable Secure Password Authentication (SPA), which is a
proprietary Microsoft protocol. Your password is already encrypted by
TLS.

You should now be able to connect to your own email server and also send and
receive emails with your desktop email client!

We use local Unix accounts as email addresses, as we did in part 1. For example, if
you have a user called user1 on your Ubuntu server, then you have an email address:
user1@your-domain.com, and the password for the email address is the same
password for the user1 user. To create a local Unix account, run

sudo adduser user1


Note: Dovecot doesn’t allow you to log in with the root account. You need to create
separate user accounts.

You can list all available mailbox users with:

sudo doveadm user '*'

It’s recommended to restart Dovecot after adding users, so Dovecot can recognize
new mailbox users.

sudo systemctl restart dovecot

Troubleshooting Tips

As a rule of thumb, you should always check the mail log (/var/log/mail.log) on
your mail server when an error happens. The following is a list of specific errors and
troubleshooting tips.

Can’t login from Mail Clients

If you can’t log into your mail server from a desktop mail client, scan your mail server
to find if the ports (TCP 587, 465, 143, and 993) are open. Note that you should run
the following command from another Linux computer or server. If you run it on your
mail server, then the ports will always appear to be open.

sudo nmap mail.your-domain.com

And check if Dovecot is running.

systemctl status dovecot

You can also check the mail log (/var/log/mail.log), which may give you some clues. If
Dovecot fails to start, the error might not be logged to the /var/log/mail.log file, you
can run the following command to see what’s wrong.

sudo journalctl -eu dovecot

For example, some folks may have the following error in the journal.

doveconf: Fatal: Error in configuration file /etc/dovecot/conf.d/10-master.conf line 78:


Unknown setting

Most of the time, it’s a simple syntax error, like a missing curly bracket. Open the
configuration file, go to the specified line and fix the error.
If you find the following error message in the mail log

imap-login: Error: Failed to initialize SSL server context: Can't load DH parameters:
error:1408518A:SSL routines:ssl3_ctx_ctrl:dh key too small

Then open the Dovecot TLS configuration file.

sudo nano /etc/dovecot/conf.d/10-ssl.conf

Add the following line in this file.

ssl_dh = </etc/dovecot/dh.pem

Save and close the file. Then generate the DH parameter file with:

sudo openssl dhparam -out /etc/dovecot/dh.pem 4096

Restart Dovecot for the changes to take effect.

Auto-Renew TLS Certificate

You can create Cron job to automatically renew TLS certificate. Simply open root
user’s crontab file.

sudo crontab -e

If you are using Nginx web server, then add the following line.

@daily certbot renew --quiet && systemctl reload postfix dovecot nginx

Reloading Postfix, Dovecot and the web server is necessary to make these programs
pick up the new certificate and private key.

Dovecot Automatic Restart

If for any reason your Dovecot process is killed, you need to run the following
command to restart it.

sudo systemctl restart dovecot

Instead of manually typing this command, we can make Dovecot automatically


restart by editing the dovecot.service systemd service unit. To override the default
systemd service configuration, we create a separate directory .

sudo mkdir -p /etc/systemd/system/dovecot.service.d/


Then create a file under this directory.

sudo nano /etc/systemd/system/dovecot.service.d/restart.conf

Add the following lines in the file, which will make Dovecot automatically restart 5
seconds after a failure is detected.

[Service]
Restart=always
RestartSec=5s

Save and close the file. Then reload systemd for the changes to take effect.

sudo systemctl daemon-reload

To check if this would work, kill Dovecot with:

sudo pkill dovecot

Then check Dovecot status. You will find Dovecot automatically restarted.

systemctl status dovecot

In previous articles, we discussed how to set up your own mail server on Ubuntu
from scratch. In part 1 and part 2 of this tutorial series, we learned how to set up
Postfix SMTP server and Dovecot IMAP server, but so far we can only have email
addresses for users with local Unix accounts. This tutorial is going to show you how
to create virtual mailboxes on Ubuntu mail server with PostfixAdmin, which is an
open-source web-based interface to configure and manage a Postfix-based email
server for many domains and users.

With virtual mailboxes, we don’t need to create a local Unix account for each email
address. If you are going to set up a mail server for a company or organization, it’s
always better to have an easy way to create virtual mailboxes in a web-based
interface, which also allows users to change their passwords. That’s where
PostfixAdmin comes in.

PostfixAdmin Features

 manage mailboxes, virtual domains, and aliases


 vacation/out-of-office messages (Personally I think it’s better done in Roundcube
webmail)
 alias domains (forwarding one domain to another with recipient validation)
 users can manage their own mailbox (change alias, password and vacation message)
 quota support for single mailboxes and total quota of a domain
 fetchmail integration: You can fetch emails from your original email address to your
new email address.
 command-line client postfixadmin-cli for those who don’t want to click around in a

web interface 😉

Note

 This tutorial works on Ubuntu 22.04, Ubuntu 20.04, and Ubuntu 18.04.
 This tutorial uses MariaDB/MySQL database server.
 Once you finish part 3, you can no longer use local Unix accounts as email addresses.
You must create email addresses from the PostfixAdmin web interface.

Prerequisites

It’s required that you have followed part 1 and part 2 of this tutorial series before
continuing to read this article.

Once the above requirements are met, let’s install and configure PostfixAdmin.

Step 1: Install MariaDB/MySQL Database Server

PostfixAdmin is written in PHP and requires a database (MySQL/MariaDB,


PostgreSQL or SQLite). This article will use MariaDB database, which is a drop-in
replacement for MySQL. It is developed by former members of MySQL team who are
concerned that Oracle might turn MySQL into a closed-source product. Enter the
following command to install MariaDB on Ubuntu.

sudo apt install mariadb-server mariadb-client

Hint: If you prefer to use MySQL, you can install it with: sudo apt install mysql-
server-8.0.

After it’s installed, MariaDB server should be automatically started. Use systemctl to
check its status.

systemctl status mariadb

Output:

● mariadb.service - MariaDB 10.3.22 database server


Loaded: loaded (/lib/systemd/system/mariadb.service; enabled; vendor preset: enabled)
Active: active (running) since Fri 2020-04-10 14:19:16 UTC; 18s ago
Docs: man:mysqld(8)
https://mariadb.com/kb/en/library/systemd/
Main PID: 9161 (mysqld)
Status: "Taking your SQL requests now..."
Tasks: 31 (limit: 9451)
Memory: 64.7M
CGroup: /system.slice/mariadb.service
└─9161 /usr/sbin/mysqld

If it’s not running, start it with this command:

sudo systemctl start mariadb

To enable MariaDB to automatically start at boot time, run

sudo systemctl enable mariadb

Now run the post-installation security script.

sudo mysql_secure_installation

When it asks you to enter MariaDB root password, press Enter key as the root
password isn’t set yet. Then enter y to set the root password for MariaDB server.

Next, you can press Enter to answer all remaining questions, which will remove
anonymous user, disable remote root login and remove test database. This step is a
basic requirement for MariaDB database security. (Notice that Y is capitalized, which
means it is the default answer. )
Step 2: Download PostfixAdmin on Ubuntu Server

PostfixAdmin is included in the default Ubuntu repository. However, I don’t


recommend it for the following reasons:

 It can create problems when you upgrade the Ubuntu system to a new version,
resulting in upgrade failure.
 If you use Nginx, the postfixadmin package might automatically install Apache on
your system.
 If you use MySQL, this package might remove MySQL from your system.
 The default postfixadmin package has a login loop issue from time to time. You will
also sometimes encounter the Invalid token! (CSRF check failed) error.

So I will show you how to install the latest version of PostfixAdmin. Go to


PostfixAdmin Github page to download the latest version. You can use the wget tool
to download it from command line. The download link is always available in the
format below. If a new version comes out, simply replace 3.3.11 with the new version
number.

sudo apt install wget

wget https://github.com/postfixadmin/postfixadmin/archive/postfixadmin-3.3.11.tar.gz

Once downloaded, extract the archive to the /var/www/ directory and rename it to
postfixadmin.

sudo mkdir -p /var/www/

sudo tar xvf postfixadmin-3.3.11.tar.gz -C /var/www/

sudo mv /var/www/postfixadmin-postfixadmin-3.3.11 /var/www/postfixadmin

Step 3: Setting Up Permissions

PostfixAdmin requires a templates_c directory, and the web server needs read and
write access to this directory, so run the following commands.

sudo mkdir -p /var/www/postfixadmin/templates_c

sudo apt install acl

sudo setfacl -R -m u:www-data:rwx /var/www/postfixadmin/templates_c/

Starting with Dovecot 2.3.11, the web server user needs permission to read Let’s
Encrypt TLS certificate in order to do password hashing. Run the following two
commands to grant permissions.

sudo setfacl -R -m u:www-data:rx /etc/letsencrypt/live/ /etc/letsencrypt/archive/

Step 4: Create a Database and User for PostfixAdmin

Log into MySQL/MariaDB shell as root with the following command.

sudo mysql -u root

Once you are logged in, create a database for PostfixAdmin using the following
command. I named it postfixadmin, but you can use whatever name you like. (Don’t
leave out the semicolon.)

create database postfixadmin;


Then enter the command below to create a database user for PostfixAdmin. Replace
postfixadmin_password with your preferred password. Note that the password
should not contain the # character, or you might not be able to log in later.

create user 'postfixadmin'@'localhost' identified by 'postfixadmin_password';

Grants all privileges of postfixadmin database to the user.

grant all privileges on postfixadmin.* to 'postfixadmin'@'localhost';

Flush the privileges table for the changes to take effect and then get out of MariaDB
shell.

flush privileges;

exit;

Step 5: Configure PostfixAdmin

The default PostfixAdmin configuration file is config.inc.php. We need to create a


config.local.php file and add custom configurations.

sudo nano /var/www/postfixadmin/config.local.php

Add the following lines in the file, so PostfixAdmin can connect to MySQL/MariaDB
database. Replace postfixadmin_password with the real PostfixAdmin password
created in step 4.

<?php
$CONF['configured'] = true;
$CONF['database_type'] = 'mysqli';
$CONF['database_host'] = 'localhost';
$CONF['database_port'] = '3306';
$CONF['database_user'] = 'postfixadmin';
$CONF['database_password'] = 'postfixadmin_password';
$CONF['database_name'] = 'postfixadmin';
$CONF['encrypt'] = 'dovecot:ARGON2I';
$CONF['dovecotpw'] = "/usr/bin/doveadm pw -r 5";
if(@file_exists('/usr/bin/doveadm')) { // @ to silence openbase_dir stuff; see
https://github.com/postfixadmin/postfixadmin/issues/171
$CONF['dovecotpw'] = "/usr/bin/doveadm pw -r 5"; # debian
}

Save and close the file. Note that we will use the ARGON2I password scheme. By
default, PostfixAdmin and Dovecot use MD5-CRYPT, which is a weak password
scheme. You can list available password schemes in Dovecot with the following
command.
sudo doveadm pw -l

Sample output:

SHA1 SSHA512 BLF-CRYPT PLAIN HMAC-MD5 OTP SHA512 SHA RPA DES-CRYPT
CRYPT SSHA MD5-CRYPT SKEY PLAIN-MD4 PLAIN-MD5 SCRAM-SHA-1
LANMAN SHA512-CRYPT CLEAR CLEARTEXT ARGON2I ARGON2ID SSHA256
NTLM MD5 PBKDF2 SHA256 CRAM-MD5 PLAIN-TRUNC SHA256-CRYPT SMD5
DIGEST-MD5 LDAP-MD5

Installing Dovecot 2.3 on Ubuntu 18.04

If you are using Ubuntu 22.04/20.4, you already have Dovecot 2.3. If you use Ubuntu
18.04, you need to install Dovecot 2.3 from the official upstream repository, so you
will be able to use ARGON2I password scheme.

Create a repository file for Dovecot.

sudo nano /etc/apt/sources.list.d/dovecot.list

Add the following line in the file.

deb [arch=amd64] https://repo.dovecot.org/ce-2.3-latest/ubuntu/bionic bionic main

Save and close the file. Because this repository is using https, so we need to install
the apt-transport-https package.

sudo apt install apt-transport-https

Then we need to import the Dovecot PGP key with the following two commands, so
that packages downloaded from this repository can be verified.

curl https://repo.dovecot.org/DOVECOT-REPO-GPG | gpg --import


gpg --export ED409DA1 | sudo tee /etc/apt/trusted.gpg.d/dovecot.gpg

Now update repository and upgrade existing Dovecot packages.

sudo apt update


sudo apt upgrade

If you see a question like below in the upgrade process, it’s always a good idea to
keep the local version and examine what needs to change later.
Once the upgrade is finished, check Dovecot version again.

dovecot --version

Output:

2.3.9.2 (cf2918cac)

Step 6: Create Apache Virtual Host or Nginx Config File for


PostfixAdmin

Nginx

If you use Nginx web server, create a virtual host for PostfixAdmin.

sudo nano /etc/nginx/conf.d/postfixadmin.conf

Put the following text into the file. Replace postfixadmin.example.com with your real
domain name and don’t forget to set DNS A record for it.

server {
listen 80;
listen [::]:80;
server_name postfixadmin.example.com;

root /var/www/postfixadmin/public/;
index index.php index.html;

access_log /var/log/nginx/postfixadmin_access.log;
error_log /var/log/nginx/postfixadmin_error.log;

location / {
try_files $uri $uri/ /index.php;
}

location ~ ^/(.+\.php)$ {
try_files $uri =404;
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include /etc/nginx/fastcgi_params;
}
}

 The above configuration uses php8.1-fpm, which is the default for Ubuntu 22.04.
 If you use Ubuntu 20.04, replace php8.1-fpm with php7.4-fpm.
 If you use Ubuntu 18.04, replace php8.1-fpm with php7.2-fpm.

Save and close the file. Then test Nginx configuration.

sudo nginx -t

If the test is successful, reload Nginx for the changes to take effect.

sudo systemctl reload nginx

Now you should be able to see the PostfixAdmin web-based install wizard at
http://postfixadmin.example.com/setup.php.

Step 7: Install Required and Recommended PHP Modules

Run the following command to install PHP modules required or recommended by


PostfixAdmin.

Ubuntu 22.04

sudo apt install php8.1-fpm php8.1-imap php8.1-mbstring php8.1-mysql php8.1-curl php8.1-


zip php8.1-xml php8.1-bz2 php8.1-intl php8.1-gmp php8.1-redis

Step 8: Enabling HTTPS

To encrypt the HTTP traffic, we can enable HTTPS by installing a free TLS certificate
issued from Let’s Encrypt. Run the following command to install Let’s Encrypt client
(certbot) on Ubuntu server.
sudo apt install certbot

If you use Nginx, then you also need to install the Certbot Nginx plugin.

sudo apt install python3-certbot-nginx

Next, run the following command to obtain and install TLS certificate.

sudo certbot --nginx --agree-tos --redirect --hsts --staple-ocsp --email you@example.com -d


postfixadmin.example.com

Where

 --nginx: Use the nginx plugin.


 --apache: Use the Apache plugin.
 --agree-tos: Agree to terms of service.
 --redirect: Force HTTPS by 301 redirect.
 --hsts: Add the Strict-Transport-Security header to every HTTP response. Forcing
browser to always use TLS for the domain. Defends against SSL/TLS Stripping.
 --staple-ocsp: Enables OCSP Stapling. A valid OCSP response is stapled to the
certificate that the server offers during TLS.

The certificate should now be obtained and automatically installed, which is indicated
by a message.

Step 9: Enable Statistics in Dovecot

PostfixAdmin needs to read Dovecot statistics. Edit the Dovecot configuration file.

sudo nano /etc/dovecot/conf.d/10-master.conf

Add the following lines to the end of this file.

service stats {
unix_listener stats-reader {
user = www-data
group = www-data
mode = 0660
}

unix_listener stats-writer {
user = www-data
group = www-data
mode = 0660
}
}

Save and close the file. Then add the web server to the dovecot group.
sudo gpasswd -a www-data dovecot

Restart Dovecot.

sudo systemctl restart dovecot

Grant permissions to the www-data user.

sudo setfacl -R -m u:www-data:rwx /var/run/dovecot/stats-reader /var/run/dovecot/stats-


writer

Step 10: Finish the Installation in Web Browser

Go to postfixadmin.example.com/setup.php to run the web-based setup wizard. First,


you need to create a setup password for PostfixAdmin.

After creating the password hash, PostfixAdmin will display a line like below.

$CONF['setup_password'] =
'$2y$10$58fIawuOb5y538RMBol/DOoqv2bJ7zhPRzRO.4Xq7MLeQJHmaFwF2';

You need to open the config.local.php file.

sudo nano /var/www/postfixadmin/config.local.php

Add the line displayed on PostfixAdmin setup page to the end of the file like below.
After saving the file, you need to refresh the PostfixAdmin setup page and enter the
setup password again, then create the admin account. Please don’t use a Gmail,
Yahoo Mail, or Microsoft email address for the admin account, or you might not be
able to log in later. Use an email address on your own domain. You can create the
email address later in PostfixAdmin.

If you encounter the following error when trying to create a superadmin account,

Password Hashing - attempted to use configured encrypt backend (dovecot:ARGON2I)


triggered an error: /usr/bin/doveadm pw -r 5 failed, see error log for details

or

can’t encrypt password with dovecotpw, see error log for details

It’s because the www-data user doesn’t have permission to read Let’s Encrypt TLS
certificate. To fix it, run the following command to grant permissions.

sudo setfacl -R -m u:www-data:rx /etc/letsencrypt/live/ /etc/letsencrypt/archive/

Sometimes, you might also need to run the following command to fix this error.
sudo setfacl -R -m u:www-data:rwx /var/run/dovecot/stats-reader /var/run/dovecot/stats-
writer

Once the superadmin account is created, you can log into PostfixAdmin at
postfixadmin.example.com/login.php.

Step 11: Checking Tables in the Database

The PostfixAdmin setup process populates the postfixadmin database with some
default tables. It’s helpful for us to know the names and structure of the tables. Log
in to MySQL/MariaDB console.

sudo mysql -u root

Select the postfixadmin database.

USE postfixadmin;

List all tables in this database.

SHOW TABLES;

Output:

+------------------------+
| Tables_in_postfixadmin |
+------------------------+
| admin |
| alias |
| alias_domain |
| config |
| domain |
| domain_admins |
| fetchmail |
| log |
| mailbox |
| quota |
| quota2 |
| vacation |
| vacation_notification |
+------------------------+
13 rows in set (0.001 sec)

The 3 most important tables are:

 domain: contains information on the domains that are using your mail server to send
and receive email.
 mailbox: contains information on every email address, including hashed password and
the location of mail files.
 alias: contains the alias of each email address.

If you are interested, you can check what columns each table contains. For example,
the following command will show us the columns in the domain table.

DESCRIBE domain;

Output:

+-------------+--------------+------+-----+---------------------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------------------+-------+
| domain | varchar(255) | NO | PRI | NULL | |
| description | varchar(255) | NO | | NULL | |
| aliases | int(10) | NO | | 0 | |
| mailboxes | int(10) | NO | | 0 | |
| maxquota | bigint(20) | NO | | 0 | |
| quota | bigint(20) | NO | | 0 | |
| transport | varchar(255) | NO | | NULL | |
| backupmx | tinyint(1) | NO | | 0 | |
| created | datetime | NO | | 2000-01-01 00:00:00 | |
| modified | datetime | NO | | 2000-01-01 00:00:00 | |
| active | tinyint(1) | NO | | 1 | |
+-------------+--------------+------+-----+---------------------+-------+

Log out of MySQL/MariaDB console.

EXIT;

Step 12: Configure Postfix to Use MySQL/MariaDB Database


By default, Postfix delivers emails only to users with a local Unix account. To make it
deliver emails to virtual users whose information is stored in the database, we need
to configure Postfix to use virtual mailbox domains.

First, we need to add MySQL map support for Postfix by installing the postfix-mysql
package.

sudo apt install postfix-mysql

Then edit the Postfix main configuration file.

sudo nano /etc/postfix/main.cf

Add the following lines at the end of this file.

virtual_mailbox_domains = proxy:mysql:/etc/postfix/sql/mysql_virtual_domains_maps.cf
virtual_mailbox_maps =
proxy:mysql:/etc/postfix/sql/mysql_virtual_mailbox_maps.cf,
proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_domain_mailbox_maps.cf
virtual_alias_maps =
proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_maps.cf,
proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_domain_maps.cf,
proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_domain_catchall_maps.cf

Where:

 virtual_mailbox_domains points to a file that will tell Postfix how to look up domain
information from the database.
 virtual_mailbox_maps points to files that will tell Postfix how to look up email
addresses from the database.
 virtual_alias_maps points to files that will tell Postfix how to look up aliases from the
database.

We want to use dovecot to deliver incoming emails to the virtual users’ message
store, so also add the following line at the end of this file.

virtual_transport = lmtp:unix:private/dovecot-lmtp
Save and close the file. Next, we need to create the .cf files one by one. Create the sql
directory.

sudo mkdir /etc/postfix/sql/

Create the mysql_virtual_domains_maps.cf file.

sudo nano /etc/postfix/sql/mysql_virtual_domains_maps.cf

Add the following content. Replace password with the postfixadmin password you
set in Step 2.

user = postfixadmin
password = password
hosts = localhost
dbname = postfixadmin
query = SELECT domain FROM domain WHERE domain='%s' AND active = '1'
#query = SELECT domain FROM domain WHERE domain='%s'
#optional query to use when relaying for backup MX
#query = SELECT domain FROM domain WHERE domain='%s' AND backupmx = '0' AND
active = '1'
#expansion_limit = 100

Create the mysql_virtual_mailbox_maps.cf file.

sudo nano /etc/postfix/sql/mysql_virtual_mailbox_maps.cf

Add the following content.

user = postfixadmin
password = password
hosts = localhost
dbname = postfixadmin
query = SELECT maildir FROM mailbox WHERE username='%s' AND active = '1'
#expansion_limit = 100

Create the mysql_virtual_alias_domain_mailbox_maps.cf file.

sudo nano /etc/postfix/sql/mysql_virtual_alias_domain_mailbox_maps.cf

Add the following content.

user = postfixadmin
password = password
hosts = localhost
dbname = postfixadmin
query = SELECT maildir FROM mailbox,alias_domain WHERE alias_domain.alias_domain
= '%d' and mailbox.username = CONCAT('%u', '@', alias_domain.target_domain) AND
mailbox.active = 1 AND alias_domain.active='1'

Create the mysql_virtual_alias_maps.cf file.

sudo nano /etc/postfix/sql/mysql_virtual_alias_maps.cf

Add the following content.

user = postfixadmin
password = password
hosts = localhost
dbname = postfixadmin
query = SELECT goto FROM alias WHERE address='%s' AND active = '1'
#expansion_limit = 100

Create the mysql_virtual_alias_domain_maps.cf file.

sudo nano /etc/postfix/sql/mysql_virtual_alias_domain_maps.cf

Add the following content.

user = postfixadmin
password = password
hosts = localhost
dbname = postfixadmin
query = SELECT goto FROM alias,alias_domain WHERE alias_domain.alias_domain = '%d'
and alias.address = CONCAT('%u', '@', alias_domain.target_domain) AND alias.active = 1
AND alias_domain.active='1'

Create the mysql_virtual_alias_domain_catchall_maps file.

sudo nano /etc/postfix/sql/mysql_virtual_alias_domain_catchall_maps.cf

Add the following content.

# handles catch-all settings of target-domain


user = postfixadmin
password = password
hosts = localhost
dbname = postfixadmin
query = SELECT goto FROM alias,alias_domain WHERE alias_domain.alias_domain = '%d'
and alias.address = CONCAT('@', alias_domain.target_domain) AND alias.active = 1 AND
alias_domain.active='1'
Since the database passwords are stored in plain text so they should be readable
only by user postfix and root, which is done by executing the following two
commands.

sudo chmod 0640 /etc/postfix/sql/*


sudo setfacl -R -m u:postfix:rx /etc/postfix/sql/

Next, we need to change the value of the mydestination parameter in Postfix. Display
the current value:

postconf mydestination

Sample output:

mydestination = $myhostname, example.com, localhost.$mydomain, localhost

The mydestination parameter contains a list of domain names that will receive emails
delivered to local Unix accounts. In part 1, we added the apex domain name (like
example.com) to mydestination. Since we are going to use virtual mailbox, we need
to remove the apex domain name from the list by issuing the following command.

sudo postconf -e "mydestination = \$myhostname, localhost.\$mydomain, localhost"

Now let’s open the Postfix main configuration file again.

sudo nano /etc/postfix/main.cf

Add the following lines at the end of this file.

virtual_mailbox_base = /var/vmail
virtual_minimum_uid = 2000
virtual_uid_maps = static:2000
virtual_gid_maps = static:2000

The first line defines the base location of mail files. The remaining 3 lines define
which user ID and group ID Postfix will use when delivering incoming emails to the
mailbox. We use the user ID 2000 and group ID 2000.

Save and close the file. Restart Postfix for the changes to take effect.

sudo systemctl restart postfix

Next, we need to create a user named vmail with ID 2000 and a group with ID 2000.

sudo adduser vmail --system --group --uid 2000 --disabled-login --no-create-home

Create the mail base location.


sudo mkdir /var/vmail/

Make vmail as the owner.

sudo chown vmail:vmail /var/vmail/ -R

Step 13: Configure Dovecot to Use MySQL/MariaDB Database

We also need to configure the Dovecot IMAP server to query user information from
the database. First, run the following command to add MySQL support for Dovecot.

sudo apt install dovecot-mysql

Then edit the 10-mail.conf file.

sudo nano /etc/dovecot/conf.d/10-mail.conf

In part 2, we used the following mail_location. Email messages are stored under the
Maildir directory under each user’s home directory.

mail_location = maildir:~/Maildir

Since we are using virtual mailbox domain now, we need to enable mail_home for
the virtual users by adding the following line in the file, because virtual users don’t
have home directories by default.

mail_home = /var/vmail/%d/%n/

Save and close the file. Then edit the 10-auth.conf file.

sudo nano /etc/dovecot/conf.d/10-auth.conf

In part 2, we used the following value for auth_username_format.

auth_username_format = %n
The %n would drop the domain if it was given. Because in part 2 we were using local
Unix account for the username of every email address, we must use %n to drop the
domain, so users were able to login with the full email address.

Now we are using virtual mailbox domains, which means the username of every
email address includes the domain part, so we need to change the
auth_username_format as follows. %u won’t drop away the domain. This allows users
to login with the full email address.

auth_username_format = %u

Then find the following line.

#auth_default_realm =

Change it to

auth_default_realm = example.com

This is to ensure users who didn’t enter the @example.com part in the username field
can still log in. Dovecot will append the @example.com part if it’s not given by users.

Next, uncomment the following line at the end of this file, so Dovecot can query user
information from MySQL/MariaDB database.

!include auth-sql.conf.ext

Now you probably don’t want local Unix users to send emails without registering
email addresses in PostfixAdmin, then comment out the following line by adding the
# character at the beginning, so Dovecot won’t query the local /etc/passwd or
/etc/shadow file.

#!include auth-system.conf.ext

It can be helpful to add the following two lines in this file to debug login issues. The
login errors would be logged into /var/log/mail.log file. (Once users can login
without problems, you can comment out the following two lines.)

auth_debug = yes
auth_debug_passwords = yes
Save and close the file.

Edit the dovecot-sql.conf.ext file.

sudo nano /etc/dovecot/dovecot-sql.conf.ext

Here is the content that you should have in this file. By default, all lines in this file are
commented out, so you can simply copy and paste them at the bottom. Replace
password with the postfixadmin password you set in Step 2.

driver = mysql

connect = host=localhost dbname=postfixadmin user=postfixadmin password=password

default_pass_scheme = ARGON2I

password_query = SELECT username AS user,password FROM mailbox WHERE username


= '%u' AND active='1'

user_query = SELECT maildir, 2000 AS uid, 2000 AS gid FROM mailbox WHERE
username = '%u' AND active='1'

iterate_query = SELECT username AS user FROM mailbox

Restart Dovecot.

sudo systemctl restart dovecot

When a user tries to log in, Dovecot would use the Argon2 algorithm to generate a
password hash from the password entered by the user, then compare it with the
password hash stored in the database.

Step 14: Add Domain and Mailboxes in PostfixAdmin


Log in to PostfixAdmin web interface as the admin. Click the Domain List tab and
select New Domain to add a domain. You can choose how many aliases and
mailboxes are allowed for this domain.

Then click Virtual List tab and select Add Mailbox to add a new email address for
your domain.

Next, you can open your desktop email client such as Mozilla Thunderbird and add a
mail account.
 In the incoming server section, select IMAP protocol, enter mail.your-domain.com as
the server name, choose port 143 and STARTTLS. Choose normal password as the
authentication method.
 In the outgoing section, select SMTP protocol, enter mail.your-domain.com as the
server name, choose port 587 and STARTTLS. Choose normal password as the
authentication method.

Hint 1: You can also use port 993 with SSL/TLS encryption for IMAP, and use port
465 with SSL/TLS encryption for SMTP. You should not use port 25 as the SMTP port
in mail clients to submit outgoing emails.

Hint 2: If you use Microsoft 365 Outlook email client, then you shouldn’t enable
Secure Password Authentication (SPA), which is a proprietary Microsoft protocol.
Your password is already encrypted by TLS.

You should now be able to connect to your own email server and also send and
receive emails with your desktop email client!

Note that you cannot use local Unix accounts to login now. You must log in with the
virtual user created from PostfixAdmin web interface.

You might also like