Skip to main content
Email DeliverabilityMay 7, 202614 min read

Why Your Odoo Emails End Up in Spam (and How to Fix It in 2026)

If your Odoo emails are going to spam, you are not alone. Most Odoo deployments ship with bad email defaults, and the tutorials online stop at "configure SMTP" without telling you the rest. Here is the actual checklist that fixes it. Most of it takes less than 30 minutes.

Why this happens (the short version)

Odoo can send email perfectly. The product itself is not the problem. The problem is that email deliverability is an infrastructure concern, and Odoo hands you a blank SMTP form expecting you to know what to do. Most teams plug in a Gmail account or a self-hosted Postfix server and call it done. Then half the invoices land in spam and customers start asking why they never got the bill.

Once you strip away the noise, there are exactly three reasons your Odoo emails go to spam:

  1. Sender authentication is broken. SPF, DKIM, or DMARC is missing or misconfigured.
  2. Content triggers spam filters. Spammy words, bad link ratios, all-caps subject lines.
  3. HTML is malformed. Broken inline CSS, base64 images, missing alt text, broken image references.

All three are fixable. None of them require deep email expertise. The next sections walk through each one with copy-pasteable DNS records and the exact tools to verify your work.

Step 1: Fix SPF (15 minutes)

SPF stands for Sender Policy Framework. In plain English, it is a TXT record on your domain that says "these IP addresses are allowed to send email as me." When a receiving server sees an email claiming to be from you, it pulls your SPF record and checks if the sending IP is on the list. If not, it gets suspicious.

To check what you have right now, run this from any terminal:

dig +short txt yourdomain.com | grep spf1

If it returns nothing, you have no SPF record and you need to add one. If it returns multiple records starting with v=spf1, you have a different problem (more on that below).

The Odoo trap

Most Odoo deployments use an external email service like Mailgun, SendGrid, Amazon SES, or Postmark. Each of those services has its own SPF record you need to include. If you skip this, every email Odoo sends will fail SPF.

Here is what an SPF record looks like for a typical Odoo setup using Mailgun for transactional and Google Workspace for human email:

v=spf1 include:mailgun.org include:_spf.google.com ~all

Add this as a TXT record on the root of your domain (host = @ or your bare domain depending on your DNS provider). The ~all at the end means "soft fail anything not on this list" which is the standard recommendation.

Common mistakes

  • Multiple SPF records. RFC 7208 allows exactly one. If you have two, both fail. Merge them into a single record with multiple includes.
  • Forgetting the include for your provider. Mailgun is include:mailgun.org, SES is include:amazonses.com, SendGrid is include:sendgrid.net. Check your provider's docs.
  • Using -all without testing first. A hard fail blocks legitimate mail you forgot to include. Stick with ~all until you have monitored DMARC reports for a month.
  • Hitting the 10 DNS lookup limit. SPF allows a maximum of 10 nested DNS lookups. Big chains of include statements can blow past this and fail silently.

Once added, verify with mxtoolbox.com/spf.aspx. Plug in your domain. You want a green checkmark and a record that lists every service that sends as you.

Step 2: Fix DKIM (20 minutes)

DKIM stands for DomainKeys Identified Mail. While SPF says "these servers can send," DKIM says "this specific email was signed by my private key, so it is genuinely from me and has not been modified in transit." The receiving server fetches your public key from DNS, verifies the signature on the email headers, and gives you a deliverability boost when it passes.

How to set it up

You do not generate DKIM keys yourself. Your email provider does, and they hand you the public key as a TXT record to drop into DNS:

  1. Log into your email provider (Mailgun, SES, SendGrid, Postmark, etc.).
  2. Find the section labeled DKIM, Domain Authentication, or Sending Domains.
  3. Add your domain. The provider generates a key pair and shows you a public key plus a hostname.
  4. Copy the hostname (something like k1._domainkey.yourdomain.com) and the value.
  5. Create a TXT record at that hostname in your DNS provider with the value as-is.

The actual record value looks like this (truncated for readability):

k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQ
DkIM7nhpKf2VW7bO9P3eCOaQpLyG8cv2sX5jVfHwK2zE...

After adding the record, go back to your provider and click "Verify" or "Authenticate." They run a DNS lookup against the hostname and confirm the public key matches their stored private key. Until you do this verification step, DKIM will not actually sign anything.

Common mistakes

  • Forgetting to enable DKIM signing in the provider. Some providers require you to flip a switch after the DNS verification. SES and SendGrid both have this gotcha.
  • Copy-paste errors. The public key is long. Some DNS providers wrap it onto multiple lines and break the value. Use your DNS provider's "raw" or "import" mode if available.
  • Using the wrong selector. Each provider uses a different selector (k1, s1, mailo, default). Use exactly what they tell you. The selector is the bit before ._domainkey.
  • Quoting issues. If your DNS provider auto-quotes TXT values, paste without the surrounding quotes. If it does not auto-quote, wrap the value in double quotes.

Verify with dkimcore.org or send a test email to mail-tester.com. Both tools will show whether DKIM is signing and validating end-to-end.

Step 3: Fix DMARC (15 minutes)

DMARC ties SPF and DKIM together and tells the receiver what to do when one of them fails. Without DMARC, a receiving server has to guess. With DMARC, you give an explicit policy: do nothing, send to spam, or reject outright.

Since 2024, Gmail and Yahoo have required DMARC for any sender pushing more than 5,000 emails per day. As of 2026, it is effectively required for everyone. Skip it and you will see deliverability drop on Gmail, Yahoo, and most major B2B mailbox providers.

The right way to roll out DMARC

Do not jump straight to p=reject. You will block legitimate mail you forgot about (a CRM that sends from your domain, an old marketing tool, a forgotten cron job). Roll out in three phases:

# Week 1: monitor only, do not block anything
_dmarc TXT "v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com"

# Week 4: send failing mail to spam
_dmarc TXT "v=DMARC1; p=quarantine; rua=mailto:dmarc@yourdomain.com"

# Month 2: reject failing mail outright
_dmarc TXT "v=DMARC1; p=reject; rua=mailto:dmarc@yourdomain.com"

Add the TXT record at the hostname _dmarc.yourdomain.com. The rua tag is the email address that receives daily aggregate reports from every receiving mail server.

Reading DMARC reports

Reports arrive as zip files containing XML. They are not human-readable. Use a free service like Postmark's DMARC Digests or DMARC Report to parse them and see which servers are sending as your domain, which are passing SPF and DKIM, and which are failing. Spend a week in monitor mode reviewing reports before escalating to quarantine.

Once a full week of reports shows 100% pass rates from your legitimate senders (Odoo, Google Workspace, your CRM), bump the policy to quarantine. Wait another month, confirm no legitimate mail is being quarantined, then push to reject. This is the slow, safe path that does not blow up your invoices.

Step 4: Audit your email content

Authentication gets your email past the front door. Content decides whether it lands in the inbox or in spam. The standard tool here is SpamAssassin, which assigns each email a score from 0 to 10. Anything above 5 is treated as spam by most receivers.

Common Odoo template issues

  • Excessive caps in subject lines. "INVOICE READY FOR PAYMENT" reads as spam. Use sentence case.
  • Too many links relative to content. An email with three sentences and seven links scores poorly.
  • Spam trigger words. FREE, GUARANTEED, ACT NOW, LIMITED TIME, CLICK HERE. SpamAssassin has a long list of these baked in.
  • Missing alt text on images. Every image tag needs an alt attribute. Empty alt="" is fine for decorative images, but missing entirely is a flag.
  • All-image emails. Spammers used to send mostly-image emails to evade text scanners. Modern filters know this and penalize emails without enough plain text.
  • Missing plain text alternative. Every HTML email should have a plain text version. Most email libraries handle this automatically. Make sure yours does.
  • Unsubscribe link missing. For marketing email this is a hard requirement. For transactional email it is optional but does not hurt.

How to test

Send a test email to mail-tester.com. It gives you a SpamAssassin score plus a breakdown of which rules triggered. Aim for 9/10 or better. If you score lower, the report tells you exactly which rules to fix.

The catch with mail-tester is that you have to run it manually for each template. Mailtest does this automatically for every email Odoo sends, so you catch regressions when a developer ships a new template that scores badly.

Step 5: Fix HTML quality

Odoo's default email templates are reasonable. Custom modules and inherited templates often break things. The following issues silently kill deliverability and rendering:

  • Inline CSS using vendor-prefixed properties. Outlook strips -webkit-*, -moz-*, and most modern CSS. If your template relies on flexbox or grid, it will look broken in 30% of inboxes. Use tables for layout. Yes, like 2005.
  • Base64-encoded images. Embedding a 200KB image as base64 inflates email size by ~30%. Some filters drop emails over 100KB. Always link to hosted images instead.
  • Broken image references. Relative URLs like /web/image/123 work inside Odoo but are nonsense in an email client. Use absolute URLs with full domain.
  • Missing meta charset. Without <meta charset="utf-8">, non-ASCII characters render as garbage in some clients.
  • Tables nested 5+ levels deep. Legacy email rendering chokes. Keep nesting under 4 levels if you can.
  • Inline width without max-width. Mobile clients get sad when the table is hardcoded to 800px. Add max-width: 100% on the outer table.

Run your templates through Putsmail or premailer. Both lint your HTML and flag the issues above.

Step 6: Test before you send

Here is the workflow that kills more deliverability than anything else:

  1. Developer builds a custom email template.
  2. Tests by emailing themselves once. Looks fine.
  3. Ships to production.
  4. Customer asks two weeks later why they never got the invoice.
  5. Now you are debugging deliverability after the fact, with no logs and no reproduction.

The fix is to capture every email Odoo sends in a test inbox first. Score it. Render it across clients. Confirm authentication passes. Then enable real sending. This is exactly what Mailtest does on OEC.sh.

How Mailtest works

Mailtest runs as a dedicated SMTP capture container alongside your Odoo deployment. Every email Odoo sends gets intercepted and scored across three tiers:

  • Tier 1: SPF, DKIM, DMARC authentication checks against your real DNS.
  • Tier 2: SpamAssassin content scoring with a full ruleset.
  • Tier 3: HTML quality (broken images, inline styles, base64 inflation, missing alt text).

Per-organization rotation keeps your test traffic separate from production. Agency plans get a fleet dashboard that shows scores across every client deployment in one place.

See how Mailtest works →

Common Odoo-specific gotchas

Even with SPF, DKIM, DMARC, and clean HTML, Odoo has a few quirks that bite teams in production.

Mass mailing kills transactional

Do not use the same SMTP credentials for transactional email (invoices, password resets, order confirmations) and marketing email (campaigns, newsletters). When a marketing burst hits the provider rate limit, your transactional mail queues up behind it and customers stop getting password resets. Use a separate domain or subdomain for marketing (mail.yourdomain.com) with its own provider account.

Bounce handling needs a separate return path

Odoo's bounce processing reads from a mailbox to know which addresses are dead. The return path (envelope sender) on outgoing mail must be different from the From address, and it must point at a mailbox Odoo can read. If you skip this, Odoo never learns which addresses are bouncing and your sender reputation slowly tanks as you keep retrying dead addresses.

Database name in the subject

Odoo's default email subjects sometimes include the database name in brackets, like [yourdb-prod] Invoice INV/2026/00001. This looks like spam to filters and confuses customers. Strip it in your mail.thread settings or override the default subject template.

From name vs From email mismatch

Setting a display name like "Yourdomain Billing" with an actual email address that does not match your SPF-authorized domain causes alignment failures in DMARC. The visible From and the envelope From must both align with your authenticated domain. If you want to send as billing@yourdomain.com, the SMTP envelope sender must also be on yourdomain.com.

Wrong port, wrong protocol

Use port 587 with STARTTLS for submission, not port 25. Port 25 is for server-to-server transfer and is blocked by most cloud providers (DigitalOcean, AWS, GCP) by default. If your Odoo logs show connection timeouts to your SMTP host, this is almost always why.

The 30-minute total fix

If you got nothing else from this post, here is the checklist. Do these in order and you will be in the inbox within an hour:

  • [ ]SPF record set with an include for every service that sends as you
  • [ ]DKIM enabled in your provider, public key TXT record live in DNS, verification clicked
  • [ ]DMARC in monitor mode (p=none) with a working aggregate report email
  • [ ]Email templates audited for spam triggers and HTML issues
  • [ ]Mailtest enabled to score every email going forward
  • [ ]Bounce processing configured with a separate return path
  • [ ]Mass mailing on a separate subdomain or provider account

After a month of clean DMARC reports, escalate the policy to quarantine. After two months total, push to reject. By then your domain reputation will be solid and you will see a noticeable jump in deliverability across Gmail, Outlook, and Yahoo.

TL;DR

Odoo emails go to spam because of bad authentication, bad content, or bad HTML. Fix SPF, DKIM, and DMARC. Audit your templates with mail-tester or Mailtest. Test before you send, not after. Mailtest captures every email Odoo sends and scores all three tiers automatically, so you catch problems before customers do.

Frequently Asked Questions

Why are my Odoo emails going to spam in 2026?

Three reasons cover almost every case. First, sender authentication is broken: SPF, DKIM, or DMARC is missing or misconfigured. Second, content triggers spam filters: spammy words, bad link ratios, all-caps subject lines. Third, the HTML is malformed: broken inline CSS, base64 images, missing alt text. Fix all three and you land in the inbox.

Do I need DMARC for Odoo emails?

Yes. Since 2024, Gmail and Yahoo require DMARC for any sender pushing more than 5,000 emails per day, and they reward DMARC-authenticated mail with better inbox placement for everyone else. Start with p=none in monitoring mode, then escalate to p=quarantine and p=reject once you have a clean DMARC report.

What's the difference between SPF and DKIM?

SPF tells receiving servers which IP addresses are allowed to send email for your domain. DKIM adds a cryptographic signature to each email so the receiver can verify it has not been tampered with and was sent by an authorized server. You need both, plus DMARC to tie them together.

Can Mailtest fix my email deliverability?

Mailtest captures every email Odoo sends and scores it across SPF, DKIM, DMARC, SpamAssassin content scoring, and HTML quality. It tells you exactly what is wrong before customers see anything. Fixing the underlying DNS records and templates is still your job, but Mailtest removes the guesswork.

How do I test Odoo email before customers see it?

Don't deploy to production and then ask the customer if they got the invoice. Capture every outgoing email in a test inbox first, score it for authentication and content, fix any issues, then enable real sending. Mailtest does this automatically for OEC.sh deployments. For one-off tests, mail-tester.com works manually.

Stop Guessing Whether Your Emails Land

Mailtest captures every Odoo email, scores authentication, content, and HTML, and tells you what to fix before customers notice. Free tier includes Mailtest on one project.