Setup Mail Server on CentOS7 With Postfix, Dovecot, MySQL and SquirrelMail

In this tutorial you’ll learn, how to configure a secure virtual user mail server with Postfix, Dovecot, mysql & squirrelmail. We’ll explain how to create new user mailboxes and send or receive email to and from configured domains.

Let us understand the components we are going to use :-

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.

Squirrelmail: SquirrelMail is a standards-based webmail package written in PHP. It includes built-in pure PHP support for the IMAP and SMTP protocols, and all pages render in pure HTML 4.0 (with no JavaScript required) for maximum compatibility across browsers. It has very few requirements and is very easy to configure and install. SquirrelMail has all the functionality you would want from an email client, including strong MIME support, address books, and folder manipulation.

Pre-requisites for Production use

  • 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.

Step 1: Update, set your hostname and disable SELinux

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

To disable selinux, open /etc/selinux/config:

vim /etc/selinux/config
SELINUX=disabled

Save & exit the file & Reboot the server.

Step 2: Install postfix, Apache and PHP

To install postfix, run the command below:

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

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

sudo yum install -y php-common php-json php-xml php-mbstring php-mysqlnd

Step 3: Configure MySQL

We will need a database to store and retrieve important data for both Roundcube and Postfix. So make sure you have MariaDB or MySQL installed.

Let’s create Postfix Mail accounts database. Log into the MariaDB client with the command:

mysql -u root -p

Enter 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:

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.

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]');

You can use names and passwords you prefer for:

Create a database for Roundcube which we shall install later.

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;

Step 4: Configure Postfix

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

Configure the master.cf file

sudo vim /etc/postfix/master.cf

Uncomment the following lines in the file.

submission inet n       -       n       -       -       smtpd
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_reject_unlisted_recipient=no
  -o smtpd_sasl_type=dovecot
  -o smtpd_sasl_path=private/auth
  -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
  -o milter_macro_daemon_name=ORIGINATING
smtps     inet  n       -       n       -       -       smtpd
  -o syslog_name=postfix/smtps
  -o smtpd_tls_wrappermode=yes
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_sasl_type=dovecot
  -o smtpd_sasl_path=private/auth
  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
  -o milter_macro_daemon_name=ORIGINATING

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}

Save the file after you have made the above changes.

Open main.cf file & Make the following changes:

sudo vim /etc/postfix/main.cf
append_dot_mydomain = no
biff = no
config_directory = /etc/postfix
smtpd_tls_key_file=/etc/letsencrypt/live/mail.example.com/privkey.pem
smtpd_tls_cert_file=/etc/letsencrypt/live/mail.example.com/fullchain.pem
smtpd_use_tls=yes
smtpd_tls_auth_only = yes
smtp_tls_security_level = may
smtpd_tls_security_level = may
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
smtpd_sasl_security_options= noanonymous, noplaintext
smtpd_sasl_tls_security_options = noanonymous
smtpd_recipient_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
mydestination = $myhostname, localhost.$mydomain
relayhost =
myhostname = mail.example.xyz
mydomain= example.xyz
myorigin = $mydomain
inet_interfaces = all
inet_protocols = all
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
message_size_limit = 52428800
mailbox_size_limit = 0
recipient_delimiter = +

##following configuration gives Postfix access to the account-related data we ##created and stored 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

##Handing off local delivery to Dovecot's LMTP, and telling it where to store mail
virtual_transport = lmtp:unix:private/dovecot-lmtp

Now, add database configurations to these specific files as shown below:

Allow Postfix to access domains, user accounts & email aliases 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'
$ 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 Email='%s'
$ 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 Email='%s'
$ 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:

sudo chmod 640 /etc/postfix/database-domains.cf
sudo chmod 640 /etc/postfix/database-users.cf
sudo chmod 640 /etc/postfix/database-alias.cf
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

Restart postfix.

sudo systemctl restart postfix
Lets test the postfix settings we made.

Now that our database is set-up, let us test if the configuration we made on Postfix are working. Using the following commands we can test Postfix settings we made

You should see a 1 if successful and an alias email address in the last one.

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

Step 5: Install and configure Dovecot

Install dovecot.

sudo yum install dovecot dovecot-mysql dovecot-pigeonhole

After it is successfully installed, 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 uncomment the following lines.

$ sudo vim /etc/dovecot/dovecot.conf

listen = *, ::
protocols = imap pop3 lmtp
!include conf.d/*.conf
!include_try local.conf
log_path = /var/log/dovecot.log  ##Add this for logs

Next, open /etc/dovecot/conf.d/10-auth.conf file and make sure the lines below are without comments.

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

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

These are the some 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
$ vim /etc/dovecot/conf.d/auth-sql.conf.ext.

passdb {
  driver = sql
  # Path for SQL configuration file, see example-config/dovecot-sql.conf.ext
  args = /etc/dovecot/dovecot-sql.conf.ext
}

userdb {
driver = static     ## Don't forget to change this
  args = uid=vmail gid=vmail home=/home/vmail/%d/%n/
}
userdb {
  driver = prefetch
}
userdb {
  driver = sql
  args = /etc/dovecot/dovecot-sql.conf.ext
}

Emails will be stored in /home/vmail.

Create the /home/vmail/domain directory .

sudo mkdir /home/vmail/example.com

Now we will add database details that we configured for postfix in the file we included in “args” in the file above.

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

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

Now we are going to configure mailbox locations and namespaces.

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

$ sudo vim /etc/dovecot/conf.d/10-mail.conf

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

Next, we will edit /etc/dovecot/conf.d/10-master.conf and make the following changes.

$ sudo vim /etc/dovecot/conf.d/10-master.conf

service imap-login {
  inet_listener imap {
    port = 143
  }
  inet_listener imaps {
    port = 993
    ssl = yes
  }
}

service pop3-login {
  inet_listener pop3 {
    port = 110
  }
  inet_listener pop3s {
    port = 995
    ssl = yes
  }
}

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

service auth {
  unix_listener /var/spool/postfix/private/auth {
    mode = 0660
    user = postfix
    group = postfix
  }

  unix_listener auth-userdb {
    mode = 0666
 user = vmail
  }

unix_listener auth-master {
group = vmail
mode = 0660
user = dovecot
} 
}

service auth-worker {
  user = vmail
}

service dict {
  unix_listener dict {
  }
}

service managesieve-login {
inet_listener sieve {
port = 4190
}
}
service managesieve {
}
protocol sieve {
managesieve_max_line_length = 65536
managesieve_implementation_string = dovecot
log_path = /var/log/dovecot.log
info_log_path = /var/log/dovecot.log
}
plugin {
sieve = ~/.dovecot.sieve
sieve_global_path = /etc/dovecot/sieve/default.sieve
sieve_dir = ~/sieve
sieve_global_dir = /etc/dovecot/sieve/global/
}
lda_mailbox_autocreate = yes
lda_mailbox_autosubscribe = yes
protocol lda {
mail_plugins = $mail_plugins autocreate sieve quota
postmaster_address = [email protected]
hostname = mail.example.com
auth_socket_path = /var/run/dovecot/auth-master
log_path = /var/log/dovecot.log
info_log_path = /var/log/dovecot.log
}
protocol lmtp {
mail_plugins = $mail_plugins autocreate sieve quota
log_path = /var/log/dovecot.log
info_log_path = /var/log/dovecot.log
}

NOTE : The Dovecot Sieve plugin provides mail filtering facilities at time of final message delivery using the Sieve language.

vmail user is responsible for handling mails in the 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 

Now open this file /etc/dovecot/conf.d/15-lda.conf and do the following changes

$ sudo vim /etc/dovecot/conf.d/15-lda.conf

postmaster_address = [email protected]
hostname = mail.example.com
quota_full_tempfail = yes
recipient_delimiter = +
lda_mailbox_autocreate = yes
lda_mailbox_autosubscribe = yes
protocol lda {
mail_plugins = $mailplugins sieve quota
}

We will now edit /etc/dovecot/conf.d/20-imap.conf & /etc/dovecot.conf.d/20-pop3.conf

$ sudo vim /etc/dovecot/conf.d/20-imap.conf

protocol imap {
mail_plugins = $mail_plugins quota imap_quota
}
$ sudo vim /etc/dovecot.conf.d/20-pop3.conf

protocol pop3 {
mail_plugins = $mail_plugins quota
}

Next, we will edit /etc/dovecot/conf.d/20-lmtp.conf

$ sudo vim /etc/dovecot/conf.d/20-lmtp.conf

protocol lmtp {
postmaster_address = [email protected]
mail_plugins = $mail_plugins sieve
}

In /etc/dovecot/conf.d/10-ssl.conf, we will add our sslkey and certificate.

$ sudo vim /etc/dovecot/conf.d/10-ssl.conf

ssl = required
ssl_cert = </etc/letsencrypt/live/mail.example.com/fullchain.pem
ssl_key = </etc/letsencrypt/live/mail.example.com/privkey.pem

After you have correctly done all the above in all the files, you can restart dovecot service

sudo systemctl restart dovecot 

Step 5: Install and configure SquirrelMail

SquirrelMail can be installed by downloading its files directly from their official website and place them in the document root directory of your web server.

wget http://downloads.sourceforge.net/project/squirrelmail/stable/1.4.22/squirrelmail-webmail-1.4.22.zip

Unzip the zip file into the document root of your webserver.

sudo unzip squirrelmail-webmail-1.4.22.zip -d /var/www/html/

Now, we will rename squirrelmail-webmail-1.4.22 so that it could be easy to remember & access.

sudo mv squirrelmail-webmail-1.4.22/ squirrelmail

Reset permissions and ownership on your webroot.

sudo chmod 755 -R /var/www/html/
sudo chown apache:apache -R /var/www/html/

SquirrelMail uses two directories to store the user configuration and the attachments that are about to be sent.

  1. Data directory: It is used for storing user preferences, like their signature, theme, address book (by default), and other information specific to each user.
  2. Attachments directory: It is used for temporarily storing attachments which needs to be cached at the server before being sent.

NOTE: It’s preferred, for security reasons, to have these directories outside the web tree.

We will create these two directories and will grant them required permissions and ownership.

sudo mkdir -p /var/local/squirrelmail/attach
sudo mkdir -p /var/local/squirrelmail/data
sudo chmod 755 -R /var/local/squirrelmail/attach
sudo chown apache:apache -R /var/local/squirrelmail/attach
sudo chmod 755 -R /var/local/squirrelmail/data
sudo chown apache:apache -R /var/local/squirrelmail/data

Restart apache service.

systemctl restart httpd 

Step 6: Open all of the needed ports on the firewall.

In case if it is a EC2 instance of AWS, you’ll need go to > security groups > inbound rules. From there you’ll be able to add the following ports.

  • HTTPS: 443
  • SMTP: 25
  • POP3: 110
  • IMAP: 143
  • SMTP Secure: 465
  • MSA: 587
  • IMAP Secure: 993
  • POP3 Secure: 995

Step 7: Testing our Mail server

After everything is set-up. It’s time to test if we are capable of sending and receiving of mails.

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

Input any email account we configured earlier and its corresponding password and try sending and receiving of mails from squirrelmail console.

____________________________________________________________________________________________________________________________

OpenDKIM is method to digitally sign & verify emails on the mail servers using public & private keys.
Configure Opendkim, click here > Configure OpenDKIM with Postfix on CentOS 7

Leave a Reply

Your email address will not be published. Required fields are marked *