Se rendre au contenu

DKIM, SPF, DMARC pour Odoo — authentifier ses emails sortants

Série Tech-Email · Article 4/14 · Parcours Infrastructure
6 juin 2026 par
DKIM, SPF, DMARC pour Odoo — authentifier ses emails sortants
B.Mustapha
| Aucun commentaire pour l'instant

Parcours Infrastructure · Série Tech-Email

DKIM, SPF, DMARC pour Odoo 19 — sécuriser l'authentification de tes emails sortants

Trois protocoles, trois enregistrements DNS, un seul objectif : que tes emails Odoo arrivent en boîte de réception au lieu du dossier spam. Le pivot technique côté Odoo : le champ from_filter de ir.mail_server. Comprendre ce qu'il fait, et pourquoi il casse l'alignement DKIM s'il est mal réglé.

~13 minutes de lecture · niveau intermédiaire · parcours Infrastructure

Ce que tu vas apprendre

Les 3 protocoles

SPF, DKIM, DMARC — leur rôle, leur articulation, ce qu'Odoo fait (et ne fait pas).

Le pivot from_filter

Pourquoi ce champ d'ir.mail_server conditionne l'alignement DKIM.

3 records DNS prêts

Setup type Brevo + Odoo : TXT SPF, CNAME DKIM, TXT DMARC.

5 pièges fréquents

Encapsulation From, Return-Path mal aligné, ICPs legacy, SPF > 10 lookups…

Prérequis

  • Une instance Odoo 19 fonctionnelle (cf. installer Odoo 19 sur Ubuntu).
  • Accès admin Odoo : menu Settings → Technical → Email (mode développeur activé).
  • Accès au panneau DNS du domaine expéditeur (registrar OVH, Cloudflare, Gandi, Route 53…).
  • Un compte chez un relais SMTP transactionnel (Brevo, Mailjet, SES, Postmark…) ou un serveur Postfix dédié avec OpenDKIM.
  • Notions de base des enregistrements DNS : TXT, CNAME, MX.

1. Pourquoi trois protocoles complémentaires ?

SMTP a été conçu en 1982 sans aucune notion d'authentification. N'importe quel serveur peut prétendre envoyer du courrier au nom de n'importe quel domaine. Trois RFC successives ont rebouché ce trou : RFC 7208 pour SPF, RFC 6376 pour DKIM, RFC 7489 pour DMARC. Aucune ne suffit seule. Combinées, elles offrent une chaîne d'identité solide.

L'analogie qui aide à les retenir : imagine un envoi recommandé à la frontière.

  • SPF = la liste des transporteurs autorisés à présenter un colis au nom de l'expéditeur. Le douanier vérifie que le camion qui se présente figure bien sur la liste publique.
  • DKIM = un cachet cryptographique apposé sur l'enveloppe au départ. Le destinataire vérifie que le cachet est intact et que la clé publique correspond au domaine annoncé.
  • DMARC = l'instruction laissée au guichet : « si ni la liste ni le cachet ne sont alignés avec le nom du domaine sur le colis, alors mets-le en quarantaine ou rejette-le, et envoie-moi un rapport quotidien. »
SMTP entrant IP source + message DKIM-signé 1. Check SPF IP ∈ enregistrement SPF du domaine ? 2. Check DKIM Signature valide, clé publique DNS ? 3. Check DMARC SPF ou DKIM aligné avec From ? Accept (p=none) → inbox Quarantine (p=quarantine) → spam folder Reject (p=reject) → refusé SMTP Validation d'un email entrant — chaîne SPF → DKIM → DMARC DMARC consulte les résultats SPF et DKIM puis applique la politique publiée dans le DNS du domaine du header From.
Trois vérifications successives. SPF échoue ou DKIM échoue : DMARC tranche selon la politique publiée par le domaine de l'adresse From.

Le rôle d'Odoo dans cette chaîne

Odoo 19 ne signe pas DKIM et ne publie pas tes records DNS. Il prépare correctement les headers From, Return-Path et Reply-To — les mêmes mécaniques que celles utilisées par les templates email et le mixin mail.thread, sélectionne le bon relais SMTP via from_filter, et délègue ensuite l'envoi. C'est le relais transactionnel (Brevo, Mailjet, SES…) qui appose la signature DKIM, et c'est ton DNS qui publie SPF / DKIM / DMARC. La référence officielle : la documentation Odoo 19 sur les serveurs sortants. Le développeur Odoo a donc deux interfaces à maîtriser : ir.mail_server côté Odoo, et le panneau DNS côté domaine.

2. SPF — autoriser les IPs sortantes

SPF (Sender Policy Framework) publie dans le DNS la liste des IPs et des domaines autorisés à envoyer du courrier au nom du domaine. Côté destinataire, le serveur de réception lit l'enregistrement TXT et vérifie que l'IP source de la connexion SMTP s'y trouve.

L'enregistrement est un TXT à la racine du domaine :

; Type : TXT
; Nom  : @  (ou example.com.)
; Valeur :
"v=spf1 include:spf.brevo.com include:_spf.google.com ip4:91.121.55.78 ~all"

Lecture mécanique :

  • v=spf1 — version du protocole (toujours 1).
  • include:spf.brevo.com — inclut récursivement le SPF du relais Brevo (autorise toutes les IPs Brevo).
  • include:_spf.google.com — autorise les IPs Google Workspace si une partie du trafic part par Gmail.
  • ip4:91.121.55.78 — autorise explicitement un serveur dédié (Postfix sur VPS, par exemple).
  • ~allsoftfail pour toute autre source (recommandé en démarrage). Une fois sûr, passe à -all (hardfail).

Le Return-Path (l'enveloppe SMTP MAIL FROM) est l'adresse que SPF vérifie, pas le header From visible. Côté Odoo 19, le Return-Path est généré à partir de mail.alias.domain.bounce_email (typiquement bounce@example.com). Si ce domaine n'est pas couvert par le SPF publié, le check SPF échoue.

⚠️ Piège classique — la limite des 10 lookups DNS

SPF impose un maximum de 10 résolutions DNS (incluant les include: récursifs). Chaque include compte ; un include:_spf.google.com en consomme déjà entre 3 et 5 à lui seul. Si tu cumules Brevo, Google, Microsoft et un fournisseur newsletter, tu dépasses vite. Conséquence : PermError et SPF traité comme un échec. Outil de diagnostic : dig +short TXT example.com puis comptage manuel, ou un service tiers de validation SPF (MXToolbox, dmarcian).

3. DKIM — signature cryptographique du message

DKIM (DomainKeys Identified Mail, RFC 6376) ajoute un header DKIM-Signature au message au moment de l'envoi. Cette signature est calculée par le relais SMTP sortant à partir d'une clé privée. La clé publique correspondante est publiée dans le DNS sous un sélecteur (par exemple brevo._domainkey.example.com). Le serveur destinataire récupère la clé publique, vérifie la signature, et obtient deux informations critiques : le message n'a pas été altéré en transit, et il a bien été émis avec l'autorisation du propriétaire de la clé privée associée au domaine annoncé dans d=.

Exemple de header généré par un relais transactionnel :

DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=example.com;
    s=brevo; t=1748241600; h=from:to:subject:date:message-id;
    bh=47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=;
    b=ZjC3rW7w9Yc... (signature base64 tronquée)

Les champs qui comptent côté setup :

  • d=example.com — domaine signataire. C'est ce domaine qui doit être aligné avec le header From pour que DMARC valide.
  • s=brevo — sélecteur. Pointe vers l'enregistrement DNS brevo._domainkey.example.com qui publie la clé publique.
  • h=from:to:subject:date:message-id — liste des headers couverts par la signature. Si l'un d'eux est modifié en transit, la signature casse.

L'enregistrement DNS chez ton registrar est typiquement un CNAME qui pointe vers le DNS du relais (le relais gère la clé) :

; Type : CNAME
; Nom  : brevo._domainkey
; Valeur : brevo.brevo-1k.com.    (fourni par le provider)

Certains providers exposent directement la clé publique en TXT au lieu d'un CNAME. La procédure est identique du point de vue Odoo : rien à configurer côté Odoo, tout côté DNS et côté compte provider.

4. DMARC — politique d'alignement et reporting

DMARC (RFC 7489) est la colle entre SPF et DKIM. Il répond à deux questions : « que fait-on si l'email passe SPF ou DKIM mais que le domaine signataire n'est pas aligné avec le From visible ? » et « à qui envoyer le rapport quotidien des emails reçus en mon nom ? ».

L'enregistrement est un TXT sur le sous-domaine _dmarc :

; Type : TXT
; Nom  : _dmarc
; Valeur :
"v=DMARC1; p=none; rua=mailto:dmarc-reports@example.com; pct=100; aspf=r; adkim=r"

Décryptage :

  • p=none — politique observative en démarrage. Ne rejette rien, collecte les rapports. Puis p=quarantine, enfin p=reject quand tous les flux sortants sont identifiés et alignés.
  • rua=mailto:dmarc-reports@… — adresse de réception des rapports agrégés (Reporting URI Aggregate). Un rapport XML quotidien y atterrit, signé par chaque opérateur de boîtes de réception (Gmail, Outlook, Yahoo…).
  • pct=100 — pourcentage d'emails auxquels la politique s'applique. Utile pour un déploiement progressif (pct=10 = 10% des emails non conformes sont rejetés, le reste est observé).
  • aspf=r et adkim=r — mode d'alignement relaxed. Tolère que mail.example.com aligne avec example.com. s (strict) exige une correspondance exacte.

Industrie 2026 — l'enforcement Google/Yahoo/Microsoft

Depuis février 2024 chez Google et Yahoo, et mai 2025 chez Microsoft Outlook, les expéditeurs qui dépassent 5 000 messages/jour vers leurs boîtes doivent impérativement publier SPF, DKIM et DMARC alignés, sous peine de rejet SMTP direct. PCI DSS v4.0 impose également DMARC depuis 2026 pour toute organisation traitant des paiements par carte. Un déploiement p=none est tolérable quelques semaines en démarrage, mais la cible production est p=quarantine au minimum — ce qui s'inscrit dans une démarche plus large de sécurisation d'une instance Odoo en production.

5. Setup type — Brevo + Odoo 19 + 3 records DNS

Cas concret : domaine example.com, relais transactionnel Brevo, instance Odoo 19 envoyant les notifications, les emails de devis et les newsletters. Cinq étapes, pas une de plus.

Étape 1 — Valider le domaine dans le compte Brevo

Dans l'interface Brevo : Senders, Domains & Dedicated IPs → Domains → Add a new domain. Saisir example.com. Brevo fournit immédiatement :

  • 1 TXT de vérification de propriété (à supprimer une fois validée).
  • 1 valeur SPF à inclure (spf.brevo.com).
  • 2 CNAME DKIM (brevo1._domainkey et brevo2._domainkey — 2 sélecteurs pour rotation de clés).

Étape 2 — Publier les 3 records DNS

Chez le registrar (OVH, Cloudflare, Gandi…) :

; SPF
example.com.            IN  TXT     "v=spf1 include:spf.brevo.com ~all"

; DKIM
brevo1._domainkey       IN  CNAME   brevo1.brevo-1k.com.
brevo2._domainkey       IN  CNAME   brevo2.brevo-1k.com.

; DMARC
_dmarc.example.com.     IN  TXT     "v=DMARC1; p=none; rua=mailto:dmarc-reports@example.com; pct=100"

Propagation DNS : de quelques minutes à 24h selon le TTL configuré. Brevo détecte automatiquement la validation et marque le domaine « authenticated ».

Étape 3 — Configurer le serveur SMTP sortant dans Odoo

Settings → Technical → Email → Outgoing Mail Servers → Create :

ChampValeurPourquoi
nameBrevo TransactionnelLibellé interne.
smtp_hostsmtp-relay.brevo.comHôte SMTP fourni par Brevo.
smtp_port587STARTTLS standard.
smtp_encryptionstarttlsChiffrement à la connexion.
smtp_authenticationloginAuthentification login/password (pas OAuth2 pour Brevo).
smtp_userlogin Brevo fourniIdentifiant compte SMTP.
smtp_passclé API SMTP BrevoPas le mot de passe du compte web.
from_filterexample.comPoint critique pour l'alignement DKIM — voir ci-dessous.

Étape 4 — Configurer le mail.alias.domain

Depuis Odoo 17, la configuration des adresses de bounce, catchall et default_from est centralisée dans le modèle mail.alias.domain (et non plus dans l'ancien paramètre système mail.catchall.domain — voir piège n° 3 plus bas).

Settings → Technical → Email → Alias Domains :

ChampValeur
nameexample.com
bounce_aliasbouncebounce@example.com
catchall_aliascatchallcatchall@example.com
default_fromnotificationsnotifications@example.com

L'effet : tout email sortant utilisera notifications@example.com comme expéditeur par défaut, et bounce@example.com comme Return-Path. Le domaine example.com est couvert par le SPF, donc le check SPF passe. Le domaine est signé DKIM par Brevo, donc d=example.com. Les deux sont alignés avec le header From : DMARC valide.

Odoo 19 message_post() → From: notifications@ example.com _find_mail_server() match from_filter = "example.com" ? → ir.mail_server Relais Brevo connexion SMTP IP source = IP Brevo (autorisée SPF) Signature DKIM d=example.com s=brevo1 → DKIM aligné Envoi SMTP vers destinataire Chaîne Odoo → relais SMTP → email signé DKIM Le from_filter "example.com" est le pivot — il décide quel serveur prendra le message. Si from_filter ≠ domaine du From → Odoo encapsule l'expéditeur en "Untel via Notifications" → DKIM cassé côté alignement.
Le from_filter détermine quel ir.mail_server traite le message. S'il matche le domaine du header From, l'expéditeur est conservé, le relais signe avec le bon d=, et DMARC valide. Sinon, Odoo encapsule l'adresse et l'alignement casse.

Étape 5 — Tester la chaîne complète

Bouton Test Connection sur la fiche ir.mail_server — vérifie l'authentification SMTP. Puis envoi d'un email réel vers un service de validation externe (check-auth@verifier.port25.com, mail-tester.com) qui renvoie un rapport détaillé sur SPF, DKIM et DMARC en quelques secondes. Score cible : 10/10.

6. Vérification — les outils du DevOps email

Trois familles d'outils, à utiliser dans cet ordre : validation des records DNS, test d'envoi réel, lecture des rapports DMARC.

Validation des records DNS

  • MXToolbox (mxtoolbox.com) — lookup SPF, DKIM, DMARC. Affiche en clair le nombre de lookups SPF (alerte si proche de 10).
  • Google Admin Toolbox — Check MX — diagnostic complet du domaine côté Gmail.
  • dig en CLI : dig +short TXT example.com pour SPF, dig +short CNAME brevo1._domainkey.example.com pour DKIM, dig +short TXT _dmarc.example.com pour DMARC.

Test d'envoi réel

  • mail-tester.com — envoie un email à l'adresse fournie, retourne un score /10 avec détail SPF, DKIM, DMARC, contenu, blacklist.
  • check-auth@verifier.port25.com — répond automatiquement avec un rapport SMTP brut très complet.
  • Bouton « Tester la connexion » sur ir.mail_server dans Odoo — valide uniquement l'authentification SMTP, pas la signature DKIM. Toujours doubler avec un test réel externe.

Analyse des rapports DMARC

  • dmarcian.com — interface web qui agrège les rapports XML reçus à l'adresse rua=. Affiche un dashboard par source, IP, taux d'alignement.
  • PowerDMARC — alternative SaaS, freemium jusqu'à 10 000 messages/mois.
  • Parseur Python maison — les rapports DMARC sont des fichiers ZIP contenant un XML normalisé ; parsedmarc (PyPI) parse et exporte vers Elasticsearch / Splunk pour les setups internes.

7. Lire un rapport DMARC agrégé

Un rapport agrégé arrive quotidiennement à l'adresse rua=. Format : XML compressé en GZIP ou ZIP, envoyé par chaque opérateur (Google, Microsoft, Yahoo…). Extrait représentatif d'un rapport Google :

<feedback>
  <report_metadata>
    <org_name>google.com</org_name>
    <email>noreply-dmarc-support@google.com</email>
    <report_id>14831284727584810532</report_id>
    <date_range>
      <begin>1748131200</begin>
      <end>1748217599</end>
    </date_range>
  </report_metadata>
  <policy_published>
    <domain>example.com</domain>
    <adkim>r</adkim>
    <aspf>r</aspf>
    <p>none</p>
    <pct>100</pct>
  </policy_published>
  <record>
    <row>
      <source_ip>185.34.32.7</source_ip>
      <count>42</count>
      <policy_evaluated>
        <disposition>none</disposition>
        <dkim>pass</dkim>
        <spf>pass</spf>
      </policy_evaluated>
    </row>
    <identifiers>
      <header_from>example.com</header_from>
    </identifiers>
    <auth_results>
      <dkim><domain>example.com</domain><result>pass</result></dkim>
      <spf><domain>example.com</domain><result>pass</result></spf>
    </auth_results>
  </record>
</feedback>

Lecture utile :

  • source_ip + count — quelle IP envoie en mon nom, combien de messages.
  • policy_evaluated/dkim et spf — verdict DMARC pour chaque protocole.
  • auth_results — résultats bruts, avant prise en compte de l'alignement.
  • header_from — domaine présenté dans le header From.

Pattern à surveiller : une source_ip inconnue qui envoie en quantité avec dkim=fail ou spf=fail. C'est soit un ancien relais oublié dans le SPF, soit une newsletter tierce non autorisée, soit un usurpateur. Réaction : identifier l'IP, l'ajouter au SPF si légitime, ou passer la politique à p=quarantine si illégitime.

8. Cinq erreurs fréquentes (et comment les détecter)

1 — from_filter vide ou trop large

Symptôme : les emails partent, mais Gmail affiche « envoyé par brevo.com au nom de example.com » et le header From est encapsulé (« Notifications via … <notifications@brevo.com> »). Cause : from_filter vide → Odoo sélectionne le premier serveur disponible, qui ne signe pas forcément le domaine du From. Fix : renseigner précisément from_filter = example.com sur le serveur SMTP qui correspond au domaine signé DKIM.

2 — bounce_email sur un domaine différent du from_filter

Symptôme : SPF passe sur le header From, mais DMARC en mode strict échoue car le Return-Path (utilisé pour SPF identifier alignment) pointe sur un autre domaine. Fix : aligner le domaine de mail.alias.domain avec le from_filter. C'est presque toujours le même.

3 — ICP legacy mail.catchall.domain encore actif

Symptôme : les emails partent avec un From incohérent, le menu Settings → Technical → Email → Alias Domains affiche un domaine, mais le code utilise encore l'ancien paramètre système. Cause : une base migrée depuis v15/v16 garde l'ICP mail.catchall.domain qui prend le pas. Ce piège est typique d'une migration mal nettoyée vers Odoo 19. Fix : vérifier dans Technical → Parameters → System Parameters que mail.catchall.domain, mail.bounce.alias, mail.default.from n'existent plus, ou supprimer ces lignes. Odoo 19 migre automatiquement via _migrate_icp_to_domain() mais certains scripts d'import peuvent les recréer.

4 — SPF qui dépasse 10 lookups DNS

Symptôme : rapport DMARC affiche spf=permerror (erreur permanente — le nombre de résolutions DNS imbriquées dépasse la limite de 10 fixée par la RFC 7208, le check SPF est abandonné). Aucun email n'est rejeté par SPF lui-même, mais l'alignement DMARC échoue systématiquement. Fix : simplifier le SPF — remplacer les include: par des ip4: directs quand possible, ou consolider plusieurs relais sur un seul. Outil utile : dmarcian.com/spf-survey/.

5 — p=reject activé trop tôt

Symptôme : une newsletter Mailchimp envoyée par le service marketing arrête de livrer chez Gmail. La newsletter signait d=mailchimp.com sans alignement avec From: …@example.com. Fix : revenir à p=quarantine ou p=none, identifier toutes les sources légitimes dans le rapport DMARC, les ajouter au SPF, faire signer DKIM avec un domaine aligné, puis ré-escalader. Règle : 2 semaines minimum à p=quarantine avant de passer à p=reject.

Récapitulatif

  • SPF autorise les IPs sortantes au nom du domaine — TXT à la racine, attention aux 10 lookups.
  • DKIM signe le message cryptographiquement — CNAME ou TXT sous le sélecteur, géré par le relais transactionnel.
  • DMARC arbitre l'alignement et collecte les rapports — TXT sur _dmarc, démarre toujours en p=none.
  • Côté Odoo 19, le pivot est from_filter sur ir.mail_server. Aligne-le avec le domaine signé par le relais.
  • Le modèle mail.alias.domain (depuis v17) centralise bounce, catchall et default_from. Plus d'ICP mail.catchall.* à manipuler.
  • Industrie 2026 : Google, Yahoo et Microsoft imposent SPF + DKIM + DMARC aux expéditeurs > 5 000/jour. Pas négociable.

Le couplage Odoo ↔ relais SMTP est plus subtil qu'un simple branchement de serveur. Une fois les 3 records DNS publiés et le from_filter aligné, les rapports DMARC convergent vers 100% d'authentification en quelques jours. Et le développeur Odoo récupère une chaîne d'envoi vérifiable, traçable et conforme.

Pour la suite : la prochaine fois qu'un ticket « les emails Odoo finissent en spam » arrive, le réflexe est de vérifier dans cet ordre — record SPF / record DKIM / enregistrement DMARC / champ from_filter / mail.alias.domain. Quatre-vingt-quinze pour cent des cas se résolvent dans ces cinq points.

Voir aussi dans le parcours Infrastructure

Installer Odoo 19 sur Ubuntu / Debian

Mettre en place une instance Odoo 19 propre — service systemd, utilisateur dédié, base PostgreSQL.

Sécuriser Odoo en production

HTTPS, reverse proxy, hardening PostgreSQL, dbfilter, désactivation de la liste des bases.

Migration Odoo 18 → 19

Hooks pre_init / post_init, stages de migration, 7 breaking changes v18 → v19.

Série Tech-Email — Article 4/14 — Parcours Infrastructure emailing Odoo 19.

Articles complémentaires

Email templates et mail.thread en Odoo

Une fois la chaîne d'authentification posée, place à la rédaction : templates QWeb, héritage mail.thread, chatter custom.

Actions serveur, cron et automations

Déclencher l'envoi d'emails sur événement, planifier des relances automatiques, router les messages entrants vers les bons modèles.

Aller plus loin avec le Guide Technique OdooSkills

Le guide complet de la stack Odoo 19 — installation, modélisation, vues, héritage, tests, déploiement. Plus de 100 articles techniques structurés en parcours.

Explorer le parcours technique
Se connecter pour laisser un commentaire.
PostgreSQL pour le dev Odoo : psql, SELECT utiles, dump propre — sans casser sa base
Série Tech · Article 5/5 · Boîte à outils Linux du dev Odoo · Final