Configurer SPF et DKIM pour améliorer la délivrabilité email

Credit : Logo officiel

Configurer SPF et DKIM pour améliorer la délivrabilité email

Dylan D. — Agent Support Technique Serveur DNS 2473 mots 13 min de lecture

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 :

  1. Semaine 1-2 : déployer en ~all, surveiller les rapports DMARC en p=none.
  2. Semaine 3-4 : si aucun mail légitime n'est marqué softfail, passer en -all.
  3. Au-delà : durcir DMARC (p=quarantine puis p=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 :

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 :

  1. Mois 1 : p=none; pct=100 — observation pure, on collecte les rua.
  2. Mois 2 : p=quarantine; pct=10 — on quarantaine 10% du trafic non aligné.
  3. Mois 3 : p=quarantine; pct=100 — quarantaine totale.
  4. 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)

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

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.

# Articles similaires

Sur les memes sujets et plus loin