Two small, dependency-free modules that keep Odoo Email Marketing from burning your sender reputation. Both are production-proven and fully tested.
| Module | What it does |
|---|---|
mass_mailing_throttle |
Global send-rate caps (per rolling hour + per rolling minute) for mass mailings. Configurable in Settings. Large mailings drain themselves in slices, hands-free. |
mail_list_headers_raw |
Fixes the RFC 2047-mangled List-Unsubscribe header so Gmail/Outlook/Yahoo show their native Unsubscribe button and one-click unsubscribe (RFC 8058) actually counts. |
They are independent — install either or both.
Problem 1 — Odoo has no send-rate limit. Every mass-send path in Odoo
hands all remaining recipients to the composer in one pass. There is
internal batching, but no time-based cap: a 5,000-recipient mailing leaves as
fast as your relay accepts it. On Gmail/Google Workspace, Office 365, or any
relay with hourly caps, that means deferrals, rate-limit bounces, spam
foldering — and a domain reputation that takes weeks to recover.
mass_mailing_throttle adds the missing knob: a global budget per rolling
hour (default 200) plus optional per-minute burst smoothing (default 10),
enforced at the one method every send path funnels through. Throttled
mailings just sit in Sending and finish by themselves.
Problem 2 — your unsubscribe header is silently broken. Odoo builds
messages with email.policy.SMTP, and Python's header folder RFC
2047-encodes any header line it cannot fold — which is every
List-Unsubscribe URL, since URLs contain no whitespace to break on. The
result on the wire:
List-Unsubscribe: =?utf-8?q?=3Chttps=3A//mycompany=2Eexample=2Ecom/mailing/42/?=
=?utf-8?q?unsubscribe=5Foneclick=3F...?=
List-* headers are structured fields (RFC 2369) where encoded-words are
illegal, so mailbox providers find no URI: no native Unsubscribe button, and
no credit for the one-click unsubscribe Gmail and Yahoo have required from
bulk senders since 2024. mail_list_headers_raw disables folding on exactly
the messages that carry List-* headers (with guard rails against the RFC
5321 line limit), so the URL goes out verbatim.
-
Clone into your addons path:
git clone https://github.com/ConStrut/odoo-mail-deliverability.gitor copy the module folder(s) you want into a directory already listed in
addons_path. -
Restart Odoo, update the Apps list (Apps → Update Apps List, with developer mode on).
-
Install Mass Mailing Send Throttle and/or Raw List-Unsubscribe Headers from Apps.
Note: the throttle ships enabled at 200 emails/hour and 10/minute — that is its job. Review the limits in Settings → Email Marketing → Send Throttle right after installing, especially if you already send at higher volumes.
- Odoo 18.0, Community and Enterprise.
- No external Python dependencies. No JavaScript. No new models.
mass_mailing_throttledepends onmass_mailing;mail_list_headers_rawdepends onbaseonly.
odoo-bin -d <your-db> --test-tags /mass_mailing_throttle,/mail_list_headers_raw --stop-after-init
These modules deliberately stay small:
- No per-mailing or per-server limits — the budget is global, because relay caps are per account, not per campaign.
- No warm-up schedules, no reputation scoring, no analytics. Pair the throttle with proper SPF/DKIM/DMARC and list hygiene; it controls volume, nothing else.
- The header fix does not add
List-*headers — Odoo'smass_mailingalready sets them; this module just stops them being mangled in transit.
Issues and PRs welcome, especially version ports (the header-folding bug
affects any Odoo version that builds messages with email.policy.SMTP).
Please keep PRs in the spirit of the modules: minimal surface, no new
dependencies, tests included.