Mailgun Connector — Bounce, Complaint & Event Tracking
by Practical Business Machines https://practicalbusinessmachines.com| Availability |
Odoo Online
Odoo.sh
On Premise
|
| Odoo Apps Dependencies |
•
Email Marketing (mass_mailing)
• Contacts (contacts) • Discuss (mail) |
| Lines of code | 560 |
| Technical Name |
mailgun_connector |
| License | LGPL-3 |
| Website | https://practicalbusinessmachines.com |
Mailgun Connector
Bounce, Complaint & Event Tracking for Odoo Email Marketing
Real bounce numbers. Cleaner lists. Better deliverability.
Out of the box, Odoo never learns what Mailgun already knows. Hard bounces, spam complaints and unsubscribes are processed by Mailgun but never flow back — so every mailing shows bounced = 0, dead addresses get re-mailed forever, and the sending reputation of your domain quietly erodes. Mailgun Connector closes the loop.
The gap it fills
Without the connector
- Every mailing reports 0 bounces, whatever Mailgun actually saw.
- Hard-bounced and complained addresses stay on your lists and get mailed again.
- Repeated sends to dead mailboxes drag down your domain reputation.
- Historical suppression data sits in Mailgun, invisible to Odoo.
With the connector
- Bounce, complaint and unsubscribe counts on each mailing are real.
- Dead and unhappy recipients land on the Odoo blacklist automatically.
- You stop mailing addresses that hurt deliverability.
- A one-click backfill pulls Mailgun's existing suppression lists into Odoo.
How it works
1. Point Mailgun at Odoo
Paste your signing key and copy the ready-made /mailgun/webhook URL
from Settings → Mailgun Connector into Mailgun → Webhooks. No code,
no proxy, no middleware.
2. Events flow back in real time
Every bounce, complaint and unsubscribe is HMAC-verified, logged, and applied to the right mailing trace and contact — the moment Mailgun reports it.
3. Backfill the past
One click (or the optional nightly job) pulls Mailgun's existing bounce, complaint and unsubscribe lists via the API, so historical dead addresses stop getting mailed.

What happens to each Mailgun event
Only deliverability events mutate Odoo state. Everything else is recorded for audit but never touches your stats — so opens are logged, not double-counted against Odoo's own tracking pixel.
| Mailgun event | Effect in Odoo |
|---|---|
failed (permanent) |
Mailing trace marked bounced, contact's bounce counter +1, address blacklisted. |
failed (temporary / soft) |
Bounce counted, but the address is never blacklisted — a full mailbox is not a dead one. |
complained (spam) |
Trace marked bounced (opt-out), address blacklisted. |
unsubscribed |
Address blacklisted. |
delivered / opened / clicked / … |
Recorded in the Mailgun Events log only — no state change. |
Per-campaign status is only written when the event is matched to a mailing by Message-Id. A looser recipient-only match is kept for visibility but never rewrites an unrelated campaign's bounce status.
Features
- Real-time webhook at
/mailgun/webhook— bounces, complaints and unsubscribes applied the instant Mailgun reports them. - HMAC-SHA256 signature verification on every call, with a 15-minute replay guard. Unsigned or forged calls are rejected.
- Idempotent by Mailgun event id. At-least-once webhook retries and repeated backfills never double-apply a side effect.
- Automatic blacklisting of hard bounces, spam complaints and unsubscribes — each independently toggleable.
- Soft bounces counted, never blacklisted — temporary failures don't cost you a good contact.
- Full audit log (Mailgun Events) of every delivery event, with filters for failures, complaints, unsubscribes and blacklisted actions, plus the raw payload.
- Suppression backfill — one-click button and an optional nightly job pull Mailgun's existing lists via the API.
- US & EU regions, safe recipient normalization, and concurrency-safe ingestion.

Real numbers on every mailing
Because permanent failures write straight back to the mailing trace, the Email Marketing dashboard finally shows the truth: real bounce counts per campaign, a blacklist that keeps itself clean, and a bounce counter that rises on the contacts that actually failed.

Configuration
Everything lives under Settings → Mailgun Connector:
- Paste your Webhook Signing Key, Private API Key and Sending Domain
(e.g.
mg.example.com). - Pick the API Base URL for your region — US (
api.mailgun.net) or EU (api.eu.mailgun.net). - Copy the generated Webhook URL into Mailgun → Webhooks for
permanent_fail,temporary_fail,complainedandunsubscribed(optionallydelivered/opened/clicked).
- Choose which events add to the blacklist — hard bounce, spam complaint and unsubscribe are independently switchable.
- Click Sync suppressions now once to backfill history.
- Optionally enable the Mailgun: sync suppressions scheduled action (ships disabled, so nothing runs until you say so).
Built to be trusted with your list
Secure by default
Every webhook call is verified with an HMAC-SHA256 signature over Mailgun's
timestamp + token, compared in constant time. A signed timestamp
older than 15 minutes is rejected as a replay. Invalid signatures never reach your data.
Safe to retry
Events are de-duplicated on Mailgun's event id with a database uniqueness constraint and concurrency-safe ingestion, so retries, races and repeated backfills apply each side effect exactly once. One shared, idempotent code path drives both the webhook and the backfill.
Compatibility & support
Odoo 17.0 & 19.0, Community & Enterprise · depends on the standard
Email Marketing (mass_mailing) module · License OPL-1.
A Practical Business Machines product by Davenport Pacific. Questions? support@dvptp.com
Please log in to comment on this module