manuals:servers:mailserver


The following ports have to be opened in your firewall:

  25/tcp  # SMTP
  80/tcp  # HTTP (for autoconfiguration)
 443/tcp  # HTTPS (for autoconfiguration)
 587/tcp  # Submission
 993/tcp  # IMAP SSL


MariaDB is a community-developed fork of the MySQL relational database management system intended to remain free under the GNU GPL.

Install the database server:

sudo apt install mariadb-server

Harden it:

sudo mysql_secure_installation

Use one file per InnoDB table:

/etc/mysql/my.cnf
[mysqld]
innodb_file_per_table = 1

Restart the daemon:

sudo systemctl restart mariadb.service


Create a database called mailserver and a user called mailuser:

sudo mariadb
CREATE DATABASE mailserver;
GRANT SELECT ON mailserver.* TO 'mailuser'@'localhost' IDENTIFIED BY 'password';
FLUSH PRIVILEGES;
USE mailserver;

(Of course, change password to an actual password.)

Create tables

Domains:

CREATE TABLE `virtual_domains` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(50) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Users:

CREATE TABLE `virtual_users` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `domain_id` INT(11) NOT NULL,
  `password` VARCHAR(106) NOT NULL,
  `email` VARCHAR(100) 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;

Aliases:

CREATE TABLE `virtual_aliases` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `domain_id` INT(11) 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;


Add domains, users, aliases

Domains:

INSERT INTO `mailserver`.`virtual_domains`
  (`id` ,`name`)
VALUES
  ('1', 'quietlife.nl');

Users:

INSERT INTO `mailserver`.`virtual_users`
  (`id`, `domain_id`, `password` , `email`)
VALUES
  ('1', '1', ENCRYPT('user1-password', CONCAT('$6$', SUBSTRING(SHA(RAND()), -16))), 'user1@quietlife.nl'),
  ('2', '1', ENCRYPT('user2-password', CONCAT('$6$', SUBSTRING(SHA(RAND()), -16))), 'user2@quietlife.nl');

Aliases:

INSERT INTO `mailserver`.`virtual_aliases`
  (`id`, `domain_id`, `source`, `destination`)
VALUES
  ('1', '1', 'postmaster@quietlife.nl', 'root@quietlife.nl'),
  ('2', '1', 'root@quietlife.nl', 'user1@quietlife.nl');


Postfix is a free and open-source mail transfer agent (MTA) that routes and delivers electronic mail, intended as an alternative to Sendmail MTA.
sudo apt install postfix postfix-mysql


/etc/postfix/main.cf
smtpd_banner = $myhostname ESMTP
biff = no
append_dot_mydomain = no
readme_directory = no
compatibility_level = 2
 
# TLS parameters
smtp_dns_support_level = dnssec
smtp_tls_cert_file = /etc/letsencrypt/live/quietlife.nl/fullchain.pem
smtp_tls_key_file = /etc/letsencrypt/live/quietlife.nl/privkey.pem
smtp_tls_security_level = dane
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
 
smtpd_tls_auth_only = yes
smtpd_tls_cert_file = /etc/letsencrypt/live/quietlife.nl/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/quietlife.nl/privkey.pem
smtpd_tls_security_level = may
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtpd_tls_received_header = yes
 
# Use strong ciphers
smtp_tls_protocols = TLSv1.3, TLSv1.2, !TLSv1.1, !TLSv1, !SSLv2, !SSLv3
smtp_tls_mandatory_protocols = TLSv1.3, TLSv1.2, !TLSv1.1, !TLSv1, !SSLv2, !SSLv3
smtp_tls_ciphers = high
smtp_tls_mandatory_ciphers = high
smtp_tls_exclude_ciphers = EXP, LOW, MEDIUM, aNULL, eNULL, SRP, PSK, kDH, DH, kRSA, DHE, DSS, RC4, DES, IDEA, SEED, ARIA, CAMELLIA, AESCCM8, 3DES, ECDHE-ECDSA-AES256-SHA384, ECDHE-ECDSA-AES128-SHA256, ECDHE-RSA-AES256-SHA384, ECDHE-RSA-AES128-SHA256, MD5, SHA
 
smtpd_tls_protocols = TLSv1.3, TLSv1.2, !TLSv1.1, !TLSv1, !SSLv2, !SSLv3
smtpd_tls_mandatory_protocols = TLSv1.3, TLSv1.2, !TLSv1.1, !TLSv1, !SSLv2, !SSLv3
smtpd_tls_ciphers = high
smtpd_tls_mandatory_ciphers = high
smtpd_tls_exclude_ciphers = EXP, LOW, MEDIUM, aNULL, eNULL, SRP, PSK, kDH, DH, kRSA, DHE, DSS, RC4, DES, IDEA, SEED, ARIA, CAMELLIA, AESCCM8, 3DES, ECDHE-ECDSA-AES256-SHA384, ECDHE-ECDSA-AES128-SHA256, ECDHE-RSA-AES256-SHA384, ECDHE-RSA-AES128-SHA256, MD5, SHA
smtpd_tls_eecdh_grade = ultra
smtpd_tls_dh1024_param_file = /etc/ssl/dhparams.pem
 
tls_eecdh_ultra_curve = secp384r1
tls_high_cipherlist = EECDH+AESGCM:EDH+AESGCM
tls_preempt_cipherlist = yes
tls_ssl_options= NO_COMPRESSION, NO_RENEGOTIATION
 
# Enable SMTP for authenticated users and hand off authentication to Dovecot
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
 
# Network and host parameters
inet_interfaces = all
inet_protocols = all
mydestination = localhost
myhostname = vitas.quietlife.nl
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
myorigin = /etc/mailname
 
# Mail queue parameters
maximal_queue_lifetime = 12h
bounce_queue_lifetime = 12h
maximal_backoff_time = 1h
minimal_backoff_time = 5m
queue_run_delay = 5m
 
# Mailbox parameters
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
relayhost = 
mailbox_size_limit = 51200000
message_size_limit = 51200000
recipient_delimiter = +
disable_vrfy_command = yes
 
# Hand off local delivery to Dovecot's LMTP and tell it where to store mail
virtual_transport = lmtp:unix:private/dovecot-lmtp
 
# 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, mysql:/etc/postfix/mysql-virtual-email2email.cf
 
# Strip MUA headers
smtp_header_checks = regexp:/etc/postfix/header_checks
/etc/mailname
quietlife.nl
/etc/postfix/mysql-virtual-mailbox-domains.cf
user = mailuser
password = password
hosts = 127.0.0.1
dbname = mailserver
query = SELECT 1 FROM virtual_domains WHERE name='%s'
/etc/postfix/mysql-virtual-mailbox-maps.cf
user = mailuser
password = password
hosts = 127.0.0.1
dbname = mailserver
query = SELECT 1 FROM virtual_users WHERE email='%s'
/etc/postfix/mysql-virtual-alias-maps.cf
user = mailuser
password = password
hosts = 127.0.0.1
dbname = mailserver
query = SELECT destination FROM virtual_aliases WHERE source='%s'
/etc/postfix/mysql-virtual-email2email.cf
user = mailuser
password = password
hosts = 127.0.0.1
dbname = mailserver
query = SELECT email FROM virtual_users WHERE email='%s'
/etc/postfix/master.cf
# ==========================================================================
# service   type  private unpriv  chroot  wakeup  maxproc command + args
#                 (yes)   (yes)   (no)    (never) (100)
# ==========================================================================
smtp        inet  n       -       y       -       -       smtpd
#smtp       inet  n       -       y       -       1       postscreen
#smtpd      pass  -       -       y       -       -       smtpd
#dnsblog    unix  -       -       y       -       0       dnsblog
#tlsproxy   unix  -       -       y       -       0       tlsproxy
submission  inet  n       -       y       -       -       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
   -o milter_macro_daemon_name=ORIGINATING
#  -o smtpd_reject_unlisted_recipient=no
#  -o smtpd_helo_restrictions=$mua_helo_restrictions
#  -o smtpd_sender_restrictions=$mua_sender_restrictions
#  -o smtpd_recipient_restrictions=
#  -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
#smtps      inet  n       -       y       -       -       smtpd
#  -o syslog_name=postfix/smtps
#  -o smtpd_tls_wrappermode=yes
#  -o smtpd_sasl_auth_enable=yes
#  -o smtpd_reject_unlisted_recipient=no
#  -o smtpd_client_restrictions=$mua_client_restrictions
#  -o smtpd_helo_restrictions=$mua_helo_restrictions
#  -o smtpd_sender_restrictions=$mua_sender_restrictions
#  -o smtpd_recipient_restrictions=
#  -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
#  -o milter_macro_daemon_name=ORIGINATING
#628        inet  n       -       y       -       -       qmqpd
pickup      unix  n       -       y       60      1       pickup
   -o content_filter=
   -o receive_override_options=no_header_body_checks
cleanup     unix  n       -       y       -       0       cleanup
qmgr        unix  n       -       n       300     1       qmgr
#qmgr       unix  n       -       n       300     1       oqmgr
tlsmgr      unix  -       -       y       1000?   1       tlsmgr
rewrite     unix  -       -       y       -       -       trivial-rewrite
bounce      unix  -       -       y       -       0       bounce
defer       unix  -       -       y       -       0       bounce
trace       unix  -       -       y       -       0       bounce
verify      unix  -       -       y       -       1       verify
flush       unix  n       -       y       1000?   0       flush
proxymap    unix  -       -       n       -       -       proxymap
proxywrite  unix  -       -       n       -       1       proxymap
smtp        unix  -       -       y       -       -       smtp
relay       unix  -       -       y       -       -       smtp
#  -o smtp_helo_timeout=5 -o smtp_connect_timeout=5
showq       unix  n       -       y       -       -       showq
error       unix  -       -       y       -       -       error
retry       unix  -       -       y       -       -       error
discard     unix  -       -       y       -       -       discard
local       unix  -       n       n       -       -       local
virtual     unix  -       n       n       -       -       virtual
lmtp        unix  -       -       y       -       -       lmtp
anvil       unix  -       -       y       -       1       anvil
scache      unix  -       -       y       -       1       scache
/etc/postfix/header_checks
/^Received:.*with ESMTPSA/	IGNORE
/^X-Originating-IP:/		IGNORE


Refresh aliases:

sudo newaliases
sudo postmap /etc/aliases


Dovecot is an open-source IMAP and POP3 server for Linux/UNIX-like systems, written primarily with security in mind.
sudo apt install dovecot-core dovecot-imapd dovecot-lmtpd dovecot-mysql

Create a vmail user and vmail group and set permissions:

sudo groupadd -g 5000 vmail
sudo useradd -g vmail -u 5000 vmail -d /var/mail
sudo chown -R vmail:vmail /var/mail/
sudo mkdir -p /var/mail/vhosts/quietlife.nl/
sudo chmod 2700 /var/mail/vhosts/*
sudo chown -R vmail:dovecot /etc/dovecot/


/etc/dovecot/dovecot.conf
# Enable installed protocols
!include_try /usr/share/dovecot/protocols.d/*.protocol
protocols = imap lmtp
/etc/dovecot/conf.d/10-mail.conf
# Location for users' mailboxes.
mail_location = maildir:/var/mail/vhosts/%d/%n
 
[...]
 
# System user and group used to access mails.
mail_uid = vmail
mail_gid = vmail
 
# Group to enable temporarily for privileged operations.
mail_privileged_group = vmail
/etc/dovecot/conf.d/10-auth.conf
# Disable LOGIN command and all other plaintext authentications unless
# SSL/TLS is used (LOGINDISABLED capability).
disable_plaintext_auth = yes
 
[...]
 
# Space separated list of wanted authentication mechanisms:
auth_mechanisms = plain login
 
[...]
 
## Password and user databases
##
#!include auth-system.conf.ext
!include auth-sql.conf.ext
/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=/var/mail/vhosts/%d/%n
}
/etc/dovecot/dovecot-sql.conf.ext
# Database driver: mysql, pgsql, sqlite
driver = mysql
 
[...]
 
# Database connection string. This is driver-specific setting.
connect = host=localhost dbname=mailserver user=mailuser password=password
 
[...]
 
# Default password scheme.
default_pass_scheme = SHA512-CRYPT
 
[...]
 
# passdb query to retrieve the password.
password_query = SELECT email as user, password FROM virtual_users WHERE email='%u';
/etc/dovecot/conf.d/10-master.conf
# Enable imaps on port 993 only (disable imap on port 143)
service imap-login {
  inet_listener imap {
    port = 0
  }
  inet_listener imaps {
    port = 993
    ssl = yes
  }
 
[...]
 
# Disable pop3s and pop3
service pop3-login {
  inet_listener pop3 {
    port = 0
  }
  inet_listener pop3s {
    port = 0
    #ssl = yes
  }
}
 
# Enable lmtp for local delivery
service lmtp {
  unix_listener /var/spool/postfix/private/dovecot-lmtp {
    mode = 0600
    user = postfix
    group = postfix
  }
}
 
[...]
 
service auth {
  unix_listener auth-userdb {
    mode = 0600
    user = vmail
    group = vmail
  }
 
  # Postfix smtp-auth
  unix_listener /var/spool/postfix/private/auth {
    mode = 0666
    user = postfix
    group = postfix
  }
 
  # Auth process is run as this user.
  user = dovecot
}
 
service auth-worker {
  user = vmail
}
/etc/dovecot/conf.d/10-ssl.conf
# SSL/TLS support: yes, no, required.
ssl = required
 
[...]
 
# PEM encoded X.509 SSL/TLS certificate and private key.
ssl_cert = </etc/letsencrypt/live/quietlife.nl/fullchain.pem 
ssl_key = </etc/letsencrypt/live/quietlife.nl/privkey.pem
 
[...]
 
# Minimum SSL protocol version to use.
ssl_min_protocol = TLSv1.2
 
# SSL ciphers to use
ssl_cipher_list = EECDH+AESGCM:EDH+AESGCM
 
# Colon separated list of elliptic curves to use. Empty value (the default)
# means use the defaults from the SSL library. P-521:P-384:P-256 would be an
# example of a valid value.
ssl_curve_list = P-521:P-384
 
# Prefer the server's order of ciphers over client's
ssl_prefer_server_ciphers = yes 


Sender Policy Framework (SPF) is a simple email-validation system designed to detect email spoofing by providing a mechanism to allow receiving mail exchangers to check that incoming mail from a domain comes from a host authorized by that domain's administrators.
sudo apt install postfix-pcre postfix-policyd-spf-python


Add SPF to the Postfix configuration:

Change

/etc/postfix/main.cf
smtpd_recipient_restrictions = 
        permit_sasl_authenticated, 
        permit_mynetworks, 
        reject_unauth_destination

to

/etc/postfix/main.cf
smtpd_recipient_restrictions = 
        permit_sasl_authenticated, 
        permit_mynetworks, 
        reject_unauth_destination,
        check_policy_service unix:private/policyd-spf
 
policyd-spf_time_limit = 3600

(Mind the comma!)

/etc/postfix/master.cf
[...]
 
# SPF configuration
policyd-spf unix  -       n       n       -       0       spawn
  user=policyd-spf argv=/usr/bin/policyd-spf


Finally, add a DNS TXT record for @ (or quietlife.nl.), containing:

"v=spf1 mx -all"

This tells the receiving mailserver that all mails coming from your domain should originate from the IP's in your A / AAAA records.



DomainKeys Identified Mail (DKIM) is an email authentication method designed to detect email spoofing. It allows the receiver to check that an email claimed to have come from a specific domain was indeed authorized by the owner of that domain.
sudo apt install opendkim opendkim-tools


Add the opendkim user to the postfix group:

sudo adduser postfix opendkim


Create an /etc/opendkim directory to store the tables:

sudo mkdir /etc/opendkim
/etc/opendkim.conf
Syslog                  yes
SyslogSuccess           yes
LogWhy                  yes
 
Canonicalization        relaxed/simple
Mode                    sv
SubDomains              no
OversignHeaders         From
 
KeyTable                /etc/opendkim/key.table
SigningTable            refile:/etc/opendkim/signing.table 
ExternalIgnoreList      /etc/opendkim/trusted.hosts
InternalHosts           /etc/opendkim/trusted.hosts
 
UserID                  opendkim:postfix
UMask                   007
 
Socket                  local:/var/spool/postfix/var/run/opendkim/opendkim.sock
PidFile                 /var/spool/postfix/var/run/opendkim/opendkim.pid
 
TrustAnchorFile         /usr/share/dns/root.key

Change the 201902 example to the current year/month:

/etc/opendkim/key.table
quietlife.nl    quietlife.nl:201902:/etc/dkimkeys/quietlife.nl.private
/etc/opendkim/signing.table
*@quietlife.nl  quietlife.nl

Add localhost, your hostname, your domain name(s) and your FQDN to the trusted hosts:

/etc/opendkim/trusted.hosts
127.0.0.1
::1
localhost
vitas
quietlife.nl
vitas.quietlife.nl


Then override the OpenDKIM systemd unit file by running sudo systemctl edit opendkim.service. Add these lines:

[Service]
PIDFile=/var/spool/postfix/var/run/opendkim/opendkim.pid
User=opendkim
Group=postfix
ExecStart=
ExecStart=/usr/sbin/opendkim -P /var/spool/postfix/var/run/opendkim/opendkim.pid -p local:/var/spool/postfix/var/run/opendkim/opendkim.sock

And run sudo systemctl daemon-reload afterwards.

Add OpenDKIM to the Postfix configuration:

sudo mkdir -p /var/spool/postfix/var/run/opendkim
sudo chown opendkim:postfix /var/spool/postfix/var/run/opendkim
/etc/postfix/main.cf
[...]
 
# Use OpenDKIM to sign and verify mail
milter_default_action = accept
milter_protocol = 6
smtpd_milters = unix:var/run/opendkim/opendkim.sock
non_smtpd_milters = $smtpd_milters


Generate keys (use the current year/month instead of the example 201708):

opendkim-genkey -b 2048 -h rsa-sha256 -r -s 201708 -d quietlife.nl -v
sudo mv 201708.private /etc/dkimkeys/quietlife.nl.private
sudo chown opendkim:opendkim /etc/dkimkeys/quietlife.nl.private
mv 201708.txt dns.txt


Finally, add a DNS TXT record with the contents of dns.txt:

201708._domainkey  3600  IN  TXT  "v=DKIM1; h=sha256; k=rsa; s=email; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA63ggTqo80JaQBGV2uNreiX2/2yQx3PHbh9/4k+gIYO71ujqjGblk5z2FgzbWrTaIU7fZ0nN09bZAVDYavc9817fpYIYvnenDdKPJazl4hiVbBJL8jZ8/0ndu5WkCIzY60ukI423IAK+ppx7UW7Tpq38RokyFW8Wq96RAuhqeGkdxQN03N//yAtRCmeWwHw+jdGGq1WGbOKE7LcigRBMW9xPdJOk/rQPU2OjRh3b/BLohMYY0NX+0+Ybp0+5JuO6NZeYqWKbvezhtltTPrsYJU1m3cJTv11UxYiI8QPmSPGMJKVUevQv6Pn2aCARuNPIxSqfGwW6iwBhUZuxb1zQPCwIDAQAB"

(Change h=rsa-sha256 to h=sha256 and cut the key starting with v=DKIM1; …)



Amavis is an open source content filter for electronic mail, implementing mail message transfer, decoding, some processing and checking, and interfacing with external content filters to provide protection against spam, viruses and other malware.
sudo apt install amavisd-new pyzor razor p7zip-full spamassassin

Set up razor:

sudo su - amavis -s /bin/bash
razor-admin -create
razor-admin -register
exit


/etc/amavis/conf.d/15-content_filter_mode
# Default SPAM checking mode
# Please note, that anti-spam checking is DISABLED by
# default.
# If You wish to enable it, please uncomment the following lines:
@bypass_spam_checks_maps = (
   \%bypass_spam_checks, \@bypass_spam_checks_acl, \$bypass_spam_checks_re);
/etc/amavis/conf.d/20-debian_defaults
[...]
$final_spam_destiny       = D_DISCARD;
[...]
/etc/amavis/conf.d/50-user
$undecipherable_subject_tag = undef;
$virus_admin = undef;
$spam_admin = undef;
/etc/amavis/conf.d/05-node_id
# To manually set $myhostname, edit the following line with the correct Fully
# Qualified Domain Name (FQDN) and remove the # at the beginning of the line.
$myhostname = "localhost";

Add Amavis to the Postfix configuration:

/etc/postfix/main.cf
[...]
 
# Use Amavis to filter content
content_filter = smtp-amavis:localhost:10024
/etc/postfix/master.cf
[...]
 
# Amavis configuration
smtp-amavis unix  -       -       -       -       2       smtp
   -o smtp_data_done_timeout=1200
   -o smtp_send_xforward_command=yes
   -o disable_dns_lookups=yes
   -o max_use=20
localhost:10025 inet n    -       -       -       -       smtpd
   -o content_filter=
   -o local_recipient_maps=
   -o relay_recipient_maps=
   -o smtpd_restriction_classes=
   -o smtpd_delay_reject=no
   -o smtpd_client_restrictions=permit_mynetworks,reject
   -o smtpd_helo_restrictions=
   -o smtpd_sender_restrictions=
   -o smtpd_recipient_restrictions=permit_mynetworks,reject
   -o smtpd_data_restrictions=reject_unauth_pipelining
   -o smtpd_end_of_data_restrictions=
   -o mynetworks=127.0.0.0/8,[::ffff:127.0.0.0]/104,[::1]/128
   -o smtpd_error_sleep_time=0
   -o smtpd_soft_error_limit=1001
   -o smtpd_hard_error_limit=1000
   -o smtpd_client_connection_count_limit=0
   -o smtpd_client_connection_rate_limit=0
   -o receive_override_options=no_header_body_checks,no_unknown_recipient_checks,no_milters


The goal of autoconfiguration is to make it very easy for users to configure the connection to their email servers.

This guide assumes you use Apache or nginx, but any HTTP server will suffice.

The result is an autoconfiguration URL that mail clients like Thunderbird can parse to preconfigure settings.

Apache

/etc/apache2/sites-available/autoconfig.quietlife.nl.conf
<VirtualHost *:80>
   ServerName autoconfig.quietlife.nl
   DocumentRoot /var/www/autoconfig.quietlife.nl
    <Directory /var/www/autoconfig.quietlife.nl>
     Order allow,deny
     allow from all
    </Directory>
</VirtualHost>

Enable it:

sudo a2ensite autoconfig.quietlife.nl.conf
sudo systemctl reload apache2.service


nginx

/etc/nginx/sites-available/autoconfig.quietlife.nl
server {
        listen 80;
        listen [::]:80;
        server_name autoconfig.quietlife.nl;
        root /var/www/autoconfig.quietlife.nl;
}

Enable it:

cd /etc/nginx/sites-enabled/
sudo ln -s ../sites-available/autoconfig.quietlife.nl autoconfig.quietlife.nl
sudo systemctl reload nginx.service


Configuration

/var/www/autoconfig.quietlife.nl/mail/config-v1.1.xml
<?xml version="1.0" encoding="UTF-8"?>
<clientConfig version="1.1">
 <emailProvider id="quietlife.nl">
  <domain>quietlife.nl</domain>
  <displayName>quietlife.nl</displayName>
  <displayShortName>quietlife</displayShortName>
   <incomingServer type="imap">
    <hostname>quietlife.nl</hostname>
    <port>993</port>
    <socketType>SSL</socketType>
    <authentication>password-cleartext</authentication>
    <username>%EMAILADDRESS%</username>
   </incomingServer>
   <outgoingServer type="smtp">
    <hostname>quietlife.nl</hostname>
    <port>587</port>
    <socketType>STARTTLS</socketType>
    <authentication>password-cleartext</authentication>
    <username>%EMAILADDRESS%</username>
   </outgoingServer>
 </emailProvider>
</clientConfig>


Let's Encrypt certificates expire every three months, and certbot automatically renews them. After renewing the certificates, you have to reload Postfix and Dovecot. This can be automated with a script you put in /etc/letsencrypt/renewal-hooks/post/:

/etc/letsencrypt/renewal-hooks/post/mail.sh
#!/bin/sh
systemctl reload dovecot.service postfix.service

Make it executable:

sudo chmod +x /etc/letsencrypt/renewal-hooks/post/mail.sh


sudo systemctl restart postfix.service dovecot.service opendkim.service amavis.service


Failure is the state or condition of not meeting a desirable or intended objective, and may be viewed as the opposite of success.

Test your mail server status

Go to MxToolBox and run a test. Ideally, you should not see any problems.

Test DKIM DNS record

opendkim-testkey -d quietlife.nl -s 201902

If nothing is shown, your DNS record is set up properly.

Test signatures

Send an empty email to port25.com's verifier. It should return this:

==========================================================
Summary of Results
==========================================================
SPF check:          pass
DKIM check:         pass
SpamAssassin check: ham


In computing, Author Domain Signing Practices (ADSP) is an optional extension to the DKIM email authentication scheme, whereby a domain can publish the signing practices it adopts when relaying mail on behalf of associated authors.

If DKIM is working well, you can set up an ADSP record, telling the receiving mailserver that all mails coming from your domain should have a valid DKIM signature.

Add a DNS TXT record containing this:

_adsp._domainkey  3600  IN  TXT  "dkim=all"


Domain-based Message Authentication, Reporting and Conformance (DMARC) is an email-validation system designed to detect and prevent email spoofing. It is intended to combat certain techniques often used in phishing and email spam, such as emails with forged sender addresses that appear to originate from legitimate organizations.

If SPF and DKIM are working well, you can set up a DMARC record.

Add a DNS TXT record containing this:

_dmarc  3600  IN  TXT  "v=DMARC1; p=reject"


If you want to receive aggregate reports, you can set a rua option:

_dmarc  3600  IN  TXT  "v=DMARC1; p=reject; rua=mailto:postmaster@quietlife.nl"

If you also want to receive failure reports, you can set a ruf option:

_dmarc  3600  IN  TXT  "v=DMARC1; p=reject; rua=mailto:postmaster@quietlife.nl; ruf=mailto:postmaster@quietlife.nl"


More information about DMARC records can be found here.