v1.0.0

Mail server

# Config in distributor VPS web

Set Reverse DNS on VPS

mail.{domain}

Config SELinux

sudo nano /etc/selinux/config
SELINUX=disabled

Config HOSTNAME

sudo nano /etc/hosts
{IP_VPS} mail.{domain} mail

Config NetworkManager

sudo nano /etc/sysconfig/network
HOSTNAME=mail.{domain}

Restart NetworkManager service

sudo systemctl restart NetworkManager

Config DNS record

A        @                    3600        {IP}
A        mail                 3600        {IP}
MX       @                    3600        mail.{domain}
TXT      @                    3600        "v=spf1 +a +mx +ip4:{IP} ~all"
TXT      _dmarc               3600        "v=DMARC1; p=quarantine; pct=100; rua=mailto:{admin_email}; sp=none; aspf=r;"
TXT      default._domainkey   3600        "v=DKIM1; k=rsa; p={dkim_token};"

Test HOST

host {domain}
{domain} has address {IP}
{domain} mail is handled by {priority} mail.{domain}

Test nslookup

nslookup
> mail.{domain}
Name:    mail.{domain}
Address: {IP}
> exit

Test dig

dig {domain}
{domain}.      {number}      IN      A      {IP}
dig {domain} MX
{domain}.      {number}      IN      MX     10 mail.{domain}.

Test ping

ping mail.{domain}

# Install Postfix

Install Postfix

sudo dnf install -y postfix postfix-mysql

Enable and start Postfix service

sudo systemctl enable --now postfix

# Install Dovecot

Install Dovecot

sudo dnf install -y dovecot dovecot-mysql

Enable and start Dovecot service

sudo systemctl enable --now dovecot

# Create mail database

Login MySQL

mysql -u root -p

Create database

CREATE DATABASE {db_mail};

Create user MySQL

CREATE USER {user_mail}@localhost IDENTIFIED BY '{password_mail}';

Grand permission user with database

GRANT ALL PRIVILEGES ON {db_mail}.* TO {user_mail}@localhost;

Apply privileges

FLUSH PRIVILEGES;

Use database

USE {db_mail};

Create table domain

CREATE TABLE tbl_domains (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
active INT NOT NULL DEFAULT 1,
PRIMARY KEY (id),
UNIQUE KEY name (name))
ENGINE=InnoDB DEFAULT CHARSET=utf8;

Create table user

CREATE TABLE tbl_users (
id INT NOT NULL AUTO_INCREMENT,
email VARCHAR(255) NOT NULL,
password VARCHAR(255) NOT NULL,
full_name VARCHAR(255) NOT NULL,
department VARCHAR(255) NOT NULL,
active INT NOT NULL DEFAULT 1,
domain_id INT NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY email (email),
FOREIGN KEY (domain_id) REFERENCES tbl_domains(id) ON DELETE CASCADE)
ENGINE=InnoDB DEFAULT CHARSET=utf8;

Create table alias

CREATE TABLE tbl_aliases (
id INT NOT NULL AUTO_INCREMENT,
source VARCHAR(255) NOT NULL,
destination TEXT NOT NULL,
active INT NOT NULL default 1,
domain_id INT NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY source (source),
FOREIGN KEY (domain_id) REFERENCES tbl_domains (id))
ENGINE=InnoDB DEFAULT CHARSET=utf8;

Insert data to table

INSERT INTO tbl_domains (name, active) VALUES ('{domain}', '1');
INSERT INTO tbl_users (email, password, full_name, department, domain_id) VALUES ('{email}', ENCRYPT('{password}'), '{full_name}', '{department}', '1');
INSERT INTO tbl_aliases (source, destination, domain_id) VALUES ('{alias}@{domain}', '{email}', '1');

Test database

SELECT * FROM tbl_domains;
SELECT * FROM tbl_users;
SELECT * FROM tbl_aliases;
exit;

# Config Postfix

main.cf

sudo nano /etc/postfix/main.cf
myhostname = mail.{domain}

mydomain = {domain}

myorigin = $mydomain

inet_interfaces = all

mydestination = localhost, localhost.localdomain

mynetworks = 127.0.0.0/8

relayhost = 

recipient_delimiter = +

smtpd_banner = $myhostname ESMTP $mail_name

biff = no

Move end of file

# Config SASL Authentication
# Enabling SMTP for authenticated users, and handing off authentication to Dovecot 
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
broken_sasl_auth_clients = yes
smtpd_sasl_authenticated_header = yes
virtual_transport = lmtp:unix:private/dovecot-lmtp
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated permit_inet_interfaces reject_unauth_destination

# Config Virtual mailbox settings 
# Virtual domains, users, and aliases
virtual_alias_domains =
virtual_alias_maps = proxy:mysql:/etc/postfix/mysql-virtual_forwardings.cf, mysql:/etc/postfix/mysql-virtual_email2email.cf
virtual_mailbox_domains = proxy:mysql:/etc/postfix/mysql-virtual_domains.cf
virtual_mailbox_maps = proxy:mysql:/etc/postfix/mysql-virtual_mailboxes.cf
virtual_mailbox_base = /home/{user_mail}
virtual_uid_maps = static:5000
virtual_gid_maps = static:5000
virtual_create_maildirsize = yes
virtual_maildir_extended = yes
proxy_read_maps = $local_recipient_maps $mydestination $virtual_alias_maps $virtual_alias_domains $virtual_mailbox_maps $virtual_mailbox_domains $relay_recipient_maps $relay_domains $canonical_maps $sender_canonical_maps $recipient_canonical_maps $relocated_maps $transport_maps $mynetworks $virtual_mailbox_limit_maps

# SSL-TLS parameters
smtpd_use_tls = yes
smtpd_tls_auth_only = yes
smtp_tls_security_level = may
smtpd_tls_security_level = may
smtpd_tls_cert_file = /etc/letsencrypt/live/{domain}/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/{domain}/privkey.pem
smtpd_sasl_security_options = noanonymous, noplaintext
smtpd_sasl_tls_security_options = noanonymous

# Integrate OpenDKIM with Postfix
smtpd_milters = inet:127.0.0.1:8891
non_smtpd_milters = $smtpd_milters
milter_default_action = accept

# Integrate Amavis-new with Postfix
content_filter=smtp-amavis:[127.0.0.1]:10024

mysql-virtual_domains.cf

sudo nano /etc/postfix/mysql-virtual_domains.cf
user = {user_db}
password = {password_db}
dbname = {db_name}
query = SELECT name FROM tbl_domains WHERE name='%s' AND active=1
hosts = 127.0.0.1

mysql-virtual_forwardings.cf

sudo nano /etc/postfix/mysql-virtual_forwardings.cf
user = {user_db}
password = {password_db}
dbname = {db_name}
query = SELECT destination FROM tbl_aliases WHERE source='%s' AND active=1
hosts = 127.0.0.1

mysql-virtual_mailboxes.cf

sudo nano /etc/postfix/mysql-virtual_mailboxes.cf
user = {user_db}
password = {password_db}
dbname = {db_name}
query = SELECT CONCAT(SUBSTRING_INDEX(email, '@', -1), '/', SUBSTRING_INDEX(email, '@', 1), '/') FROM tbl_users WHERE email='%s' AND active=1
hosts = 127.0.0.1

mysql-virtual_email2email.cf

sudo nano /etc/postfix/mysql-virtual_email2email.cf
user = {user_db}
password = {password_db}
dbname = {db_name}
query = SELECT email FROM tbl_users WHERE email='%s' AND active=1
hosts = 127.0.0.1

Assign permission for mysql-virtual_*

sudo chmod o= /etc/postfix/mysql-virtual_*
sudo chgrp postfix /etc/postfix/mysql-virtual_*

Test connection

sudo postmap -q {domain} mysql:/etc/postfix/mysql-virtual_domains.cf
{domain}
sudo postmap -q {email} mysql:/etc/postfix/mysql-virtual_mailboxes.cf
{domain}/{email_name}
sudo postmap -q {alias}@{domain} mysql:/etc/postfix/mysql-virtual_forwardings.cf
{email}

Create group and assign permission

sudo groupadd -g 5000 {user_mail}
sudo useradd -g {user_mail} -u 5000 {user_mail} -d /home/{user_mail} -m

master.cf

sudo nano /etc/postfix/master.cf
smtp       inet  n       -       n       -       -       smtpd
  -o content_filter=spamassassin
submission inet  n       -       n       -       -       smtpd
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_sasl_type=dovecot
  -o smtpd_sasl_path=private/auth
  -o smtpd_reject_unlisted_recipient=no
  -o smtpd_client_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
  -o content_filter=spamassassin

Move end of file

dovecot      unix  -       n       n       -       -       pipe     flags=DRhu user={user_mail}:{user_mail} argv=/usr/libexec/dovecot/deliver -f ${sender} -d ${recipient}
spamassassin unix  -       n       n       -       -       pipe     flags=R    user=spamd                   argv=/usr/bin/spamc -e /usr/sbin/sendmail -oi -f ${sender} ${recipient}
smtp-amavis  unix  -       -       n       -       2       smtp
  -o smtp_data_done_timeout=1200
  -o smtp_send_xforward_command=yes
  -o disable_dns_lookups=yes
127.0.0.1:10025 inet n     -       n      -        -       smtpd
  -o content_filter=
  -o local_recipient_maps=
  -o relay_recipient_maps=
  -o smtpd_restriction_classes=
  -o smtpd_client_restrictions=
  -o smtpd_helo_restrictions=
  -o smtpd_sender_restrictions=
  -o smtpd_recipient_restrictions=permit_mynetworks,reject
  -o mynetworks=127.0.0.0/8
  -o strict_rfc821_envelopes=yes
  -o smtpd_error_sleep_time=0
  -o smtpd_soft_error_limit=1001
  -o smtpd_hard_error_limit=1000

Restart Postfix service

sudo systemctl restart postfix

Add service to Firewall

sudo firewall-cmd --permanent --add-service=smtp
sudo firewall-cmd --permanent --add-service=smtps

Reload Firewall service

sudo firewall-cmd --reload

# Config Dovecot

dovecot.cf

sudo nano /etc/dovecot/dovecot.conf
protocols = imap pop3 lmtp

listen = *

10-mail.conf

sudo nano /etc/dovecot/conf.d/10-mail.conf
mail_location = maildir:/home/{user_mail}/%d/%n/maildir

mail_privileged_group = mail

10-auth.conf

sudo nano /etc/dovecot/conf.d/10-auth.conf
disable_plaintext_auth = no (SMTP) yes (TLS)

auth_mechanisms = plain login

!include auth-sql.conf.ext

auth-sql.conf.ext

sudo nano /etc/dovecot/conf.d/auth-sql.conf.ext
userdb {
  driver = static
  args = uid=5000 gid=5000 home=/home/{user_mail}/%d/%n allow_all_users=yes
}

dovecot-sql.conf.ext

sudo nano /etc/dovecot/dovecot-sql.conf.ext
driver = mysql
connect = host=127.0.0.1 dbname={db_name} user={user_db} password={password_db}
default_pass_scheme = SHA512-CRYPT
password_query = SELECT email AS user, password FROM tbl_users WHERE email='%u' AND active=1;

Assign permission for dovecot-sql.conf.ext

sudo chgrp dovecot /etc/dovecot/dovecot-sql.conf.ext
sudo chmod o= /etc/dovecot/dovecot-sql.conf.ext

10-master.conf

sudo nano /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 = 0660
    user = postfix
    group = postfix
  }
}
service auth {
  unix_listener auth-userdb {
    mode = 0600
    user = {user_mail}
  }
  unix_listener /var/spool/postfix/private/auth {
    mode = 0660
    user = postfix
    group = postfix
  }
  user = dovecot
}
service auth-worker {
  user = {user_mail}
}

10-ssl.conf

Mail no SSL/TLS

sudo nano /etc/dovecot/conf.d/10-ssl.conf
ssl = no
#ssh_cert = ...
#ssh_key = ...

Mail with SSL/TLS

sudo nano /etc/dovecot/conf.d/10-ssl.conf
ssl = required
ssh_cert = </etc/letsencrypt/live/{domain}/fullchain.pem
ssh_key = </etc/letsencrypt/live/{domain}/privkey.pem

Restart Dovecot service

sudo systemctl restart dovecot

Restart Postfix service

sudo systemctl restart postfix

Add service to Firewall

sudo firewall-cmd --permanent --add-service=pop3
sudo firewall-cmd --permanent --add-service=pop3s

Reload Firewall service

sudo firewall-cmd --reload

# Test Postfix

Test SMTP

telnet mail.{domain} smtp
220 mail.{domain} ESMTP Postfix
ehlo mail.{domain}
250 mail.{domain}
...
quit

Test POP3

telnet mail.{domain} pop3
+OK Dovecot ready
quit

View log mail

sudo tail -f /var/log/maillog

# Roundcube

Download current release

wget https://github.com/roundcube/roundcubemail/releases/download/1.6.8/roundcubemail-1.6.8-complete.tar.gz

Extract file

tar xvf roundcubemail-1.6.8-complete.tar.gz

Rename folder

mv roundcubemail-1.6.8 webmail

Copy to Apache

sudo cp -rf webmail /var/www/html

Login MySQL

mysql -u root -p

Create database

CREATE DATABASE {db_roundcube};

Create user MySQL

CREATE USER {user_roundcube}@localhost IDENTIFIED BY '{password_roundcube}';

Grand permission user with database

GRANT ALL PRIVILEGES ON {db_roundcube}.* TO {user_roundcube}@localhost;

Apply privileges

FLUSH PRIVILEGES;
exit;

Init database

mysql -u {user_roundcube} -p {db_roundcube} < /var/www/webmail/SQL/mysql.initial.sql

Change timezone

sudo nano /etc/php.ini
date.timezone = Asia/Ho_Chi_Minh

Restart php-fpm service

sudo systemctl restart php-fpm

Access installer

https://mail.{domain}/installer

IMAP host

ssl://mail.{domain}:993

SMTP server

tls://mail.{domain}:587
ssl://mail.{domain}:465

Tick plugins and save config

Save as config.inc.php under /var/www/webmail/config/ directory

Give ownership to the folder

sudo chown -R apache:apache /var/www/html/webmail/temp
sudo chown -R apache:apache /var/www/html/webmail/logs

Grant write permissions to the directory

sudo chmod -R 755 /var/www/html/webmail/temp
sudo chmod -R 755 /var/www/html/webmail/logs

Restart httpd service

sudo systemctl restart httpd

Test send email and remove installer directory

# SpamAssassin

Install SpamAssassin

sudo dnf install -y spamassassin

Config SpamAssassin

sudo nano /etc/mail/spamassassin/local.cf
required_score 5

Assign permission for SpamAssassin

sudo groupadd -g 5555 spamd
sudo useradd -u 5555 -g spamd -s /bin/false -d /var/log/spamassassin spamd
sudo chown spamd:spamd /var/log/spamassassin

Enable and start SpamAssassin service

sudo systemctl enable --now spamassassin

Restart Dovecot service

sudo systemctl restart dovecot

Restart Postfix service

sudo systemctl restart postfix

Send email with SPAM title from another email to email config

XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X

# OpenDKIM

Install OpenDKIM

sudo dnf --enablerepo=epel,crb -y install opendkim opendkim-tools

Create public and private key

sudo opendkim-genkey -D /etc/opendkim/keys -d {domain}
ls -la /etc/opendkim/keys

Config OpenDKIM

sudo nano /etc/opendkim.conf
Mode sv

Socket inet:8891@127.0.0.1

Umask 022

Canonicalization relaxed/simple

Domain {domain}

# KeyFile ...

KeyTable refile:/etc/opendkim/KeyTable

SigningTable refile:/etc/opendkim/SigningTable

ExternalIgnoreList refile:/etc/opendkim/TrustedHosts

InternalHosts refile:/etc/opendkim/TrustedHosts
ls -la /etc/opendkim
sudo nano /etc/opendkim/KeyTable
default._domainkey.{domain} {domain}:default:/etc/opendkim/keys/default.private
sudo nano /etc/opendkim/SigningTable
*@{domain} default._domainkey.{domain}
sudo nano /etc/opendkim/TrustedHosts
# ::1
{domain}
mail.{domain}

Restart Dovecot service

sudo systemctl restart dovecot

Restart Postfix service

sudo systemctl restart postfix

Enable and start OpenDKIM service

sudo systemctl enable --now opendkim

Copy OpenDKIM key in config and paste to DNS default._domainkey record

sudo nano /etc/opendkim/keys/default.txt

Send email to verify

check-auth@verifier.port25.com

# Check virus

Install Amavisd

sudo dnf install -y clamav clamav-update amavisd-new

Config Amavisd

sudo nano /etc/amavisd/amavisd.conf
$mydomain = '{domain}';
$myhostname = 'mail.{domain}';
$notify_method  = 'smtp:[127.0.0.1]:10025';
$forward_method = 'smtp:[127.0.0.1]:10025';

Enable and start Amavisd service

sudo systemctl enable --now amavisd

Restart Postfix service

sudo systemctl restart postfix

Send email to another email and go to "Show original" and find X-Virus-Scanned