Mettre en place l'envoi d'email authentifié (SPF + DKIM + DMARC)
Objectif : vos notifications applicatives (emails transactionnels émis par votre serveur) arrivent en boîte de réception plutôt qu'en spam — ou pire, silencieusement rejetées.
Ce guide suppose que vous savez déjà administrer un serveur Linux et éditer une zone DNS. Il vous donne la recette d'une chaîne d'envoi direct (le serveur remet lui-même au destinataire, sans relais SMTP tiers), authentifiée par les trois piliers DKIM, SPF et DMARC.
Pour le pourquoi de ces trois piliers et de leur articulation, voir SPF, DKIM, DMARC : pourquoi la délivrabilité email est difficile.
Le principe en une image
Application
│ (Mailer → remise locale : sendmail ou smtp://localhost)
â–Ľ
Signeur DKIM (milter — signe chaque mail sortant, au niveau OS)
│
â–Ľ
Serveur SMTP (« Internet Site » — remise DIRECTE au MX destinataire)
│
â–Ľ
MX du destinataire → vérifie DKIM / SPF / DMARC
Trois choses portent la délivrabilité d'un mail émis directement par un serveur :
- DKIM — une signature cryptographique posée par le serveur d'envoi, vérifiable via une clé publique publiée en DNS. C'est le pilier principal quand l'IP émettrice n'est couverte par aucun SPF réputé.
- PTR (reverse DNS) — l'IP émettrice résout vers un nom cohérent. Sans PTR propre, beaucoup de MX rejettent d'emblée.
- SPF et DMARC — publiés en DNS, ils déclarent qui a le droit d'émettre pour votre domaine et quoi faire en cas d'échec.
Choix d'architecture — envoi direct, pas de relais. Faire remettre le serveur directement au MX destinataire évite de dépendre d'une boîte mail relais tierce, mais impose de bâtir soi-même la réputation d'envoi (d'où l'importance de DKIM + PTR). Vérifiez que la sortie SMTP (port 25 sortant) n'est pas bloquée par votre hébergeur avant de vous engager dans cette voie.
1. Configurer le serveur SMTP en envoi direct
Configurez votre MTA (ici Postfix) en mode « Internet Site » : il livre directement, n'écoute pas le réseau, et ne relaie que ce que l'application locale lui remet.
# /etc/postfix/main.cf (extrait) myhostname = <VOTRE_HOSTNAME> mydomain = <VOTRE_DOMAINE> myorigin = $mydomain mydestination = localhost inet_interfaces = loopback-only # n'écoute que le loopback : pas de relais ouvert # ── Envoi DIRECT : aucun relayhost, aucun credential SMTP tiers ── # Brancher le signeur DKIM comme milter (signature avant remise) milter_default_action = accept smtpd_milters = local:/run/opendkim/opendkim.sock non_smtpd_milters = local:/run/opendkim/opendkim.sock
Points de sécurité :
inet_interfaces = loopback-only— le serveur n'accepte de mail que depuis la machine locale. Vous n'exposez pas un relais ouvert.- Pas de
relayhostni desasl_passwd— aucun secret d'authentification SMTP tiers à stocker, donc rien à fuiter.
Piège fréquent — IPv6 blocklistée. Si l'IPv6 de votre serveur est mal réputée (courant sur les IP mutualisées), les MX destinataires renvoient des bounces
550. Forcez la préférence IPv4 (smtp_address_preference = ipv4) tant que vous n'avez pas une IPv6 avec PTR et réputation propres.
2. Signer en DKIM (au niveau OS, multi-domaines)
La signature se fait au niveau du système (via un milter comme OpenDKIM), pas dans l'application. Un signeur OS signe uniformément tout ce qui sort, gère plusieurs domaines avec des clés distinctes, et évite qu'une signature applicative codée en dur ne casse le multi-domaines.
2.1 Choisir un sélecteur
Un sélecteur est une étiquette (ex. votre_selecteur) qui relie une signature à un enregistrement DNS précis. La signature s=votre_selecteur n'est validée que si l'enregistrement DNS existe sous votre_selecteur._domainkey.<VOTRE_DOMAINE>.
Conseil : datez ou versionnez votre sélecteur (ex. mailAAAA) pour pouvoir faire tourner les clés sans casser l'existant.
2.2 Générer une paire de clés par domaine
# Génère clé privée + enregistrement TXT public pour un domaine opendkim-genkey -b 2048 -s votre_selecteur -d <VOTRE_DOMAINE> -D /etc/opendkim/keys/<VOTRE_DOMAINE>
Protégez les clés privées : lecture réservée à l'utilisateur du signeur (chown opendkim:, chmod 600). Ne les commitez jamais en clair ; si vous les stockez dans de l'IaC, chiffrez-les (coffre / vault).
2.3 Déclarer qui signe quoi
Le signeur a besoin de deux tables — une ligne par domaine servi.
# signing.table : quel motif d'expéditeur → quelle identité de signature *@<VOTRE_DOMAINE> votre_selecteur._domainkey.<VOTRE_DOMAINE> # key.table : quelle identité → quel sélecteur + quelle clé privée votre_selecteur._domainkey.<VOTRE_DOMAINE> <VOTRE_DOMAINE>:votre_selecteur:/etc/opendkim/keys/<VOTRE_DOMAINE>/votre_selecteur.private
Réglages de fond du démon : mode signature+vérification, canonicalisation relaxed/simple, socket local partagé avec le MTA, et un TrustedHosts limité au loopback.
2.4 Publier la clé publique en DNS
Un enregistrement TXT par domaine, sous le sélecteur :
votre_selecteur._domainkey.<VOTRE_DOMAINE> TXT "v=DKIM1; h=sha256; k=rsa; p=<VOTRE_CLE_PUBLIQUE>"
Prérequis absolu : tant que cet enregistrement n'est pas publié et propagé, la vérification renvoie
dkim=fail. Publiez le DNS avant de mettre le signeur en production.
3. Publier SPF
Le SPF déclare quels serveurs ont le droit d'émettre pour votre domaine. Il dépend de l'hébergeur mail du domaine, pas du serveur d'envoi direct.
# Domaine dont la messagerie est hébergée par un fournisseur : incluez son mécanisme SPF <VOTRE_DOMAINE> TXT "v=spf1 include:<spf.votre_fournisseur> -all"
Important : pour les mails émis directement par votre serveur (notifications applicatives), l'IP du serveur n'est généralement pas dans le SPF du domaine. C'est normal — dans ce cas la délivrabilité repose sur DKIM + PTR + DMARC, pas sur SPF. Ajouter l'IP au SPF est une option, mais élargit la surface et complique la rotation d'IP.
Terminaison : -all (rejet strict) une fois sûr de votre inventaire d'émetteurs ; ~all (softfail) pendant la phase de rodage.
4. Publier DMARC
DMARC dit aux MX destinataires quoi faire quand DKIM et SPF échouent, et où vous envoyer les rapports.
_dmarc.<VOTRE_DOMAINE> TXT "v=DMARC1; p=quarantine; rua=mailto:dmarc@<VOTRE_DOMAINE>; pct=100"
Déploiement progressif recommandé :
p=none— mode observation : vous recevez les rapports sans impact sur la remise.p=quarantine— les mails non authentifiés partent en spam.p=reject— rejet pur, une fois DKIM/SPF stabilisés et les rapports propres.
5. Piège classique — le socket entre MTA et signeur
Le milter DKIM communique avec le MTA via un socket local. Le MTA doit pouvoir le lire, sinon les mails partent non signés (dkim=none) ou le MTA refuse de démarrer (milter: can't connect).
# Répertoire du socket : propriétaire = signeur, groupe = MTA sudo install -d -o opendkim -g postfix -m 750 /run/opendkim # Autoriser l'utilisateur du MTA à lire le socket du signeur sudo adduser postfix opendkim
6. Vérifier
# 1. La clé publique est-elle bien publiée et propagée ? dig +short TXT votre_selecteur._domainkey.<VOTRE_DOMAINE> # 2. SPF et DMARC publiés ? dig +short TXT <VOTRE_DOMAINE> dig +short TXT _dmarc.<VOTRE_DOMAINE> # 3. Envoi de test : inspectez les headers reçus echo "Test" | mail -s "test auth" vous@exemple.test
Dans le mail reçu, cherchez l'en-tête Authentication-Results. Vous visez :
Authentication-Results: ...; dkim=pass; spf=pass; dmarc=pass
dkim=none→ le milter n'a pas signé : revoyez le socket (§5) et les tables (§2.3).dkim=fail→ clé DNS absente, mauvaise ou non propagée (§2.4).dmarc=failavecp=reject→ le mail sera rejeté ; repassez enp=nonele temps de corriger.
Un service de test « mail-tester » externe ou l'inspection manuelle des headers suffisent à valider la chaîne bout en bout.
Côté application
Pointez simplement le Mailer sur la remise locale — aucune signature DKIM applicative (elle est faite par l'OS) :
MAILER_DSN=sendmail://default # ou MAILER_DSN=smtp://localhost:25
Checklist de mise en production
- Sortie SMTP (port 25) non bloquée par l'hébergeur, PTR de l'IP cohérent
- MTA en « Internet Site »,
inet_interfaces = loopback-only, pas de relayhost - Une paire de clés DKIM par domaine, clés privées en
600et non commitées en clair - Enregistrements DKIM, SPF, DMARC publiés et propagés
- Socket MTA ↔ signeur lisible (test :
dkim=passsur un mail réel) - DMARC démarré en
p=none, durci versquarantine/rejectaprès observation