Credit : Logo officiel
Configurer SPF et DKIM pour améliorer la délivrabilité email
Configurer SPF et DKIM pour améliorer la délivrabilité email
La semaine dernière, je dépanne un client e-commerce qui me balance le ticket classique : « Mes confirmations de commande arrivent en spam chez Gmail, et chez Orange ça passe même plus du tout ». Je sors mon dig, et là le diagnostic tombe en trente secondes : deux enregistrements SPF concurrents sur le domaine, un DKIM expiré côté Mailgun, et zéro DMARC. Résultat : ses 800 mails transactionnels par jour finissent en quarantaine. Ce genre de cas, j'en traite trois ou quatre par semaine au support. Et 95% du temps, c'est la même chose : SPF mal foutu, DKIM oublié, DMARC absent. Cet article, c'est ce que j'aurais aimé donner à ce client avant qu'il m'appelle.
Comprendre SPF, DKIM et DMARC : trois protocoles, un seul objectif
Quand un serveur de réception (Gmail, Outlook, Free, Orange) reçoit un mail prétendant venir de contact@boutique.fr, il doit décider : c'est légitime ou c'est du phishing ? Trois mécanismes répondent à cette question, chacun à sa façon.
SPF (Sender Policy Framework, RFC 7208) vérifie l'IP émettrice. Le domaine publie en DNS la liste des serveurs autorisés à envoyer en son nom. Si le mail arrive d'une IP non listée, SPF échoue.
DKIM (DomainKeys Identified Mail, RFC 6376) vérifie l'intégrité du message. Le serveur émetteur signe le mail avec une clé privée RSA, et le récepteur vérifie la signature via la clé publique publiée en DNS. Si le contenu a été modifié en transit, la signature casse.
DMARC (Domain-based Message Authentication, RFC 7489) orchestre les deux. Il dit au récepteur : « Si SPF ou DKIM échoue, voilà ce que tu fais (rien / quarantaine / rejet) et voilà où m'envoyer le rapport ». DMARC ajoute aussi la notion d'alignement : le domaine du From: visible doit matcher celui qui a passé SPF/DKIM. C'est ce qui bloque le spoofing classique.
| Protocole | Vérifie | Casse si... | Sans lui |
|---|---|---|---|
| SPF | IP émettrice | Mail relayé sans whitelist | N'importe qui peut spoofer |
| DKIM | Signature du contenu | Forwarders qui modifient les headers | Pas de preuve d'origine |
| DMARC | Alignement + politique | Sous-domaines mal configurés | SPF/DKIM sans dents |
Quand je dépanne, je vérifie toujours dans cet ordre : SPF d'abord (le plus rapide), DKIM ensuite, DMARC en dernier. Sans les deux premiers, DMARC ne sert à rien.
Configurer SPF : la base non-négociable
Le SPF est un simple enregistrement DNS de type TXT posé à la racine du domaine. Sa syntaxe est strictement définie par la RFC 7208.
Anatomie d'un enregistrement SPF
Voici un SPF typique pour un domaine hébergé chez IONOS qui envoie aussi via Mailgun :
v=spf1 include:_spf.perfora.net include:_spf.kundenserver.de include:mailgun.org ip4:203.0.113.42 -all
Décomposons mécanisme par mécanisme :
| Mécanisme | Rôle | Exemple |
|---|---|---|
v=spf1 |
Version (toujours 1) | Obligatoire en début |
a |
Autorise l'IP du record A du domaine | a:mail.boutique.fr |
mx |
Autorise les IP des MX du domaine | mx ou mx:autredomaine.fr |
ip4 |
IP ou CIDR IPv4 explicite | ip4:203.0.113.0/24 |
ip6 |
IPv6 | ip6:2001:db8::/32 |
include |
Inclut le SPF d'un autre domaine | include:_spf.google.com |
-all |
Hardfail : rejette tout le reste | À utiliser en prod stable |
~all |
Softfail : marque suspect | Phase de rodage |
?all |
Neutre | Inutile, autant ne rien mettre |
Records concrets selon l'hébergeur
IONOS (mail mutualisé) :
btw.fr. 3600 IN TXT "v=spf1 include:_spf.perfora.net include:_spf.kundenserver.de -all"
OVH (MX Plan) :
btw.fr. 3600 IN TXT "v=spf1 include:mx.ovh.com -all"
Cloudflare (en proxy DNS, mail via Google Workspace) :
btw.fr. 3600 IN TXT "v=spf1 include:_spf.google.com -all"
Serveur Postfix maison sur VPS :
btw.fr. 3600 IN TXT "v=spf1 a mx ip4:203.0.113.42 -all"
Le piège du « 10 lookups »
La RFC limite à 10 le nombre de lookups DNS générés par un SPF (chaque include, a, mx, exists, redirect compte). Au-delà, c'est PermError : SPF invalide, comme s'il n'existait pas.
Un include:_spf.google.com à lui seul descend en cascade et consomme 4 lookups. Quand on cumule Google Workspace + Mailgun + SendGrid + un MX maison, on explose le quota. Je résous ça en remplaçant les include lourds par les IP en dur (résolues une fois pour toutes), ou via un service de SPF flattening type DMARCLY ou EasyDMARC.
Hardfail vs softfail : quand passer de ~all à -all
Je recommande systématiquement la séquence suivante :
- Semaine 1-2 : déployer en
~all, surveiller les rapports DMARC enp=none. - Semaine 3-4 : si aucun mail légitime n'est marqué softfail, passer en
-all. - Au-delà : durcir DMARC (
p=quarantinepuisp=reject).
Les domaines en -all du jour 1 sans visibilité, c'est la meilleure recette pour bloquer un mailing list à 50k abonnés sans s'en rendre compte.
Configurer DKIM : signer chaque mail sortant
Le DKIM ajoute un header DKIM-Signature à chaque mail, contenant une signature RSA du contenu. La clé publique est publiée en DNS sur un sélecteur (ex : mail._domainkey.btw.fr).
Générer une clé DKIM avec OpenDKIM (Postfix)
Sur un serveur Postfix, j'utilise opendkim-tools :
sudo apt install opendkim opendkim-tools
sudo mkdir -p /etc/opendkim/keys/btw.fr
cd /etc/opendkim/keys/btw.fr
sudo opendkim-genkey -s mail -d btw.fr -b 2048
sudo chown opendkim:opendkim mail.private
sudo chmod 600 mail.private
opendkim-genkey produit deux fichiers :
mail.private: la clé privée (à laisser sur le serveur, jamais ailleurs).mail.txt: l'enregistrement DNS public à coller chez votre registrar.
Le contenu de mail.txt ressemble à :
mail._domainkey IN TXT ( "v=DKIM1; h=sha256; k=rsa; "
"p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvX..."
"...IDAQAB" )
Je recommande 2048 bits minimum. Les clés 1024 bits sont encore acceptées mais Google et Yahoo poussent vers 2048 depuis 2024. Au-delà de 2048, certains résolveurs DNS UDP coupent la réponse (limite 512 octets sans EDNS0) — restez à 2048.
DKIM via un service tiers (Mailgun, SendGrid, Brevo)
Les ESP gèrent eux-mêmes la clé. Vous n'avez qu'un CNAME ou TXT à publier :
Mailgun :
k1._domainkey.btw.fr. IN TXT "k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GN..."
mailo._domainkey.btw.fr. IN TXT "k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQ..."
SendGrid (CNAME pointant vers leur infra) :
s1._domainkey.btw.fr. IN CNAME s1.domainkey.u12345.wl.sendgrid.net.
s2._domainkey.btw.fr. IN CNAME s2.domainkey.u12345.wl.sendgrid.net.
Brevo (ex-Sendinblue) :
mail._domainkey.btw.fr. IN TXT "k=rsa; p=MIGfMA0GCSqG..."
Vous pouvez avoir plusieurs DKIM en parallèle sur des sélecteurs différents — un par service. C'est le seul moyen propre quand vous mixez transactionnel (Postmark) et marketing (Brevo).
Configurer OpenDKIM avec Postfix
Dans /etc/opendkim.conf :
Domain btw.fr
KeyFile /etc/opendkim/keys/btw.fr/mail.private
Selector mail
Socket inet:8891@localhost
Mode sv
Canonicalization relaxed/relaxed
Dans /etc/postfix/main.cf, on chaîne le milter :
milter_default_action = accept
smtpd_milters = inet:localhost:8891
non_smtpd_milters = inet:localhost:8891
Redémarrer puis tester :
sudo systemctl restart opendkim postfix
echo "Test DKIM" | mail -s "Test" check-auth@verifier.port25.com
Configurer DMARC : la politique qui ferme la porte
DMARC se publie sur le sous-domaine _dmarc :
_dmarc.btw.fr. 3600 IN TXT "v=DMARC1; p=quarantine; pct=100; rua=mailto:dmarc@btw.fr; ruf=mailto:dmarc@btw.fr; adkim=s; aspf=s; fo=1"
Les balises clés :
| Balise | Rôle | Valeurs |
|---|---|---|
p |
Politique principale | none / quarantine / reject |
sp |
Politique sous-domaines | idem |
pct |
% de mails affectés | 0 à 100 |
rua |
Rapports agrégés (XML quotidien) | mailto: |
ruf |
Rapports forensiques (par mail) | mailto: |
adkim |
Alignement DKIM | r (relaxed) / s (strict) |
aspf |
Alignement SPF | r / s |
fo |
Conditions d'envoi ruf |
0/1/d/s |
Politique progressive
Ne jamais sauter directement en p=reject. La progression saine que j'applique chez les clients :
- Mois 1 :
p=none; pct=100— observation pure, on collecte lesrua. - Mois 2 :
p=quarantine; pct=10— on quarantaine 10% du trafic non aligné. - Mois 3 :
p=quarantine; pct=100— quarantaine totale. - Mois 4+ :
p=reject— rejet à la porte SMTP.
Les rapports rua arrivent en XML zippé une fois par jour de chaque récepteur (Google, Microsoft, Yahoo, Mail.ru...). Pour les lire sans devenir fou, j'utilise Postmark DMARC Digests ou dmarcian en gratuit, ou je parse moi-même avec parsedmarc en self-hosted :
pip install parsedmarc
parsedmarc -o /var/log/dmarc/ /var/spool/mail/dmarc/*.zip
Les commandes shell que j'utilise tous les jours
Un dépannage de délivrabilité, ça se fait au terminal en cinq minutes si on connaît les bons outils.
Vérifier les enregistrements DNS
# SPF
dig +short TXT btw.fr | grep spf1
# DKIM (selector connu)
dig +short TXT mail._domainkey.btw.fr
# DMARC
dig +short TXT _dmarc.btw.fr
# MX
dig +short MX btw.fr
# Test depuis un autre résolveur (cache)
dig @1.1.1.1 TXT _dmarc.btw.fr
dig @8.8.8.8 TXT _dmarc.btw.fr
host fait pareil en plus court :
host -t TXT _dmarc.btw.fr
host -t TXT mail._domainkey.btw.fr
Tester la signature DKIM d'un mail reçu
Si vous avez le .eml sous la main :
opendkim-testmsg < message.eml
Retourne signature ok ou pointe la cause exacte du fail (selector introuvable, hash incorrect, body altéré).
Tester la clé privée vs la clé publique
Quand on doute d'un mismatch entre la clé en DNS et celle sur le serveur :
openssl rsa -in /etc/opendkim/keys/btw.fr/mail.private -pubout -outform der 2>/dev/null | openssl base64 -A
La sortie doit matcher la valeur p= publiée en DNS.
Outils en ligne (à connaître)
- mail-tester.com : envoyez un mail à l'adresse fournie, vous obtenez un score sur 10 avec détail SPF/DKIM/DMARC/SpamAssassin/contenu. Mon premier réflexe en diag.
- mxtoolbox.com/SuperTool.aspx : outil de référence pour SPF/DKIM/DMARC/blacklists.
- check-auth@verifier.port25.com : envoyez-lui un mail vide, il répond avec un rapport d'authentification complet.
- dmarcian.com/dmarc-inspector : visualise vos politiques DMARC.
Logs Postfix : la vérité brute
Quand un mail est refusé, le journal SMTP du serveur dit pourquoi :
tail -f /var/log/mail.log | grep -E 'reject|spf|dkim|dmarc'
journalctl -u postfix -f --since "10 min ago"
Un rejet typique en sortie :
postfix/smtp[12345]: 550 5.7.26 This message does not have authentication
information or fails to pass authentication checks (DMARC).
Ça, c'est Gmail qui vous dit : « ton DMARC est en p=reject et l'alignement a échoué ». Direction dig pour comprendre.
Erreurs courantes et leur fix
Voici le top 5 que je vois passer chaque semaine au support, dans l'ordre de fréquence.
1. Deux enregistrements SPF sur le même domaine
La RFC 7208 §3.2 est claire : un seul TXT SPF par domaine. Quand un client active un nouveau service (Mailchimp, par exemple) et duplique le record au lieu de fusionner, le récepteur tombe sur :
btw.fr. TXT "v=spf1 include:_spf.perfora.net -all"
btw.fr. TXT "v=spf1 include:servers.mcsv.net -all"
Résultat : PermError, SPF ignoré. Fix : un seul record fusionné :
btw.fr. TXT "v=spf1 include:_spf.perfora.net include:servers.mcsv.net -all"
2. Mismatch de sélecteur DKIM
Le serveur signe avec le sélecteur default mais le DNS publie sur mail. Le récepteur cherche default._domainkey.btw.fr, ne trouve rien, DKIM échoue. Fix : grep -r Selector /etc/opendkim* pour voir ce qu'utilise le serveur, puis vérifier que le record DNS existe sur ce nom exact.
3. DMARC sans alignement
SPF passe (l'IP est autorisée) et DKIM passe (signature valide), mais DMARC échoue quand même. C'est l'alignement : le From: visible (contact@btw.fr) doit matcher le domaine SPF (return-path) ou DKIM (d=). Beaucoup d'ESP utilisent leur propre return-path par défaut (bounce@mailgun.org), donc seul DKIM peut sauver l'alignement. Fix : configurer un return-path personnalisé chez l'ESP, ou activer le DKIM aligné sur votre domaine.
4. SPF en PERMERROR à cause des 10 lookups
Symptôme : dmarcian ou mxtoolbox affiche Too many DNS lookups. Chaque include pèse, et _spf.google.com à lui seul tire 4 sous-includes. Fix : flatten le SPF en remplaçant les includes par les IP brutes (à automatiser car les ESP changent leurs IP), ou passer par un service de flattening hosted.
5. TTL trop long pendant les tests
Quand on déploie une nouvelle clé DKIM ou un changement SPF, un TTL à 86400 (24h) signifie qu'on attend une journée à chaque modif. Fix : la veille du déploiement, baisser le TTL à 300 (5 minutes). Une fois la conf stable, remonter à 3600 ou 86400 pour décharger les résolveurs.
6. DKIM cassé par un forwarder
Un utilisateur transfère votre mail vers Gmail, et la signature casse parce que le forwarder a réécrit le sujet ou rajouté un [FWD]. Fix : utiliser la canonicalisation relaxed/relaxed côté OpenDKIM (tolère les changements d'espaces et de casse), et activer ARC (Authenticated Received Chain, RFC 8617) si on contrôle la chaîne.
Cas particulier : Google et Yahoo depuis février 2024
Depuis février 2024, Google et Yahoo exigent SPF + DKIM + DMARC pour tout expéditeur dépassant 5000 mails/jour vers leurs domaines. Sans DMARC en p=none minimum, les mails sont rejetés purement et simplement, ou la délivrabilité s'effondre. Microsoft (Outlook.com) a emboîté le pas en 2025.
Concrètement, pour un site e-commerce qui envoie confirmations + newsletters + relances paniers, on est très vite au-dessus du seuil. Donc même si DMARC restait optionnel jusqu'en 2023, il est désormais obligatoire de fait. Et il doit être aligné, pas juste posé.
Autre point : les expéditeurs en masse doivent fournir un lien de désinscription en un clic (header List-Unsubscribe: <mailto:...>, <https://...> + List-Unsubscribe-Post: List-Unsubscribe=One-Click). Si vous utilisez un ESP correct (Mailgun, Brevo, Postmark, SendGrid), c'est géré automatiquement. Sur un Postfix maison, à vous de l'ajouter.
Pour aller plus loin
- Configurer SPF, DKIM et DMARC pas à pas — le guide pas à pas avant celui-ci, parfait si vous partez de zéro.
- Configurer un serveur mail Postfix + Dovecot — l'envers du décor : monter sa propre infra mail self-hosted.
- Mettre en place un CDN gratuit avec Cloudflare — utile si vous gérez vos DNS chez Cloudflare et voulez profiter du proxy.
- Logs Linux : où chercher et comment lire — pour débugger Postfix, Exim ou OpenDKIM par leur trace.
- Hardening Linux : sécuriser un serveur — un serveur mail compromis devient relais de spam en quelques heures, à blinder.
Signaux verts au cockpit
Un domaine bien configuré, ça se reconnaît à trois choses : un seul SPF en -all qui tient les 10 lookups, un DKIM 2048 bits signé sur tous les flux sortants, un DMARC en p=quarantine ou p=reject avec rapports rua qui arrivent. Le reste, c'est de la maintenance : surveiller les rapports, ajouter le DKIM des nouveaux services, garder le SPF lean. Si vous appliquez ce qu'il y a au-dessus, vos confirmations de commande arrêtent de finir en spam, et vous arrêtez de recevoir des messages clients à 22h le vendredi soir. Au support, c'est la routine. Chez vous, ça doit l'être aussi.