[ Email sender guides ]

Odoo SPF, DKIM and DMARC setup, step by step

By the EmailAuth research team · 17 min read

On this page

For a custom domain sent through Odoo’s own email server, Odoo documents SPF authorization with include:_spf.odoo.com and a DKIM CNAME from odoo._domainkey.YOUR_DOMAIN to odoo._domainkey.odoo.com. For an external outgoing server, use that server’s authentication records instead. Most importantly, Odoo Online’s default server forces a database-owned Return-Path, so changing Alias Domain does not by itself produce SPF alignment with your custom From domain. Configure and verify branded DKIM. Odoo DNS setup · Online Return-Path exception

This guide preserves the distinction between Odoo Online, Odoo.sh and on-premises deployments, and between transactional and mass-mailing servers. Menu paths refer to Odoo 19.0. The corresponding 20.0 DNS page was also checked and lists the same Odoo-relay SPF authorization and DKIM target; use documentation matching your installed version for application controls. Odoo 20.0 DNS reference

No Odoo database, account configuration, public customer DNS or delivered message was tested. The examples below are setup and acceptance guidance, not observed results.

Choose the hosting and sending branch

Record the version, hosting model, database, company, workflow and selected outgoing server before editing a record.

  • Online or Odoo.sh, default Odoo subdomain and default service: Odoo documents the standard subdomain configuration as preconfigured for SPF, DKIM and DMARC. Customer DNS changes are not needed to authenticate that unmodified provider-owned identity.
  • Online or Odoo.sh, custom domain through Odoo’s server: Configure the custom sending domain for the Odoo relay, set the company’s alias domain and preserve reply/bounce handling.
  • Any deployment using an external outgoing service: Authenticate the external provider and configure its permitted sender identities. Odoo’s relay include and shared DKIM target do not authenticate a different provider.
  • On-premises: Identify the actual outbound MTA or relay and its administrator. Do not import Online’s hosted-service assumptions. If it is an external SMTP provider, follow that branch; a self-operated MTA needs its own sending IP authorization, DKIM signer and key lifecycle.

Odoo’s DNS documentation limits its published relay records to its own email service. Its outbound guide explains default, external and mixed-server selection. Deployment-specific infrastructure must be identified before an on-premises configuration can be approved.

Use separate acceptance rows for invoices, quotations, chatter notifications and campaigns if they select different servers. An invoice passing DKIM does not prove that Email Marketing uses the same sender.

Map the four identities that Odoo can use

Do not treat Alias Domain as a single switch that makes all addresses identical. Record these separately:

  1. Visible From: The address recipients see. User, template, campaign, Default From Alias and FROM filtering can affect it.
  2. Envelope MAIL FROM / Return-Path: The identity used for SPF and delivery failures. Check the value actually delivered.
  3. Reply-To / catchall or application alias: The route that returns a response to the intended Odoo record or mailbox.
  4. DKIM signing domain and selector: The d= and s= values on the received message.

Odoo’s DNS page associates SPF with the bounce identity and Alias Domain. Its inbound documentation adds a crucial hosting-specific exception: on Odoo Online using the default outgoing server, the Return-Path is forced to bounce@company-name.odoo.com, regardless of the configured bounce alias. Thus From: accounts@example.com can have a healthy SPF pass for an Odoo-owned envelope domain that does not align with example.com. This is why Odoo requires sending-domain DKIM for Online DMARC. Bounce behavior · DKIM requirement

For Odoo.sh, an external service or a customized installation, inspect the real envelope rather than assuming that the Online override applies. A copied Return-Path header in an application template does not prove the SMTP envelope changed.

Company boundaries matter. Odoo supports company-specific alias domains, but the first alias domain can be shared across companies. Capture the company assignments before changing them. Preserve old catchall, bounce and application-alias routing so replies to existing quotations or tickets still arrive. Company alias settings and warnings

Configure the Odoo-relay SPF authorization safely

This section applies to a custom domain using Odoo’s own email servers, not an independent relay.

At the applicable custom-domain owner, inspect the current TXT records. If no SPF policy exists and the Odoo relay is the only authorized sender there, Odoo documents:

v=spf1 include:_spf.odoo.com ~all

If other legitimate senders exist, retain them in the same record. For example, if Google Workspace is also authorized at this exact owner:

Before: v=spf1 include:_spf.google.com ~all
After: v=spf1 include:_spf.google.com include:_spf.odoo.com ~all

These examples do not authorize replacing your complete policy. Preserve the established terminal qualifier and place new mechanisms before all. Any all mechanism makes redirect= ignored, and mechanisms after all cannot be reached. Preserve an intentional redirect-based policy when merging rather than silently disabling its control flow. SPF all and redirect, RFC 7208 §5.1. Do not add a second v=spf1 TXT record. Unrelated TXT verification records can remain. Official Odoo SPF instructions

SPF evaluates the actual MAIL FROM domain, not automatically the From domain; a null reverse path brings the HELO identity into the SPF check. Publishing a custom-domain policy does not change Online’s provider-owned Return-Path. Nor does a parent-domain SPF record automatically cover a child domain. Check every applicable owner and the actual transmitted identity. SPF standard

Count evaluated DNS-causing terms across the complete policy, including nested includes and redirects. SPF permits at most ten such terms during evaluation. Resolve excessive lookup cost, duplicate policies and syntax errors rather than assuming a short TXT string is valid. Do not flatten provider ranges into static IPs without an explicit maintenance process.

Publish the documented Odoo DKIM delegation

For the Odoo relay, the current documentation gives a fixed shared CNAME target, not a unique customer-generated public key:

Type: CNAME
Owner: odoo._domainkey.example.com
Target: odoo._domainkey.odoo.com.

Replace example.com with the intended custom signing domain. The selector is odoo for this documented route. Do not generate a private key locally or place a sample TXT key beside this CNAME. Odoo manages the signing side; your record delegates the public-key lookup. Official DKIM record

For a sender domain erp.example.com, the full owner becomes odoo._domainkey.erp.example.com. In a parent example.com zone, the relative owner is odoo._domainkey.erp; inside a separately delegated erp.example.com zone it is odoo._domainkey. For an apex sender, enter odoo._domainkey in the example.com zone. If _domainkey.erp.example.com itself is delegated, the relative owner inside that authoritative zone is odoo; do not remove its NS delegation or publish a disconnected copy in the parent. Confirm whether your editor expects relative names or a full hostname.

Do not overwrite an existing record at that owner. Resolve a conflicting CNAME, TXT or other record with the DNS administrator. Keep the CNAME DNS-only and unflattened so verification can see the alias. Check both record-level and zone-wide flattening settings if your DNS host offers them; DNS-only status alone does not prove flattening is disabled. On Cloudflare, the record’s Flatten setting and the zone-wide CNAME flattening for all CNAME records setting must both be off for this verification approach. Coordinate any shared zone-setting change with the DNS owner and assess other services before applying it. Cloudflare always flattens apex CNAMEs; same-zone targets may also flatten regardless of the selected settings. If the required literal alias cannot safely remain visible, stop and obtain a supported alternate configuration from Odoo rather than inventing a control or changing nameservers. Cloudflare flattening controls. Preserve legitimate child-zone delegation; publish at its actual authority rather than removing NS records as a shortcut. CNAME verification · Record conflicts

After DNS is prepared, select the intended company in Odoo and set the custom Alias Domain in Settings. Review assignments to other companies and the Default From Alias. The official hosted-relay procedure documents DNS publication and company-domain configuration, not a universal separate DKIM activation switch. Verify a new message afterward; publishing the CNAME alone does not prove the intended application route is using it. Application configuration

Keep replies, bounces and dedicated subdomains working

Odoo offers redirection, incoming mail servers and dedicated-subdomain DNS routing for inbound mail. These are separate operational choices, not substitutes for authenticating outgoing messages. With redirection, preserve the catchall, bounce and every application alias that remains in use. On-premises redirection and DNS routing also require the deployment’s mail-gateway configuration. Inbound methods and prerequisites

The current inbound guide describes CNAME-based routing only for a dedicated subdomain, not the domain apex. This creates an important DNS boundary:

  • If mail.example.com is an ordinary TXT/MX-based mail domain, the SPF TXT owner is mail in the parent zone or @ in a delegated child zone.
  • If mail.example.com is a CNAME to the Odoo database as part of the documented inbound route, do not add a conflicting SPF TXT or MX at that same owner. Follow the selected route’s alias and outbound instructions and inspect the resolved SPF answer.
  • A DKIM child such as odoo._domainkey.mail.example.com is a different owner from mail.example.com. The root CNAME does not replace the necessary DKIM configuration beneath the sending domain.
  • The documented Odoo.sh MX alternative does not inherit SPF from its target. Separate outbound authentication is required.

Register a dedicated subdomain in Odoo Online

Choose an unused subdomain dedicated to mail, such as mail.example.com, and identify the actual database root hostname from your Odoo account. The following is a record pattern, not a literal database target:

Type: CNAME
Owner: mail.example.com
Target: DATABASE.odoo.com.

In the parent example.com zone, the relative owner is mail. Do not place this CNAME at the organizational apex or at the apex of a separately delegated zone where required SOA/NS records already exist. Resolve existing uses of the chosen name before proceeding.

Before publishing either the CNAME route or Odoo.sh MX alternative below, have the routing owner compare and approve the exact dedicated hostname, database destination and applicable MX preference against the inbound-routing plan. A documented or account-issued target is not authorization to redirect replies, bounces or existing mailbox traffic. Stop if the change would affect an unapproved route.

  1. Publish the CNAME with the actual database-root target. If Odoo manages the DNS, the documented route is the database manager’s gear icon beside the database, Domain Names > DNS > Add DNS record. Otherwise use the authoritative DNS host.
  2. In the Online database manager, open the database’s gear menu and Domain Names.
  3. Select Use my own domain, enter the complete mail subdomain, and wait for verification. When it succeeds, select I confirm, it’s done.
  4. Open the database’s Settings and select that full subdomain in Alias Domain for the intended company. Review other company assignments before saving.

The official guide allows anything from minutes to 48 hours for propagation, depending on the provider. Treat that as an allowance, not a guaranteed waiting period or evidence of correctness. Check the exact owner, the database target and whether the DNS editor needs a trailing dot. Correct errors before retrying verification. Online dedicated-subdomain steps

Register a dedicated subdomain in Odoo.sh

Publish the dedicated mail-subdomain CNAME to the actual database root as above. Then open the Odoo.sh project, select the production branch, go to Settings > Custom domains, enter the full subdomain and select Add domain. Finally select it as the company’s Alias Domain in the database Settings. Do not assume that adding a domain to another branch configures production. Odoo.sh dedicated-subdomain steps

For Odoo.sh, the current guide also documents an alternative MX record, rather than a CNAME, at the dedicated subdomain:

Type: MX
Owner: mail.example.com
Priority: 10
Target: DATABASE.odoo.com.

Use only the chosen route, not both CNAME and MX at the same owner. The MX alternative retains the same Odoo.sh registration and Alias Domain steps. Unlike the CNAME route, it does not inherit SPF from its target: configure the subdomain’s own outbound SPF and DKIM, including the odoo._domainkey.mail.example.com CNAME when using the Odoo relay. Keep existing corporate-apex MX records unchanged.

Verify the dedicated-subdomain route before accepting replies

Use these read-only queries with your actual names:

dig @AUTHORITATIVE_NS mail.example.com CNAME +noall +answer
dig +short CNAME mail.example.com
dig @AUTHORITATIVE_NS mail.example.com MX +noall +answer
dig +short TXT mail.example.com
dig +short CNAME odoo._domainkey.mail.example.com

For the CNAME branch, require the full mail.example.com owner to resolve to the exact selected database-root target, then inspect the resolved TXT policy. For the Odoo.sh MX branch, require the exact owner, preference 10 and selected database-root target, plus the separately configured SPF policy at that owner. Run the record-type query relevant to the chosen branch; do not interpret a CNAME-followed answer as proof that an independent MX was published there. For the Odoo relay DKIM child, require the documented odoo._domainkey.odoo.com target and a resolvable public key.

Confirm the domain is accepted in the correct Online database or Odoo.sh production project, the company uses the intended Alias Domain, and a controlled reply reaches the intended chatter. Registration success and DNS answers still do not prove outgoing DKIM or DMARC; perform the delivered-message checks below. Do not switch an existing mail domain casually: preserve prior MX, aliases and routing, and coordinate migration with the mail owner.

Configure external SMTP and on-premises mail at the real sender

For an external outgoing server, first verify the domain at that provider. Obtain its current public DKIM selectors/values, supported envelope-domain configuration and activation instructions. The fixed Odoo CNAME does not make the external provider sign mail. Your own external server must use a domain you control; Odoo does not permit customers to alter its managed subdomain DNS. External-server requirements

In Odoo 19:

  1. Open Settings, enable Use Custom Email Servers in the Emails section and save.
  2. Open Outgoing Email Servers, choose New, and enter the actual provider’s supported connection settings.
  3. Configure FROM Filtering to match an address or domain that the provider permits. Do not broaden sender permissions simply to suppress an error.
  4. Run Test Connection, then exercise the real workflow. Odoo explicitly warns that a connection test can succeed while provider restrictions still prevent sending.

Online and Odoo.sh block outbound port 25. Use a port and encryption mode supported by the chosen service; the fact that a port accepts a connection does not establish TLS or sender authorization. Keep passwords, OAuth secrets and private keys out of the DNS worksheet. Connection and port guidance

For on-premises mail, the infrastructure owner must establish whether Odoo submits to an external relay or a locally operated MTA. For the latter, authorize the actual outbound IPs at the real envelope domain, configure a DKIM signer with its own generated key and selector, publish only the public key, and arrange rotation and receiver testing. The exact software commands depend on that deployment; do not substitute Odoo Online’s shared records. Preserve the on-premises inbound gateway and reply handling while changing the outgoing route.

If your actual provider is Google Workspace or Microsoft 365, use its authentication instructions alongside Odoo’s corresponding connection documentation. Submission permissions, mailbox limits and domain authentication remain separate checks. For interpreting a signature independently of alignment, see raw DKIM results versus aligned DKIM policy results.

Check FROM filtering and transaction-versus-campaign selection

Odoo searches for a server whose FROM filter matches the outgoing address or domain. Fallback selection can replace the sender with a notification address. Priority determines selection order, with lower numbers preferred; the dedicated server chosen in Email Marketing can handle mass mail separately. Selection logic

When using different servers, record each server’s filter, priority, authorized domains and purpose. In Email Marketing > Configuration > Settings, review the Dedicated Server selection. Do not infer campaign authentication from an invoice test, even when both messages display the same From domain.

For mixed Odoo/default and external routes, verify the domain filters deliberately. A fallback to notifications@DATABASE.odoo.com can pass authentication while failing the business requirement to display your brand. That is a routing/identity issue, not proof that the brand’s DNS is correct.

Preserve DMARC and plan reporting

DMARC needs at least one passing SPF or DKIM identity aligned with the visible From domain. Relaxed alignment uses the same organizational domain; strict adkim=s or aspf=s requires an exact domain match for that mechanism. A reply address and a provider-only signature do not establish alignment. DMARC specification

For accounts@example.com, inspect _dmarc.example.com. For accounts@erp.example.com, inspect _dmarc.erp.example.com and any applicable inherited policy. Its relative DNS owner is _dmarc.erp in the parent zone or _dmarc in a delegated erp.example.com zone.

Retain existing enforcement, subdomain policy, alignment modes and reporting destinations. Only if there is no effective existing or inherited policy and the domain owner explicitly approves the monitoring plan might a starting TXT value be published at the applicable owner above. For root From domain example.com, full owner _dmarc.example.com is relative _dmarc inside the example.com zone:

v=DMARC1; p=none; rua=mailto:dmarc-reports@example.com

Use an approved, monitored address rather than the literal example. Obtain the domain owner’s approval of the aggregate-report recipient and shared data separately from protocol authorization. When the destination is in a different Organizational Domain from the policy domain, the report-generating receiver must check destination-side DNS authorization before sending reports. Destinations within the same Organizational Domain are the exception. An rua address alone does not supply authorization, and a last-two-label guess is not an Organizational Domain determination. External report authorization, RFC 9990 §4. Review reports across all companies and senders; missing reports do not prove the absence of failures. DMARC aggregate reporting

Do not lower a working reject policy to make an Odoo error disappear. RFC 9989 requires valid DKIM rather than SPF-only reliance for domains publishing p=reject. For Odoo Online’s custom From on the default relay, the hosting-specific Return-Path behavior makes branded DKIM especially important.

Validate public DNS and a real Odoo workflow

Replace these illustrative names with the approved domain and observed identities. These commands are read-only patterns, not checks performed for a customer:

dig +short NS example.com
dig @AUTHORITATIVE_NS ACTUAL_SPF_OWNER TXT +noall +answer
dig +short TXT OBSERVED_MAIL_FROM_DOMAIN
dig +short CNAME odoo._domainkey.example.com
dig +short TXT odoo._domainkey.odoo.com
dig +short TXT _dmarc.example.com

A long public-key TXT answer may contain multiple component strings within one logical record. Concatenate them without inserted spaces, not as separate key records. DKIM TXT syntax.

For an external service, substitute its actual selector and signing domain and query every issued record at its required type. For a delegated zone use that zone’s authority. For CNAME-based inbound routing, inspect the alias and resolved TXT chain without creating an owner conflict. Compare authoritative and recursive responses; investigate missing keys, wrong targets, doubled suffixes and stale caches before proceeding.

Have an authorized operator send a harmless quotation, invoice preview or other approved message to a controlled external mailbox through the actual workflow. Avoid billing, posting an accounting entry or exposing customer data just to generate a sample. Test campaigns separately when their transport differs, and reply to a sample to confirm it returns to the right chatter or mailbox.

Use the receiver’s trusted Authentication-Results. Establish the receiving system’s processing boundary from its documentation or administrator-confirmed path, including whether externally supplied result fields are stripped or isolated/distinguished. Ignore those untrusted fields: authserv-id and header position alone are forgeable and do not prove origin. If that handling cannot be established, use receiver-controlled logs or traces and obtain receiver-administrator confirmation before accepting the result. Record From, smtp.mailfrom, Return-Path, every DKIM d= and s=, results, message identifier and UTC time. Trusted authentication results

The acceptance criteria are:

  1. The correct company and workflow use the intended branded From, without an unintended fallback identity.
  2. The intended branded DKIM signature passes and aligns under the effective adkim mode. DNS publication, connection success or SPF-only DMARC pass does not complete DKIM setup.
  3. SPF is checked at the observed envelope domain. Online’s documented provider-domain SPF pass without custom-domain alignment is recorded as such, not mislabeled as an SPF failure.
  4. Actual SPF fail, softfail, none, permerror or temperror is investigated even if DKIM makes DMARC pass. Resolve authorization, duplicate-policy, lookup-limit or DNS-availability faults. Separate direct-delivery evidence from forwarding effects.
  5. DMARC passes for the intended From domain, replies reach the correct destination, and bounce handling remains available.

For illustration only: an invoice from accounts@example.com with dkim=pass for d=example.com can pass DMARC while SPF passes for an unrelated Odoo envelope domain. By contrast, a passing intended Odoo signature d=erp.example.com for visible From accounts@example.com aligns under relaxed adkim=r when both share an Organizational Domain, but not under strict adkim=s; passing d=example.com aligns in both modes. A campaign signed only by an unrelated external provider does not inherit that invoice’s alignment. DKIM alignment, RFC 9989 §4.4.

Troubleshoot Odoo-specific failures

Changing Alias Domain did not align SPF: Check hosting and transport. Online’s default-server Return-Path override is documented. Verify branded DKIM instead of repeatedly editing an unused root SPF policy.

The From address became notifications: Inspect FROM filtering, default From settings and the selected server. An authenticated fallback identity can still be the wrong sender for the workflow.

Invoices pass but campaigns fail: Compare the dedicated marketing server with the transactional server. Activate the actual campaign provider’s branded signing and retest a campaign sample.

DKIM CNAME resolves but no branded signature appears: Confirm the company’s alias domain, intended From and actual outgoing route. A custom SMTP server needs its own signing setup. Check a fresh message, not one sent before configuration.

Replies disappeared after the change: Restore missing aliases or approved redirections. Previously sent messages still contain their old reply addresses. Do not alter MX records or remove the previous catchall to solve an unrelated authentication error.

SPF PermError or TempError: Permanent errors need syntax, duplicate-record or lookup-limit repair at the evaluated owner. Temporary errors need DNS resolution investigation and retesting. A DKIM pass does not excuse an unresolved direct-route SPF defect.

The SMTP connection test succeeds but messages fail: Review sender permission, relay restrictions and the actual rejection text. A transport connection is not recipient acceptance.

Keep a rollback record for each company and route. Restore only the changed settings or DNS records if needed, preserve queued-message key dependencies, and retest replies as well as outgoing mail after recovery.

[ FAQs ]

Frequently asked questions

Does Odoo Online support aligned SPF through Alias Domain alone?

Do not assume it does. The current inbound documentation says the default outgoing server forces the Return-Path to the database’s Odoo domain. Verify the observed identity and configure passing, aligned custom-domain DKIM.

Do I need DNS changes for the default Odoo subdomain?

Odoo documents its unmodified Online/Odoo.sh default subdomain as preconfigured. You cannot edit that provider-owned zone as if it were your custom domain. Modified settings and external routes need separate checks.

Can I add an SPF TXT beside my inbound-routing CNAME?

No. A CNAME cannot coexist with unrelated records at the same owner. Follow the selected dedicated-subdomain route and validate the resolved policy. Do not confuse its root owner with the separate DKIM child owner.

Does this setup apply unchanged to on-premises Odoo?

No. Identify the local MTA or external relay. That sender controls IP authorization, DKIM keys, permitted identities and activation; the hosted Odoo record recipe is not a universal on-premises configuration.

Does successful Test Connection prove DMARC passes?

No. It checks connectivity. You still need a real workflow message with the intended branded DKIM pass and alignment, an understood SPF result and receiver-side DMARC pass.

[ Sources ]

Sources

  1. Odoo DNS setup
  2. Online Return-Path exception
  3. outbound guide
  4. Odoo 20.0 DNS reference

Enterprise provenance

Why top financial institutions and governments retired their email security dashboards.

Traditional email authentication platforms sell you a dashboard and ask your engineers to do the labour. In high-stakes environments, manual oversight means delayed enforcement, configuration drift and unmonitored shadow domains.

EmailAuth is the agentic email provenance platform. Our agents enforce p=reject, keep third-party senders aligned and move your domains to full RFC 9989 compliance, the new DMARC standard, with human-in-the-loop auditability.

Governments Large enterprises Tier-1 financial institutions

SaaS · Dedicated tenancy · Air-gapped on-prem · BYOK encryption

Knowledge Base