This article is currently available in English only. Translation coming soon.
You send an email from Odoo. The UI shows success. The recipient never gets it. You check the server log — nothing. You check mail.mail — state='sent' and yet the bounce report shows nothing. You check the recipient's spam folder — empty. The email is genuinely lost between Odoo and the recipient with no signal anywhere. This is the most frustrating Odoo email bug and applies to 17.0/18.0/19.0.
Quick Fix
Enable detailed mail logging in odoo.conf:
[options]
log_handler = :INFO,odoo.addons.mail:DEBUG,odoo.addons.base.models.ir_mail_server:DEBUG
log_level = info
Restart Odoo. Re-send a test email. The log now shows the full SMTP conversation — including the response code and any "accepted but quarantined" notice from the server.
Why This Happens
"No error" can mean several different states:
- Odoo successfully handed the email to the SMTP server. The server accepted with a 250 response. The email is then rejected silently downstream — recipient's inbox provider quarantined for spam, sender domain not authenticated (SPF/DKIM/DMARC failures), or recipient is a known abuser.
- The SMTP server logged a soft error that Odoo translated as success. Some custom mail flows return 250 even on quarantine. Odoo treats 250 as success unconditionally.
- The recipient is on a deny list maintained by the SMTP provider. The provider accepts the email but never delivers it.
- DNS/MX issues. The recipient domain's MX record is misconfigured; the SMTP provider tries, fails, gives up silently. Odoo only sees the initial accept.
- Transactional log loss. The Odoo log was rotated and the relevant entry is in an archived file. Or
log_handleris filtering at WARNING or above.
Step-by-Step Diagnosis
1. Check log level.
grep "log_handler\|log_level" /etc/odoo/odoo.conf
If level is warn or error, INFO-level send confirmations never log. Bump to info and reproduce.
2. Check mail.mail state.
SELECT id, subject, state, message_id, failure_type, failure_reason
FROM mail_mail
WHERE email_to LIKE '%@example.com'
ORDER BY id DESC LIMIT 5;
state=sent + empty failure_reason = Odoo handed the mail off. Problem is downstream.
3. Check the SMTP server's logs. Critical step. Most "no error in Odoo log" bugs have full detail in the SMTP provider's log:
# For Postfix
tail -f /var/log/mail.log
# For SES
aws ses send-statistics --region us-east-1
# or check SES Console → Reputation Dashboard
# For Gmail OAuth2
# Check Google Workspace admin console → Email Log Search
4. Check authentication records. SPF, DKIM, DMARC misalignment causes silent quarantine:
dig TXT yourdomain.com # SPF
dig TXT default._domainkey.yourdomain.com # DKIM
dig TXT _dmarc.yourdomain.com # DMARC
A failing DMARC policy of p=reject results in silent drop at the recipient.
5. Test with a third-party deliverability tool. mail-tester.com or Glock Apps. Send to their address from your Odoo, see exactly which checks pass/fail. Surfaces issues no log will tell you.
Permanent Fix
For SPF/DKIM/DMARC issues, fix DNS:
# SPF — list every IP/domain authorized to send as you
yourdomain.com. TXT "v=spf1 include:_spf.google.com include:amazonses.com -all"
# DKIM — generated by your SMTP provider, just add the CNAME or TXT record
default._domainkey.yourdomain.com. CNAME default.dkim.yourdomain.com.
# DMARC — start with monitor mode, tighten after 14 days of clean reports
_dmarc.yourdomain.com. TXT "v=DMARC1; p=none; rua=mailto:[email protected]"
After DNS propagates (4 to 24 hours), test deliverability again.
For provider-side filtering, check provider rep:
- AWS SES: console shows bounce/complaint rates. Above 5% bounces or 0.1% complaints = throttled.
- Gmail OAuth2: Google Postmaster Tools shows your sending domain's reputation.
- SendGrid/Mailgun: per-message event log shows accepted/delivered/bounced/spam.
If reputation is bad, fix the source (validate email lists, suppress hard bounces, follow industry sending standards).
For Odoo's silent-success on soft failures, log every send unconditionally:
class IrMailServer(models.Model):
_inherit = 'ir.mail_server'
def send_email(self, message, **kwargs):
result = super().send_email(message, **kwargs)
_logger.info(
"MAIL SENT: from=%s to=%s subject=%s mid=%s",
message['From'],
message['To'],
message['Subject'],
result,
)
return result
This makes every send visible in the log regardless of state. Pair with log shipping to your monitoring stack.
For DNS resolution failures, ensure the Odoo server uses a reliable resolver:
# /etc/resolv.conf
nameserver 1.1.1.1
nameserver 8.8.8.8
A flaky internal DNS resolver causes intermittent SMTP failures that look like "lost emails".
For high-value emails (password resets, order confirmations), add explicit verification:
def send_password_reset(self, partner):
mail = self.env['mail.mail'].create({
'subject': 'Reset your password',
'email_to': partner.email,
'body_html': '...',
})
mail.send(raise_exception=True) # surface SMTP errors immediately
if mail.state != 'sent':
raise UserError(_("Password reset email could not be sent: %s") % mail.failure_reason)
raise_exception=True makes Odoo bubble up SMTP errors to the user instead of swallowing them.
How to Prevent It
- DKIM and SPF on every sending domain. Mandatory for any production sending. Without these, deliverability is a coin flip.
- Log every send. A custom override (above) ensures every send is logged regardless of provider behaviour. Cheap and dispositive.
- Subscribe to provider bounce notifications. SES, SendGrid, etc., can webhook your Odoo on every bounce. Adds visibility.
- Run a regular deliverability test. Schedule a weekly send to a mail-tester address; alert on score below threshold. Catches DNS/auth regressions.
- Hard-fail on critical emails. Use
raise_exception=Truefor password resets, billing notifications, and any email a user expects within seconds. - Don't reuse SMTP credentials across staging and production. Bounces from staging affect production reputation. Use separate sending domains or sub-domains.
Related Errors
- Mail stuck in outgoing queue — adjacent send-failure bug.
- Mail aliases not receiving — inverse on the inbound side.
- Mass mailing batch timeout — sibling bulk-send issue.
- Report translations missing — adjacent customer-comms bug.
Frequently Asked Questions
Why does Odoo show "sent" when the email was not delivered?
"Sent" in Odoo means "the SMTP server accepted my SUBMISSION". It does not mean delivered. Final delivery happens hours later via MX hops, recipient filtering, etc. To track final delivery, integrate webhooks from your SMTP provider that update mail.mail.state after the recipient's server confirms.
Can I see exactly which IP Odoo used for SMTP?
Yes, in the detailed log (with :DEBUG log handler enabled). Look for the Connection: line — it shows the local-IP→remote-IP pairing. Useful when SES/SendGrid quarantine specific IPs.
Why do my emails go to spam for some recipients but not others?
Per-recipient reputation. Microsoft (Outlook, Hotmail) is famously aggressive about reputation scoring. Sending volume changes, content changes, and DKIM gaps all affect score. The fix is a long game: warm up the sending domain slowly, fix authentication, monitor postmaster tools per provider.
My password reset emails fail silently sometimes. What's the durable fix?
Three layers: (1) raise_exception=True so the user sees a real error rather than nothing, (2) a fallback retry queue that picks up mails that failed in attempt 1, (3) provider webhook integration so you know within minutes if a critical email did not deliver. ECOSIRE's Odoo support and maintenance team builds this stack for every customer.
Need help with a tricky Odoo error? ECOSIRE's Odoo experts have shipped 215+ modules — get expert help.
تحریر
ECOSIRE TeamTechnical Writing
The ECOSIRE technical writing team covers Odoo ERP, Shopify eCommerce, AI agents, Power BI analytics, GoHighLevel automation, and enterprise software best practices. Our guides help businesses make informed technology decisions.
ECOSIRE
Odoo ERP کے ساتھ اپنے کاروبار کو تبدیل کریں
آپ کے کاموں کو ہموار کرنے کے لیے ماہر Odoo کا نفاذ، حسب ضرورت، اور معاونت۔
متعلقہ مضامین
How to Add a Custom Button to an Odoo Form View (2026)
Add custom action buttons to Odoo 19 form views: Python action method, view inheritance, conditional visibility, confirmation dialogs. Production-tested.
How to Add a Custom Field in Odoo Without Studio (2026)
Add custom fields via custom module in Odoo 19: model inheritance, view extension, computed fields, store/non-store decisions. Code-first, version-controlled.
How to Add a Custom Report in Odoo Using External Layout
Build a branded PDF report in Odoo 19 using web.external_layout: QWeb template, paperformat, action binding. With print logo + footer overrides.