Introduction
This guide will help you configure your mail server with Postfix, Dovecot, MySQL and SpamAssassin in Ubuntu 18.04. This setup will allow you to add virtual domains, users and aliases and protect the virtual server from spam.
Requirements
- A domain directed towards the server.
- Pre-installed and configured MySQL DBMS.
- Root rights.
- Configured FQDN.
- Optional: SSL certificate.
Install Packages:
apt-get install postfix postfix-mysql dovecot-core dovecot-imapd dovecot-lmtpd dovecot-mysql
When prompted to configure Postfix, select Internet Site:
The Postfix configuration will ask about the system mail name - you can use your FDQN or the primary domain.
FQDN is a domain name with no ambiguities in the definition. It includes the names of all parent domains in the DNS hierarchy. In DNS and, most significantly, in zone files, FQDNs are terminated with a dot, i.e. include the root domain name, which is nameless.
Creating new database (MySQL) + Users
After the installation is complete, we will create a MySQL database to set up three different tables: one for domains, the other for users, and the last for aliases.
We call the database "spacemail", but you can use any name as you like.
Create the spacemail database:
mysqladmin -p create spacemail
Log in as MySQL root user
mysql -u root -p
Enter the MySQL root password; if successful, you will see the "mysql" console.
At first we need to add a new user, for mail authentication, and give him permission "SELECT"
mysql > GRANT SELECT ON spacemail.* TO 'userspace'@'127.0.0.1' IDENTIFIED BY 'mailpassword';
After that, we need to reload MySQL privileges to make sure that it has successfully applied these permissions:
mysql > FLUSH PRIVILEGES;
Finally, we need to use the database to create tables and enter our data:
mysql> USE spacemail;
We need to create new table for domains recognized as authorized domains.
CREATE TABLE `virtual_domains` (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Creating new table for introduce new users. At this table you need to add your email and password. You should associate each user with a domain.
CREATE TABLE `virtual_users` (
`id` INT NOT NULL AUTO_INCREMENT,
`domain_id` INT NOT NULL,
`password` VARCHAR(106) NOT NULL,
`email` VARCHAR(120) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `email` (`email`),
FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
We will create a table of virtual aliases to specify the mail and any emails you intend to forward to another one.
CREATE TABLE `virtual_aliases` (
`id` INT NOT NULL AUTO_INCREMENT,
`domain_id` INT NOT NULL,
`source` varchar(100) NOT NULL,
`destination` varchar(100) NOT NULL,
PRIMARY KEY (`id`),
FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
We have successfully created three tables. Now we are going to enter the data.
Virtual Domains
Here we are going to enter your domains into the virtual_domains table. You can add as many domains as you like, but in this guide we will only enter the primary domain (example.com) and your FQDN (hostname.example.com).
INSERT INTO `spacemail`.`virtual_domains`
(`id` ,`name`)
VALUES
('1', 'example.com'),
('2', 'hostname.example.com');
Virtual Emails
We are going to enter the email addresses and passwords associated with each domain. Make sure you change all the information to your specific one.
INSERT INTO `spacemail`.`virtual_users`
(`id`, `domain_id`, `password` , `email`)
VALUES
('1', '1', ENCRYPT('firstpassword', CONCAT('$6$', SUBSTRING(SHA(RAND()), -16))), 'email1@example.com'),
('2', '1', ENCRYPT('secondpassword', CONCAT('$6$', SUBSTRING(SHA(RAND()), -16))), 'email2@example.com');
Virtual aliases
We are going to enter an email address (source) that we are going to forward to another email address (destination).
INSERT INTO `spacemail`.`virtual_aliases`
(`id`, `domain_id`, `source`, `destination`)
VALUES
('1', '1', 'alias@example.com', 'email1@example.com');
Now u need to exit from database:
Exit
Postfix settings
We are going to configure Postfix to handle SMTP connections and send messages for each user entered in the MySQL database.
First we need to create a copy of the default file, in case you want to revert to the default configuration.
cp /etc/postfix/main.cf /etc/postfix/main.cf.orig
Open the main.cf file with any text editor to change it:
sudo vi /etc/postfix/main.cf
First we need to comment out the TLS parameters and add other parameters. We will also need SSL certificates. You can get them for free.
# TLS parameters
#smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
#smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
#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_cert_file=/etc/ssl/certs/dovecot.pem
smtpd_tls_key_file=/etc/ssl/private/dovecot.pem
smtpd_use_tls=yes
smtpd_tls_auth_only = yes
We will then add the following settings below the TLS settings we changed in the previous step:
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_recipient_restrictions =
permit_sasl_authenticated,
permit_mynetworks,
reject_unauth_destination
We need to comment out the default mydestination setting and replace it with localhost. This change will allow your VPS to use virtual domains inside the MySQL table.
#mydestination = example.com, hostname.example.com, localhost.example.com, localhost
mydestination = localhost
Make sure the myhostname parameter is set to your FQDN.
myhostname = hostname.example.com
Add the following line for local mail delivery to all virtual domains listed in the MySQL table.
virtual_transport = lmtp:unix:private/dovecot-lmtp
Finally, we need to add these three parameters to tell Postfix to configure virtual domains, users and aliases.
virtual_mailbox_domains = mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
virtual_mailbox_maps = mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
virtual_alias_maps = mysql:/etc/postfix/mysql-virtual-alias-maps.cf
We will create the last three files, which we will add to the main.cf file to tell Postfix how to connect to MySQL Database.
First we need to create a file mysql-virtual-mailbox-domains.cf. You will need to modify the values depending on your personal configuration.
nano /etc/postfix/mysql-virtual-mailbox-domains.cf
user = usermail
password = mailpassword
hosts = 127.0.0.1
dbname = spacemail
query = SELECT 1 FROM virtual_domains WHERE name='%s'
Postfix needs to be restarted.
service postfix restart
We need to make sure that Postfix finds your domain, so we need to check this with the following command. If successful, the command should return a value of 1:
postmap -q example.com mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
Then we need to create a mysql-virtual-mailbox-maps.cf file.
nano /etc/postfix/mysql-virtual-mailbox-maps.cf
user = usermail
password = mailpassword
hosts = 127.0.0.1
dbname = spacemail
query = SELECT 1 FROM virtual_users WHERE email='%s'
Rebooting Postfix again
service postfix restart
At this point we need to make sure that Postfix has found the first email address using the following command. If successful, it should return 1:
postmap -q email1@example.com mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
We will create one last file to set up the connection between Postfix and MySQL.
nano /etc/postfix/mysql-virtual-alias-maps.cf
user = usermail
password = mailpassword
hosts = 127.0.0.1
dbname = spacemail
query = SELECT destination FROM virtual_aliases WHERE source='%s'
Postfix restart
service postfix restart
We need to check that Postfix can find your aliases. Enter the following command and it should return mail redirected to an alias:
postmap -q alias@example.com mysql:/etc/postfix/mysql-virtual-alias-maps.cf
If you want to enable port 587 for secure connection to email clients, you need to modify /etc/postfix/master.cf
nano /etc/postfix/master.cf
We need to uncomment these lines and add other parameters:
submission inet n - - - - smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
In some cases, we need to restart Postfix to ensure that port 587 is open.
service postfix restart
Setting up Dovecot
We will copy the 7 files we will be modifying so that we can reset everything to default if necessary. Enter the following commands in turn.
cp /etc/dovecot/dovecot.conf /etc/dovecot/dovecot.conf.orig
cp /etc/dovecot/conf.d/10-mail.conf /etc/dovecot/conf.d/10-mail.conf.orig
cp /etc/dovecot/conf.d/10-auth.conf /etc/dovecot/conf.d/10-auth.conf.orig
cp /etc/dovecot/dovecot-sql.conf.ext /etc/dovecot/dovecot-sql.conf.ext.orig
cp /etc/dovecot/conf.d/10-master.conf /etc/dovecot/conf.d/10-master.conf.orig
cp /etc/dovecot/conf.d/10-ssl.conf /etc/dovecot/conf.d/10-ssl.conf.orig
Editing the configuration file from Dovecot.
nano /etc/dovecot/dovecot.conf
Make sure this parameter is not commented out.
!include conf.d/*.conf
We are going to include protocols (add pop3 if you want) below the line !include_try /usr/share/dovecot/protocols.d/*.protocol
!include_try /usr/share/dovecot/protocols.d/*.protocol
protocols = imap lmtp
Edit the mail configuration file:
nano /etc/dovecot/conf.d/10-mail.conf
Find the "mail_location" line, comment it out and put in the following parameter:
mail_location = maildir:/var/mail/vhosts/%d/%n
Find the "mail_privileged_group" line, comment it out and add the mail parameter as follows:
mail_privileged_group = mail
Verify permissions
Use this command:
ls -ld /var/mail
Make sure that the permissions look as follows:
drwxrwsr-x 3 root vmail 4096 Jan 24 21:23 /var/mail
We are going to create a folder for each domain that we register in the MySQL table:
mkdir -p /var/mail/vhosts/example.com
Create a vmail user and group with ID 5000
groupadd -g 5000 vmail
useradd -g vmail -u 5000 vmail -d /var/mail
We need to change the owner of the /var/mail folder to the user vmail.
chown -R vmail:vmail /var/mail
then we need to edit the file /etc/dovecot/conf.d/10-auth.conf:
nano /etc/dovecot/conf.d/10-auth.conf
Authenticate the plain text and add this line:
disable_plaintext_auth = yes
Change the auth_mechanisms parameter:
auth_mechanisms = plain login
Comment this line:
#!include auth-system.conf.ext
Enable MySQL authorisation by commenting out this line:
!include auth-sql.conf.ext
nano /etc/dovecot/conf.d/auth-sql.conf.ext
We need to create an /etc/dovecot/dovecot-sql.conf.ext file with your authentication information:
Enter the following code in the file:
passdb {
driver = sql
args = /etc/dovecot/dovecot-sql.conf.ext
}
userdb {
driver = static
args = uid=vmail gid=vmail home=/var/mail/vhosts/%d/%n
}
We need to change the file /etc/dovecot/dovecot-sql.conf.ext with our MySQL user information:
nano /etc/dovecot/dovecot-sql.conf.ext
Uncomment the driver parameter and set mysql as the parameter:
driver = mysql
Comment out the connect line and enter the MySQL-specific information:
connect = host=127.0.0.1 dbname=spacemail user=usermail password=mailpassword
Comment out the default_pass_scheme line and change it to SHA-512.
default_pass_scheme = SHA512-CRYPT
Comment out the password_query line and add this information:
password_query = SELECT email as user, password FROM virtual_users WHERE email='%u';
Change the owner and group of the dovecot folder to the user vmail:
chown -R vmail:dovecot /etc/dovecot
chmod -R o-rwx /etc/dovecot
Open and modify /etc/dovecot/conf.d/10-master.conf (be careful as various parameters will be changed).
nano /etc/dovecot/conf.d/10-master.conf
##Uncomment inet_listener_imap and modify to port 0
service imap-login {
inet_listener imap {
port = 0
}
#Create LMTP socket and this configurations
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
mode = 0600
user = postfix
group = postfix
}
#inet_listener lmtp {
# Avoid making LMTP visible for the entire internet
#address =
#port =
#}
}
Change the unix_listener parameter in service_auth as follows:
service auth {
unix_listener /var/spool/postfix/private/auth {
mode = 0666
user = postfix
group = postfix
}
unix_listener auth-userdb {
mode = 0600
user = vmail
#group =
}
#unix_listener /var/spool/postfix/private/auth {
# mode = 0666
#}
user = dovecot
}
Change the auth-worker service as follows:
service auth-worker {
# Auth worker process is run as root by default, so that it can access
# /etc/shadow. If this isn't necessary, the user should be changed to
# $default_internal_user.
user = vmail
}
The SSL configuration file from Dovecot must be changed (Skip if you will use the default configuration)
# nano /etc/dovecot/conf.d/10-ssl.conf
Change the ssl parameter to the required one:
ssl = required
And change the path for ssl_cert and ssl_key:
ssl_cert = </etc/ssl/certs/dovecot.pem
ssl_key = </etc/ssl/private/dovecot.pem
Restart Dovecot:
service dovecot restart
You should check that port 993 is open and working (in case you have enabled pop3; you should also check port 995).
telnet example.com 993
Configure SpamAssassin
First we need to install SpamAssassin.
apt-get install spamassassin spamc
Then we need to create a user for SpamAssassin.
adduser spamd --disabled-login
To successfully configure SpamAssassin, it's necessary to open and modify the configuration settings.
nano /etc/default/spamassassin
We need to change the ENABLED
parameter to enable SpamAssassin daemon.
ENABLED=1
We need to configure the home and options settings.
SPAMD_HOME="/home/spamd/"
OPTIONS="--create-prefs --max-children 5 --username spamd --helper-home-dir ${SPAMD_HOME} -s ${SPAMD_HOME}spamd.log"
We then need to specify the PID_File parameter as follows:
PIDFILE="${SPAMD_HOME}spamd.pid"
It is required to specify that SpamAssassin rules will be updated automatically.
CRON=1
We need to open the file /etc/spamassassin/local.cf to configure the anti-spam rules.
nano /etc/spamassassin/local.cf
SpamAssassin will evaluate each email and if it determines that the email is greater than 5.0 when checking for spam, it will automatically be considered spam. You can use the following settings to configure the anti-spam rules:
rewrite_header Subject ***** SPAM _SCORE_ *****
report_safe 0
required_score 5.0
use_bayes 1
use_bayes_rules 1
bayes_auto_learn 1
skip_rbl_checks 0
use_razor2 0
use_dcc 0
use_pyzor 0
We need to modify the Postfix file /etc/postfix/master.cf to specify that each email will be checked by SpamAssassin.
nano /etc/postfix/master.cf
Then we need to find the next line and add the spamassassin filter:
smtp inet n - - - - smtpd
-o content_filter=spamassassin
The following parameters must be added:
spamassassin unix - n n - - pipe
user=spamd argv=/usr/bin/spamc -f -e
/usr/sbin/sendmail -oi -f ${sender} ${recipient}
SpamAssassin must be started and Postfix restarted to start checking spam from the emails.
service spamassassin start
service postfix restart
You have successfully set up a mail server with Postfix and Dovecot with MySQL authentication and spam filtering using SpamAssassin!