In order to set up a full simple mail server, this guide takes advantage of Postfix as an SMTP server, Dovecot to provide POP/IMAP functionality, and RoundCube as a webmail program or client so that users can check and receive email from their favorite web browsers.

To clear all the jargon, let us get to know what the compnents we are going to use are.

Dovecot: Dovecot is an open-source IMAP and POP3 email server for Linux/UNIX-like systems, written with security primarily in mind.

Postfix: Postfix is a free and open-source mail transfer agent (MTA) that routes and delivers electronic mail from one server to another over the internet.

Roundcube: Once the mails have been delivered into a mailbox, most users would need an easy to use interface to read their mails. Roundcube does this pretty well. It is a browser-based multilingual IMAP client with an application-like user interface. It provides full functionality you expect from an email client, including MIME support, address book, folder manipulation, message searching and spell checking.

Pre-requisites for Production use

In order to use the server for production use, you must ensure you have the following

  • You must have a Fully Qualifed Domain Name (FQDN)
  • Create A and MX Records for your Domain in a Public Domain Name Server. These records must point to the Public IP of your server.

Now that we are on the same page, it is time we get into the part where they all come and work together.

Step 1: Update and set your hostname

This is to ensure we start with the latest packages which ensures all previous patches are applied and hence beginning with a secure and an upto date system.

sudo dnf update
sudo hostnamectl set-hostname mail.example.com

Step 2: Install postfix, Apache and PHP

We need a Mail Transfer Agent to handle the sending and delivery of mails from our mail server. Luckily, postfix does that quite well. To install postfix, run the command below.

sudo dnf install postfix postfix-mysql httpd vim policycoreutils-python-utils epel-release -y

PHP will be used by Roundcube to render the pages on your browser and hence the need to install it. Get it installed by following instructions in the guide below.

How To Install PHP 7.4 on CentOS 8 / RHEL 8

After PHP is installed, add extra PHP packages like so:

sudo dnf install -y php-common php-json php-xml php-mbstring php-mysql

Step 3: Configure Postfix

Let us now configure Postfix to ensure it will be able to recieve and deliver mails from our server. Its configuration files are found under /etc/postfix.

Configure the master configuration file

sudo vim /etc/postfix/master.cf

Uncomment the following lines in the file. Ensure that the lines beginning with -o maintains the indentation.

submission inet n       -       n       -       -       smtpd
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=encrypt   ## Comment this out if you have no SSL(not recommended)
  -o smtpd_tls_auth_only=yes            ## Comment this out if you have no SSL(not recommended)
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
  -o milter_macro_daemon_name=ORIGINATINGmixed
  -o smtpd_reject_unlisted_recipient=no

Add the following dovecot-related configs at the bottom of the file.

dovecot   unix  -       n       n       -       -       pipe
    flags=DRhu user=vmail:vmail argv=/usr/libexec/dovecot/deliver -f ${sender} -d ${recipient}

We shall install and configure dovecot later on.

Save the file after you have made the changes above.

Open main.cf file

The /etc/postfix/main.cf file has main configuration options for Postfix installation.

sudo vim /etc/postfix/main.cf

Make the following changes:

Configure Hostname

Uncomment the myhostname line and replace host.domain.tld with the server’s hostname.

myhostname = mail.example.com

Configure your Domain

Add your domain to the mydomain line as below:

mydomain = example.com   ## Input your unique domain here

Uncomment or add the following lines so that they do not have a # sign in-front of them

myorigin = $myhostname
inet_interfaces = all
inet_interfaces = localhost
inet_protocols = all
mydestination = $myhostname, localhost.$mydomain, localhost
smtpd_recipient_restrictions = permit_mynetworks
home_mailbox = Maildir/

Add the following configuration lines to the end of the file. As you can notice, other configuration are SSL related. If you have SSL files, copy them in a suitable location and add them as illustrated.

append_dot_mydomain = no
biff = no
config_directory = /etc/postfix
dovecot_destination_recipient_limit = 1
message_size_limit = 4194304
smtpd_tls_key_file = /etc/postfix/ssl/yourkey.key           ##SSL Key
smtpd_tls_cert_file = /etc/postfix/ssl/yourcertificate.crt  ##SSL Cert
smtpd_use_tls=yes
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
smtpd_tls_security_level=may
virtual_transport = dovecot
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth

Add the following configuration as well which gives Postfix access to the account-related data we shall create and store in the database

virtual_mailbox_domains = mysql:/etc/postfix/database-domains.cf
virtual_mailbox_maps = mysql:/etc/postfix/database-users.cf
virtual_alias_maps = mysql:/etc/postfix/database-alias.cf

Now let us add database configurations to those specific files as shown below. Note that the databases and tables will be created later in the next step of this guide.

Allow Postfix to access domains from the database

$ sudo vim /etc/postfix/database-domains.cf

user = postfix_admin
password = StrongPassword
hosts = 127.0.0.1
dbname = postfix_accounts
query = SELECT 1 FROM domains_table WHERE DomainName='%s'

Allow Postfix to access user accounts from the database

$ sudo vim /etc/postfix/database-users.cf

user = postfix_admin
password = StrongPassword
hosts = 127.0.0.1
dbname = postfix_accounts
query = SELECT 1 FROM accounts_table WHERE DomainName='%s'

Allow Postfix to access email aliases from the database

$ sudo vim /etc/postfix/database-alias.cf

user = postfix_admin
password = StrongPassword
hosts = 127.0.0.1
dbname = postfix_accounts
query = SELECT Destination FROM alias_table WHERE Source='%s'

Change ownership and permissions of the files we created above

Change the permissions to these files

sudo chmod 640 /etc/postfix/database-domains.cf
sudo chmod 640 /etc/postfix/database-users.cf
sudo chmod 640 /etc/postfix/database-alias.cf

And the ownership to the files like so

sudo chown root:postfix /etc/postfix/database-domains.cf
sudo chown root:postfix /etc/postfix/database-users.cf
sudo chown root:postfix /etc/postfix/database-alias.cf

Since we have made new changes we need to restart Postfix to load the new configs.

sudo systemctl restart postfix

Step 4: Install and configure MySQL

Roundcube requires a database to store and retrieve important data. Install MariaDB by following this guide:

How To Install MariaDB 10.4 on CentOS 8 / RHEL 8

After MariaDB is installed, we shall continue to configure it by creating a MariaDB username and database for the Roundcube installation. Additionally, we shall create Postfix Mail accounts databse. Log into the MariaDB client with the command:

mysql -u root -p

Supply your root password and create a database for Postfix Mail accounts as shown below

create database postfix_accounts;

Create a user with full rights for the mail accounts database we just created.

grant all on postfix_accounts.* to [email protected] identified by 'StrongPassword';
flush privileges;

Create a table in the database that will store the domains you would wish to host in the server.

CREATE TABLE `postfix_accounts`.`domains_table` ( `DomainId` INT NOT NULL AUTO_INCREMENT , `DomainName` VARCHAR(50) NOT NULL , PRIMARY KEY (`DomainId`)) ENGINE = InnoDB;

Create a table in the database that will hold user accounts

CREATE TABLE `postfix_accounts`.`accounts_table` ( 
    `AccountId` INT NOT NULL AUTO_INCREMENT,  
    `DomainId` INT NOT NULL,  
    `password` VARCHAR(300) NOT NULL,  
    `Email` VARCHAR(100) NOT NULL,  
    PRIMARY KEY (`AccountId`),  
    UNIQUE KEY `Email` (`Email`),  
    FOREIGN KEY (DomainId) REFERENCES domains_table(DomainId) ON DELETE CASCADE 
) ENGINE = InnoDB;

Create a table in the database that will hold email aliases data.

An alias basically allows emails sent to one account to be redirected to another account once it reaches the mail server. For example, if you would wish all [email protected] emails to be sent to [email protected], you create an alias to accomplish that functionality.

CREATE TABLE `postfix_accounts`.`alias_table` (
    `AliasId` INT NOT NULL AUTO_INCREMENT, 
    `DomainId` INT NOT NULL, 
    `Source` varchar(100) NOT NULL, 
    `Destination` varchar(100) NOT NULL, 
    PRIMARY KEY (`AliasId`), 
    FOREIGN KEY (DomainId) REFERENCES domains_table(DomainId) ON DELETE CASCADE
) ENGINE = InnoDB;

Add records to the tables we have just created in Postfix Mail Accounts database.

We will now add our domain, some accounts and an alias.

INSERT INTO `postfix_accounts`.`domains_table` (DomainName) VALUES ('example.com');  
INSERT INTO `postfix_accounts`.`accounts_table` (DomainId, password, Email) VALUES (1, ENCRYPT('Password', CONCAT('$6$', SUBSTRING(SHA(RAND()), -16))), '[email protected]');  
INSERT INTO `postfix_accounts`.`accounts_table` (DomainId, password, Email) VALUES (1, ENCRYPT('Password', CONCAT('$6$', SUBSTRING(SHA(RAND()), -16))), '[email protected]');  
INSERT INTO `postfix_accounts`.`alias_table` (DomainId, Source, Destination) VALUES (1, '[email protected]', '[email protected]');

After that is done, log out of the database and hop onto the next step.

quit;

You can use names and passwords(strong) you prefer for:

postfix_admin user and postfix_accounts database name

Create a database for Roundcube which we shall install later as shown below

create database roundcube;

Create a user with full rights for the database we just created.

grant all on roundcube.* to [email protected] identified by 'StrongPassword';
flush privileges;

You can use names and passwords(strong) you prefer for:

roundcube_admin user and roundcube database name.

Test Posfix settings we made in Step 4

Now that our database is set-up, let us test if the configuration we made on Postfix are working

sudo postmap -q example.com mysql:/etc/postfix/database-domains.cf
sudo postmap -q [email protected] mysql:/etc/postfix/database-users.cf
sudo postmap -q [email protected] mysql:/etc/postfix/database-users.cf
sudo postmap -q [email protected] mysql:/etc/postfix/database-alias.cf

Step 5: Install and configure Dovecot

As it had been covered before, Dovecot is an open source IMAP and POP3 email server for Linux/UNIX-like systems. These protocols offers mail users the ability to retrieve mails from the server to their local mail clients and to delete mails from the server. Install Dovecot like so:

sudo dnf install dovecot dovecot-mysql -y

After it is successfully installed, let us add a user and group that will be responsible for handling mails in the system.

sudo groupadd -g 6000 vmail 
sudo useradd -g vmail -u 6000 vmail -d /home/vmail -m


Dovecot has a number of configuration files. Let us edit them step by step ensuring every configuration is accurately captured.

Open main dovecot configuration file and make sure the lines below have no # sign in from of them

$ sudo vim /etc/dovecot/dovecot.conf

!include_try /usr/share/dovecot/protocols.d/*.protocol
protocols = imap pop3 lmtp
!include conf.d/*.conf
!include_try local.conf

Next, open /etc/dovecot/conf.d/10-auth.conf file and make sure the lines below are without comments. You will notice that #!include auth-system.conf.ext is enabled by default. Comment it out leaving !include auth-sql.conf.ext only enabled.

disable_plaintext_auth = yes
auth_mechanisms = plain login
!include auth-sql.conf.ext

After that, we need to add configurations to the file we enabled above. That is /etc/dovecot/conf.d/auth-sql.conf.ext.

These are the few special variables used

  • %u – username
  • %n – user part in [email protected], same as %u if there’s no domain
  • %d – domain part in [email protected], empty if there’s no domain
  • %h – home directory

As you can see from the configuration below, we will be storing emails in /home/vmail/.

$ sudo vim /etc/dovecot/conf.d/auth-sql.conf.ext

passdb {
  driver = sql
  args = /etc/dovecot/dovecot-sql.conf.ext
}
userdb {
  driver = static
  args = uid=vmail gid=vmail home=/home/vmail/%d/%n/Maildir
}

Create the /home/vmail/ directory

sudo mkdir /home/vmail/example.com

Let us add database details we configured for postfix in the file we included in “args” in the file above

$ sudo vim /etc/dovecot/dovecot-sql.conf.ext

driver = mysql
connect = "host=127.0.0.1 dbname=postfix_accounts user=postfix_admin password=StrongPassword"
default_pass_scheme = SHA512-CRYPT
password_query = SELECT Email as User, password FROM accounts_table WHERE Email='%u';

Now we are going to confugure Mailbox locations and namespaces

Open this file /etc/dovecot/conf.d/10-mail.conf and make sure the settings are altered to be similar to the configuration below

mail_location = maildir:/home/vmail/%d/%n/Maildir
namespace inbox {
  inbox = yes
}
mail_privileged_group = mail
mbox_write_locks = fcntl

Next, open up /etc/dovecot/conf.d/10-master.conf and make the following changes to it then save.

service imap-login {
  inet_listener imap {
    port = 143
  }
  inet_listener imaps {
  }
}
service pop3-login {
  inet_listener pop3 {
    port = 110
  }
  inet_listener pop3s {
  }
}
service lmtp {
  unix_listener /var/spool/postfix/private/dovecot-lmtp {
   mode = 0600
   user = postfix
   group = postfix
  }
}
service auth {
  unix_listener /var/spool/postfix/private/auth {
    mode = 0666
    user = postfix
    group = postfix
  }
  unix_listener auth-userdb {
   mode = 0600
   user = vmail
  }
  user = dovecot
}
service auth-worker {
  user = vmail
}
service dict {
  unix_listener dict {
  }
}

vmail user is responsible for handling mails in teh server. Therefore, the user needs access to the location of the mails. Give vmail user the permissions it requires as below:

sudo chown –R vmail:vmail /home/vmail

Give vmail and dovecot users permission to read Configuration files.

sudo chown -R vmail:dovecot /etc/dovecot 
sudo chmod -R o-rwx /etc/dovecot 

Step 6: Install and configure Roundcube

And now onto our web-based client to enable users to view their mails. You can download the latest stable release of Roundcube from their official webpage.

VER="1.4.3"
wget https://github.com/roundcube/roundcubemail/releases/download/$VER/roundcubemail-$VER-complete.tar.gz

Uncompress the downloaded file and change the name of the resulting directory

tar xvzf roundcubemail-$VER-complete.tar.gz
mv roundcubemail-$VER roundcube

Now move the new directory to the document root of Apache, change its ownership to apache and restart Apache web server.

sudo mv roundcube /var/www/html/
sudo chown -R apache:apache /var/www/html/
sudo systemctl restart httpd

Fix SELinux context issues

sudo semanage fcontext -a -t httpd_sys_script_exec_t '/var/www/html(/.*)?'
sudo restorecon -R -v /var/www/html/

Load Roundcube on your favorite browser to complete installation

Open your browser and enter the following url

http://IP/FQDN/roundcube/installer

Follow the screenshots below to complete the setting up of Roundcube

<img alt="" data-ezsrc="https://kirelos.com/wp-content/uploads/2020/04/echo/roundcube-1-1024×635.png" data-ez ezimgfmt="rs rscb8 src ng ngcb8 srcset" height="438" src="data:image/svg xml,” width=”707″>

Make sure all the PHP checks are OK.

Scroll down and click “Next” if everything is working fine.

<img alt="" data-ezsrc="https://kirelos.com/wp-content/uploads/2020/04/echo/roundcube-2-next-1024×630.png" data-ez ezimgfmt="rs rscb8 src ng ngcb8 srcset" src="data:image/svg xml,”>

On the next page, look for “Database Setup” and fill in the Roundcube Database details we created earlier. After that, you can add other configs on the page as you like then scroll to the bottom and click “CREATE CONFIG

<img alt="" data-ezsrc="https://kirelos.com/wp-content/uploads/2020/04/echo/roundcube-3-database-1024×656.png" data-ez ezimgfmt="rs rscb8 src ng ngcb8 srcset" src="data:image/svg xml,”>
<img alt="" data-ezsrc="https://kirelos.com/wp-content/uploads/2020/04/echo/roundcube-4-createconfig-1024×637.png" data-ez ezimgfmt="rs rscb8 src ng ngcb8 srcset" src="data:image/svg xml,”>

On the “Create config” part look for “Create Config” and click on it which will lead to a page like below where you will be required to either download and transfer a config file or create it manually. Choose the one that you are comfortable with.

<img alt="" data-ezsrc="https://kirelos.com/wp-content/uploads/2020/04/echo/roundcube-5-savedownloadedconfig-1024×633.png" data-ez ezimgfmt="rs rscb8 src ng ngcb8 srcset" src="data:image/svg xml,”>

If you downloaded the file, transfer it to your server and copy it in the directory named in the instructions. Click “CONTINUE” after that.

sudo cp config.inc.php /var/www/html/roundcube/config/
sudo chown apache:apache /var/www/html/roundcube/config/config.inc.php

Edit the config file to include smtp hosts, ports and method of logging in

$ sudo vim /var/www/html/roundcube/config/config.inc.php

$config['default_host'] = 'localhost';  ## If SSL is confgured, use: $config['default_host'] = 'ssl//mail.example.com';
$config['support_url'] = '';
$config['defautl_port'] = 143;
$config['smtp_server'] = 'localhost';   ## If SSL is confgured, use: $config['smtp_server'] = 'tls//mail.example.com'; 
$config['smtp_port'] = 587;
$config['smtp_user'] = '%u';
$config['smtp_pass'] = '%p';
$config['smtp_auth_type'] = 'LOGIN';
$config['debug_level'] = 1;
$config['smtp_debug'] = true;
$config['plugins'] = array('virtuser_query');                                                                    
$config['virtuser_query'] = "SELECT Email FROM postfix_accounts.accounts_table WHERE Email = '%u'"; ## Enables Roundcube to use authentication for virtual users for outgoing mail
<img alt="" data-ezsrc="https://kirelos.com/wp-content/uploads/2020/04/echo/roundcube-6-testconfig-1024×587.png" data-ez ezimgfmt="rs rscb8 src ng ngcb8 srcset" src="data:image/svg xml,”>

Everything should be okay till this point. At the bottom of the page, you will see a banner that advises you to remove the whole installer directory after successfully setting up Roundcube.

<img alt="" data-ezsrc="https://kirelos.com/wp-content/uploads/2020/04/echo/roundcube-7-warning-1024×494.png" data-ez ezimgfmt="rs rscb8 src ng ngcb8 srcset" src="data:image/svg xml,”>

Step 7: Open all of the needed ports on the firewall

In case your firewall is running, allow the following ports

  • HTTP: 80
  • HTTPS: 443
  • SMTP: 25
  • POP3: 110
  • IMAP: 143
  • SMTP Secure: 465
  • MSA: 587
  • IMAP Secure: 993
  • POP3 Secure: 995
sudo firewall-cmd --permanent --add-port={80,443,25,110,143,465,587,993,995}/tcp
sudo firewall-cmd --reload

Step 8: Testing our Mail server

After everything is set-up and ready to go, it is time to test whether we are capable of sending and receiving emails.

Load your browser and enter https://IP-or-FQDN/roundcube

Input any email account we configured earlier and its corresponding password.

<img alt="" data-ezsrc="https://kirelos.com/wp-content/uploads/2020/04/echo/roundcube-8-loggin-1024×634.png" data-ez ezimgfmt="rs rscb8 src ng ngcb8 srcset" src="data:image/svg xml,”>

After logging in, test if you can send and receive mails from your local domain and external as well if the requirements are met for that.

<img alt="" data-ezsrc="https://kirelos.com/wp-content/uploads/2020/04/echo/roundcube-9-inside-1024×632.png" data-ez ezimgfmt="rs rscb8 src ng ngcb8 srcset" src="data:image/svg xml,”>
<img alt="" data-ezsrc="https://kirelos.com/wp-content/uploads/2020/04/echo/roundcube-10-mailtest-1024×527.png" data-ez ezimgfmt="rs rscb8 src ng ngcb8 srcset" src="data:image/svg xml,”>

Setting up a simple mail server can be as quick as it has been in this guide. If it is sitting in the cloud with a valid FQDN and Mail Exchange records well configured, then you should be able to send and receive emails to whomever you wish. For now, we appreciate you for visiting. Other guides are listed below for your consideration.

Install and Setup iRedMail Mail Server on Debian 10 (Buster)

How To Add Domains and User Accounts to iRedMail Mail Server

Secure iRedMail Server with Let’s Encrypt SSL Certificate

How To Install iRedMail Mail Server on CentOS 7