Serveur mail Postfix et Dovecot

Sources de la documentation :

Procédure validée sur Debian 12.

Présentation du projet

Nous souhaitons installer un serveur SMTP Postfix et un serveur IMAP Dovecot. Nous utiliserons SpamAssassin pour lutter contre les courriers indésirables. Nous configurerons également notre serveur afin d'être validé et reconnu comme émetteur de mails valides. Les comptes utilisateurs de notre serveur mail seront consignés soit dans une base MariaDB, soit dans un serveur OpenLDAP afin de permettre une plus grande souplesse de configuration.

Cette documentation est destinée à la fois aux personnes souhaitant installer leur serveur en réseau local ou pour un site Internet. Si vous êtes dans le premier cas, ignorez les étapes concernant l'installation d'un serveur public.

Pré-requis

Nous allons utiliser une base LAMP pour notre serveur. Pour cela, nous installons les paquets suivants :

apt -y install apache2

Nous allons configurer Apache. Pour cela, éditez le fichier /etc/apache2/sites-available/000-default.conf et éditez la ligne suivante :

#ServerName www.example.com

Dé-commentez la et replacez le nom de domaine par celui sur lequel vous installez votre serveur mail :

ServerName example.com

Créez le fichier /etc/apache2/sites-available/thunderbird-autoconfig.conf comme suit :

<VirtualHost *:80>
ServerName autoconfig.example.com
DocumentRoot /var/www/html/autoconfig/
<Directory /var/www/html/autoconfig/>
        Options -Indexes +FollowSymLinks +MultiViews -Includes -ExecCGI
        AllowOverride None
        Order allow,deny
        allow from all
</Directory>
</VirtualHost>

Activez le site et rechargez la configuration Apache :

a2ensite thunderbird-autoconfig
service apache2 reload

Configurez les entrées suivantes sur le DNS de votre nom de domaine en remplaçant le domaine et l'IP :

example.com. IN A 1.2.3.4
example.com. IN MX 10 example.com.
autoconfig.example.com IN CNAME example.com.
example.com. IN TXT "v=spf1 a mx -all"

Pour un serveur public

Si votre serveur mail est destiné à être utilisé sur Internet, vous devez disposer d'un nom de domaine et d'une IP fixe. Assurez-vous que les ports TCP 25, 80, 443, 465 et 993 sont ouverts et que vous pouvez y accéder depuis Internet.

Nous allons installer Let's Encrypt afin d'obtenir un certificat SSL reconnu. Pour cela, exécutez les commandes suivantes et suivez l'assistant en choisissant le mode Secure qui redirige tout trafic HTTP sur HTTPS :

apt -y install python-certbot-apache
certbot --authenticator webroot --installer apache --webroot-path /var/www/html -d example.com

Éditez la table cron de l'utilisateur root et renseignez la ligne suivante afin de demander automatiquement le renouvellement du certificat tous les dimanches :

0 3 * * 0 certbot renew && systemctl restart dovecot.service

Configurez l'entrée suivante sur le DNS de votre FAI en remplaçant le domaine et l'IP :

4.3.2.1.in-addr.arpa. IN PTR example.com

Installation des paquets

Nous allons ici installer tout ce qui est nécessaire à notre serveur mail :

Postfix
Serveur SMTP en charge du transfert des mails.
Dovecot
Serveur IMAP en charge de fournir les mails aux clients de messagerie.
SpamAssassin
Filtre anti-spam
ClamAV
Antivirus
OpenDKIM
Outil de génération de la clef DKIM
apt -y install postfix dovecot-core dovecot-imapd dovecot-lmtpd dovecot-managesieved dovecot-sieve spamassassin spamc clamav-daemon clamav clamsmtp opendkim opendkim-tools rsyslog mailutils nftables

Lors de l'installation, Postfix vous demande les questions suivantes :

Configuration type du serveur de messagerie
Site Internet
Domaine
Votre domaine

Autoriser le trafic vers le serveur mail et en loopback en modifiant le fichier /etc/nftables.conf. Adapter selon les autres services déjà installés :

Pensez à créer une règle pour SSH si vous utilisez ce service pour configurer votre serveur. Ne vous enfermez pas dehors !
#!/usr/sbin/nft -f

flush ruleset

table inet tableinet {
	chain input {
		type filter hook input priority filter; policy drop;
		iifname lo accept
		tcp dport 25 accept
		tcp dport 993 accept
		tcp dport 465 accept
		tcp dport 80 accept
		ct state {established,related} accept
	}
	chain forward {
		type filter hook forward priority filter;
	}
	chain output {
		type filter hook output priority filter;
	}
}

Activer et redémarrer nftables :

systemctl enable nftables.service
systemctl restart nftables.service

Initialisation de la base de données / de l'annuaire

Configuration avec MariaDB

Le serveur Postfix gère par défaut les utilisateurs en provenance du système d'authentification Unix. Nous souhaitons utiliser à la place des utilisateurs virtuels stockés dans la base de données. Pour cela, nous allons créer la base de données stockant les comptes utilisateurs et les alias.

Installez les paquets supplémentaires :

apt -y install postfix-mysql dovecot-mysql mariadb-server

Connectez-vous à la base de données MariaDB :

mysql -u root -p

Saisissez les commandes suivantes afin de créer la base de données :

CREATE DATABASE postfix;
USE postfix;

CREATE TABLE addresses (
	email VARCHAR(50) NOT NULL PRIMARY KEY,
	active TINYINT(1) NOT NULL DEFAULT 1,
	passwd VARCHAR(106) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE aliases (
	source VARCHAR(50) NOT NULL PRIMARY KEY,
	target VARCHAR(50) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE USER 'postfix'@'localhost' IDENTIFIED BY 'MonMotDePasseBaseDeDonnees';
GRANT SELECT ON postfix.addresses TO 'postfix'@'localhost';
GRANT SELECT ON postfix.aliases TO 'postfix'@'localhost';

Nous allons créer un premier utilisateur comme suit :

INSERT INTO postfix.addresses (email, active, passwd) VALUES ("antoine@example.com", 1, ENCRYPT('MotDePasseEmail', CONCAT('$6$', SUBSTRING(SHA(RAND()), -16)))); 

Nous allons créer un premier alias comme suit :

INSERT INTO postfix.aliases (source, target) VALUES ("apernot@example.com", "antoine@example.com");

Configuration avec OpenLDAP

Pour la création d'un annuaire OpenLDAP, reportez-vous à la documentation spécifique : Installation d'OpenLDAP, PAM-LDAP et NFS.

Installez les paquets supplémentaires :

apt -y install postfix-ldap dovecot-ldap

Pour la suite de cette documentation, les utilisateurs seront stockés dans l'OU ou=Utilisateurs,dc=example,dc=com avec la structure suivante :

dn: cn=pdubois,ou=Utilisateurs,dc=example,dc=com
objectClass: top
objectClass: inetOrgPerson
objectClass: posixAccount
cn: Paul Dubois
cn: pdubois
userPassword:: <hash du mot de passe>
sn: pdubois
gidNumber: 1100
homeDirectory: /home/pdubois
uid: pdubois
mail: pdubois@example.com
uidNumber: 1200

Configuration de Postfix

Inscrivez votre domaine dans le fichier /etc/mailname.

Créez l'utilisateur gérant les utilisateurs virtuels et le répertoire stockant les mails :

useradd -d /var/mail -U -u 5000 vmail
mkdir -p /var/mail/vmail/example.com
chown -R vmail:vmail /var/mail/vmail 

Éditez le fichier /etc/postfix/main.cf. Nous effectuerons les modifications suivantes :

Saisissez votre nom de domaine dans le champ myhostname :

myhostname = example.com

Retirez votre domaine du champ mydestination. Il est en effet impossible qu'un domaine soit affecté à des utilisateurs réels et virtuels à la fois.

Éditez la configuration propre à la gestion des domaines virtuels et la sécurité (modifier le chemin du certificat SSL si nécessaire) :

smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU)
biff = no
append_dot_mydomain = no
readme_directory = no
compatibility_level = 3.6

smtpd_tls_cert_file=/etc/letsencrypt/live/example.com/fullchain.pem
smtpd_tls_key_file=/etc/letsencrypt/live/example.com/privkey.pem
smtpd_tls_security_level=may

smtp_tls_CApath=/etc/ssl/certs
smtp_tls_security_level=may
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
smtpd_use_tls=yes
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache

smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
myhostname = example.com
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
myorigin = /etc/mailname
mydestination = localhost
relayhost = 
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all
inet_protocols = all

virtual_mailbox_domains = example.com
virtual_mailbox_base = /var/mail/vmail
virtual_gid_maps = static:5000
virtual_uid_maps = static:5000
virtual_minimum_uid = 5000
virtual_mailbox_maps = mysql:/etc/postfix/mysql_virtual_mailbox_maps.cf
virtual_alias_maps = mysql:/etc/postfix/mysql_virtual_aliases.cf
virtual_transport = lmtp:unix:private/dovecot-lmtp
smtpd_sasl_auth_enable = yes
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_tls_auth_only = yes

# Signature OpenDKIM
milter_default_action = accept
milter_protocol = 2
smtpd_milters = inet:localhost:8892
non_smtpd_milters = inet:localhost:8892

# ClamAV
strict_rfc821_envelopes = yes
disable_vrfy_command = yes
smtpd_helo_required = yes
smtpd_client_restrictions =
smtpd_helo_restrictions =
smtpd_sender_restrictions =

content_filter = scan:localhost:10026

Pour une configuration utilisant LDAP, modifiez les lignes suivantes :

virtual_mailbox_maps = ldap:/etc/postfix/ldap_virtual_mailbox_maps.cf
virtual_alias_maps = ldap:/etc/postfix/ldap_virtual_aliases.cf

Modifiez les lignes suivantes dans le fichier /etc/postfix/master.cf en prenant garde à ce que les options (commençant par -o) doivent être précédées par au moins un espace :

smtp      inet  n       -       y       -       -       smtpd
  -o content_filter=spamassassin
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 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
pickup    unix  n       -       y       60      1       pickup
cleanup   unix  n       -       y       -       0       cleanup
qmgr      unix  n       -       n       300     1       qmgr
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 syslog_name=postfix/$service_name
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
postlog   unix-dgram n  -       n       -       1       postlogd

maildrop  unix  -       n       n       -       -       pipe
  flags=DRXhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
uucp      unix  -       n       n       -       -       pipe
  flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
ifmail    unix  -       n       n       -       -       pipe
  flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
bsmtp     unix  -       n       n       -       -       pipe
  flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient
scalemail-backend unix -       n       n       -       2       pipe
  flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension}
mailman   unix  -       n       n       -       -       pipe
  flags=FRX user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py ${nexthop} ${user}
spamassassin unix -     n       n       -       -       pipe
  user=debian-spamd argv=/usr/bin/spamc -f -e /usr/sbin/sendmail -oi -f ${sender} ${recipient}

# Antivirus
scan      unix  -       -       n       -       16      smtp
   -o smtp_send_xforward_command=yes
   -o disable_dns_lookups=yes
   -o smtp_data_done_timeout=1200

# For injecting mail back into postfix from the filter
localhost:10025 inet  n -       n       -       16      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_style=host
   -o smtpd_authorized_xforward_hosts=127.0.0.0/8

Configuration afin d'utiliser un relais SMTP

Un relais SMTP permet de faire transiter les messages émis sur un serveur relais afin que ces messages soient vus par le serveur destinataire comme émis par le relais. Cela est utile lorsque votre serveur ne peut être reconnu comme serveur de confiance (adresse IP publique dynamique, reverse DNS incorrect, etc.). Un compte valide sur un service mail permettant le relais SMTP sera nécessaire.

Modifiez le fichier /etc/postfix/main.cf comme suit :

Supprimez le domaine du champ mydestination autre que localhost et ajoutez les lignes suivantes :

relayhost=[mail.servicemail.net]:587
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl/sasl_passwd
smtp_sasl_security_options = noanonymous

Configurez le compte mail du relais dans le fichier /etc/postfix/sasl/sasl_passwd :

[mail.servicemail.net]:587 relais-smtp@servicemail.net:MotDePasseCompteRelaisSMTP

Générez le hash SASL :

postmap /etc/postfix/sasl/sasl_passwd

Configuration avec MariaDB

Créez le fichier /etc/postfix/mysql_virtual_mailbox_maps.cf et saisissez la configuration :

user = postfix
password = MonMotDePasseBaseDeDonnees
hosts = 127.0.0.1
dbname = postfix
query = SELECT 1 FROM addresses WHERE email = '%s'

Créez le fichier /etc/postfix/mysql_virtual_aliases.cf et saisissez la configuration :

user = postfix
password = MonMotDePasseBaseDeDonnees
hosts = 127.0.0.1
dbname = postfix
query = SELECT 1 FROM aliases WHERE source = '%s'

Testez en saisissant la commande suivante :

postmap -q antoine@example.com mysql:/etc/postfix/mysql_virtual_mailbox_maps.cf

Si vous obtenez 1, la configuration est correcte.

Configuration avec OpenLDAP

Créez le fichier /etc/postfix/ldap_virtual_mailbox_maps.cf et saisissez la configuration :

server_host = ldap://127.0.0.1
version = 3
bind = yes
bind_dn = cn=lecteur,dc=example,dc=com
bind_pw = MotDePasseLectureSeule
search_base = ou=Utilisateurs,dc=example,dc=com
scope = sub
query_filter = (&(mail=%s)(objectClass=inetOrgPerson))
result_attribute = mail

Créez le fichier /etc/postfix/ldap_virtual_aliases.cf et saisissez la configuration :

server_host = ldap://127.0.0.1
version = 3
bind = yes
bind_dn = cn=lecteur,dc=example,dc=com
bind_pw = MotDePasseLectureSeule
search_base = ou=Utilisateurs,dc=example,dc=com
scope = sub
query_filter = (&(mail=%s)(objectClass=alias))
result_attribute = mail

Testez en saisissant les commandes suivantes :

service clamav-daemon restart
service clamsmtp restart
service postfix restart
postmap -q pdubois@example.com ldap:/etc/postfix/ldap_virtual_mailbox_maps.cf

Si vous obtenez l'adresse mail demandée, la configuration est correcte.

Configuration d'OpenDKIM

Modifiez le fichier /etc/opendkim.conf :

Domain                  example.com
KeyFile                 /etc/postfix/dkim/mail.private
Selector                mail
Socket                  inet:8892@localhost

Dans le fichier /etc/default/opendkim, modifiez la ligne suivante :

SOCKET="inet:8892@localhost"

Créez et allez dans le dossier accueillant la clef, puis générez la.

mkdir /etc/postfix/dkim/
cd /etc/postfix/dkim/
opendkim-genkey -t -s mail -d example.com

Configurez une entrée TXT sur une seule ligne (ou DKIM) dans votre DNS avec le contenu du fichier /etc/postfix/dkim/mail.txt.

Configuration de Dovecot

Configurez le serveur Dovecot. Pour cela, nous allons modifier les lignes suivantes dans le fichier /etc/dovecot/conf.d/10-mail.conf :

mail_location = maildir:/var/mail/vmail/%d/%n
mail_privileged_group = vmail
mail_uid = 5000
mail_gid = 5000

Modifiez le fichier /etc/dovecot/conf.d/10-master.conf :

service imap-login {
	inet_listener imap {
	}
	inet_listener imaps {
		port = 993
		ssl = yes
	}
}
	
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 = 0666
	  #user =
	  #group =
	#}
}

Modifiez les chemins vers les certificats SSL dans le fichier /etc/dovecot/conf.d/10-ssl.conf (ajuster les chemins vers les certificats SSL si nécessaire) :

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

Modifiez la configuration du fichier /etc/dovecot/conf.d/15-lda.conf :

protocol lda {
  mail_plugins = $mail_plugins sieve
}

Modifiez la configuration du fichier /etc/dovecot/conf.d/15-mailboxes.conf :

mailbox Drafts {
  special_use = \Drafts
  auto = subscribe
}
mailbox Junk {
  special_use = \Junk
  auto = subscribe
}
mailbox Trash {
  special_use = \Trash
  auto = subscribe
}
mailbox Sent {
  special_use = \Sent
  auto = subscribe
}

Modifiez la configuration du fichier /etc/dovecot/conf.d/20-lmtp.conf :

protocol lmtp {
  mail_plugins = $mail_plugins sieve
  postmaster_address = pdubois@example.com
}

Ajoutez la ligne suivante au fichier /etc/dovecot/conf.d/90-sieve.conf :

sieve_after = /etc/dovecot/sieve/spamfilter.sieve

Générez les paramètres DH :

openssl dhparam 2048 > /etc/dovecot/dh.pem

Ajoutez la ligne suivante au fichier /etc/dovecot/conf.d/10-ssl.conf :

ssl_dh=</etc/dovecot/dh.pem

Configuration avec MariaDB

Le réglage des méthodes d'authentification se fait en modifiant le fichier /etc/dovecot/conf.d/10-auth.conf :

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

Renseignez les requêtes utilisées par Dovecot pour rechercher les utilisateurs virtuels dans la base de données en éditant le fichier /etc/dovecot/dovecot-sql.conf.ext :

driver = mysql
connect = host=127.0.0.1 dbname=postfix user=postfix password=MonMotDePasseBaseDeDonnees
default_pass_scheme = SHA512-CRYPT
password_query = \
   SELECT email as username, passwd AS password FROM addresses WHERE email = '%u'
user_query = \
   SELECT 5000 AS uid, 5000 as gid, email, '/var/mail/vmail/%d/%n' AS home \
   FROM addresses WHERE email = '%u'
iterate_query = SELECT email AS user FROM addresses

Configuration avec OpenLDAP

Le réglage des méthodes d'authentification se fait en modifiant le fichier /etc/dovecot/conf.d/10-auth.conf :

auth_mechanisms = plain login
#!include auth-system.conf.ext
!include auth-ldap.conf.ext

Renseignez les requêtes utilisées par Dovecot pour rechercher les utilisateurs virtuels dans la base de données en éditant le fichier /etc/dovecot/dovecot-ldap.conf.ext :

uris = ldap://127.0.0.1
dn = cn=lecteur,dc=example,dc=com
dnpass = MotDePasseLectureSeule
debug_level = 0
auth_bind = no
ldap_version = 3
base = ou=Utilisateurs,dc=example,dc=com
scope = subtree

user_attrs = homeDirectory=home
user_filter = (&(|(uid=%u)(mail=%u))(objectClass=inetOrgPerson))

pass_attrs = mail=user,userPassword=password
pass_filter = (&(|(uid=%u)(mail=%u))(objectClass=inetOrgPerson))

Redémarrez Dovecot et testez la connexion avec Dovecot :

service dovecot restart
doveadm auth test -x service=imap pdubois@example.com

Configuration de SpamAssassin

Si, au lieu de mettre les spam en pièce-jointe, vous souhaitez simplement les étiqueter comme tel, modifiez la ligne suivante dans le fichier /etc/spamassassin/local.cf :

report_safe 0

Activez le service au démarrage :

systemctl enable spamd.service

Configuration du système d'auto-configuration Thunderbird

Créez le fichier /var/www/html/autoconfig/mail/config-v1.1.xml :

<?xml version="1.0" encoding="UTF-8"?>
<clientConfig version="1.1">
  <emailProvider id="example.com">
    <domain>example.com</domain>
    <displayName>Mon domaine</displayName>
    <displayShortName>Mon domaine</displayShortName>
    <incomingServer type="imap">
      <hostname>example.com</hostname>
      <port>993</port>
      <socketType>SSL</socketType>
      <authentication>password-cleartext</authentication>
      <username>%EMAILADDRESS%</username>
    </incomingServer>
    <outgoingServer type="smtp">
      <hostname>example.com</hostname>
      <port>465</port>
      <socketType>SSL</socketType>
      <authentication>password-cleartext</authentication>
      <username>%EMAILADDRESS%</username>
    </outgoingServer>
  </emailProvider>
</clientConfig>

Démarrage et tests du service

Redémarrez les services :

service apache2 restart
service opendkim restart
service postfix restart
service dovecot restart
service spamd restart
service clamsmtp restart
service clamav-daemon restart

Nous allons tester l'envoi d'un mail :

echo "Ceci est mon premier mail" | mailx -s "Hello world" pdubois@example.com

Si un fichier mail correspondant au message envoyé est présent dans le répertoire /var/mail/vmail/example.com/pdubois/new, la configuration est correcte.