TL;DR
Unosend is a good email service, but its SMTP relay has authentication issues — at least with some setups. The HTTP API works fine. I built an Odoo module that intercepts outgoing email and sends it through the Unosend API instead. The code is public.
The problem
I was setting up Odoo for an organization that uses Unosend as their email provider. Unosend has a generous free tier (5000 emails/month), verified domain, DKIM, SPF — the whole stack. The REST API works fine.
Then I configured SMTP in Odoo and saw this in the logs:
WARNING: No mail server matches the from_filter
WARNING: Ocurrió un error al enviar el correo electrónico
I tested the SMTP credentials directly:
import smtplib
server = smtplib.SMTP('smtp.unosend.co', 587)
server.starttls()
server.login('unosend', 'un_XXXX...') # 535 Authentication Failed
Authentication Failed. Every time. I generated multiple API keys, including a fresh one just for SMTP. Same result.
Unosend's docs say the SMTP password is your API key. But Unosend's SMTP backend runs on Zoho (mx.zohomail.com), and Zoho keeps rejecting the auth. Probably a bug on their end, or some config mismatch. Either way, the HTTP API (POST /api/v1/emails) works every time.
The fix: intercept email sending in Odoo
Odoo sends email through the ir.mail_server model — specifically the send_email() method. It takes an email.message.Message object (RFC 2822) already built and routes it through SMTP.
The natural solution: inherit ir.mail_server and override send_email() to send through the Unosend API instead.
The flow looks like this:
[mail module] → ir_mail_server.send_email()
│
├── Unosend enabled? → parse message → POST /api/v1/emails
│ │
│ ├── Success → return Message-ID
│ └── Failure → log + SMTP fallback
│
└── No → original SMTP
How the module works
- Config: Adds fields in Settings → Email (API key, default FROM, etc.)
- Interception: Every time Odoo tries to send an email, the module checks: "is there an Unosend API key?"
- Parsing: Takes the RFC 2822 message, extracts FROM, TO, CC, Subject, HTML/plain text
- Sending: POSTs to
https://www.unosend.co/api/v1/emailswith the API key - Fallback: If the API call fails, retry via SMTP (optional, configurable)
The module doesn't replace the existing SMTP server — it complements it. The SMTP server still defines the from_filter and acts as a backup.
Why override ir_mail_server.send_email() and not mail.mail._send()
mail.mail._send() iterates over emails in batches, manages states (outgoing → exception → sent), and calls ir_mail_server.send_email() for each one. Overriding _send() is riskier because there's a lot of state and notification logic around it. Better to intercept at the point just before the SMTP connection opens.
Why share this
This isn't a Unosend-only problem. Plenty of email providers have modern HTTP APIs but flaky SMTP configs. SendGrid, Mailgun, Postmark, Resend — they all offer REST and SMTP, but SMTP doesn't always work in every environment (corporate firewalls, proxies, containers with port restrictions).
The module is designed to be generic. Change the base URL and the payload format, and it works with any email API.
Where to find it
The code is on GitLab:
GitLab: gitlab.com/zczoft-odoo/unosend-mail
Structure:
unosend_mail/
├── __init__.py
├── __manifest__.py
├── models/
│ ├── ir_mail_server.py # Core: send_email override
│ └── res_config_settings.py # Config fields
├── views/
│ └── res_config_settings_views.xml
└── SPECIFICATION.md
Requires Odoo 18+ and the mail module. Contributions welcome.
What's next
- Support attachments (currently skipped)
- Track opens/clicks from Unosend in Odoo
- Make it compatible with Odoo 16+
- Add automated tests
Lessons learned
- Don't assume SMTP works just because the API works. Zoho (Unosend's backend) has its own auth rules.
- Override at the right point.
ir_mail_server.send_email()is the sweet spot — high enough to avoid state logic, low enough to catch all outgoing traffic. - Always leave a fallback. APIs can fail (rate limits, maintenance, version changes). The SMTP that "doesn't work" can save the day.
- Provider docs don't always match reality. Unosend documents SMTP with API key as password, but in practice it doesn't work. Always test.
Had a similar issue with Unosend or another provider? Built an Odoo module for HTTP API email delivery? Leave a comment or contribute to the repo.