MailGun
Mailgun is an email delivery service for sending, receiving, and tracking emails. We utilise it to send emails via the hub.
Email sending domains
New domains, e.g. for sending emails via a new client hub, need to be added to Mailgun.
For a new domain to then be verified within Mailgun, the required Mailgun DNS records must be configured within the DNS provider's system.

See also: Mailgun How Do I Add or Delete a Domain?
Suppression lists
Mailgun tracks several suppression lists per sending domain — addresses it will no longer deliver to. We surface and manage only the bounces list: when a send hard-bounces (invalid mailbox, domain doesn't exist, and similar permanent failures), Mailgun adds the address to that domain's bounce list, and every further send to it is dropped silently rather than retried.
We deliberately never read or clear the unsubscribes or complaints lists through the hub. Those exist because a recipient opted out or marked a message as spam, so removing an address from either would mean emailing someone who asked not to receive mail — a compliance problem, not a delivery convenience. See Mailgun's own docs on suppressions for how the other lists work.
A suppression list belongs to a Mailgun domain, not to a hub — the same sending domain is often shared across several hubs (see Email sending domains above), so its bounce list mixes bounces from all of them. Hub admins can only see and clear suppressions for their own hub because the API resolves the hub's sending domain, then filters Mailgun's list down to addresses that belong to a user of that hub — the domain itself is not the security boundary.
That filter matches two kinds of address, under different rules:
- A user's primary address, for any hub they are an active member of.
- A user's additional addresses, for their home hub only (
users.helix_domain_id), and only where the hub hasallowMultipleUserEmailsenabled.
See Email suppression list for the admin-facing feature built on this.
Reading a domain's whole list
Because a hub's own addresses are scattered through a list dominated by other hubs' users, the API reads the domain's entire bounce list before filtering, rather than a page at a time. Mailgun's suppressions endpoint caps limit at 1000, and the busiest sending domain holds a few thousand bounces, so a whole list is a handful of sequential calls — around one to two seconds.
Reading all of it is also what makes ordering possible: Mailgun documents no sort parameter, and its pagination cursor iterates by address, so suppression date is only available once the whole list is in hand.
Two properties of the endpoint are worth knowing when changing this code:
- A
nextlink is not a signal that more remain. Mailgun returns all four paging links on every response, including one carrying zero items. An empty page is what marks the end of the list. - The walk is bounded. It stops after 20 pages (20,000 addresses) and raises a
slackAlert, so a domain that outgrows a single request is noticed before an admin reports a missing address.
Configuration
Suppressions are read and cleared by api/ directly, over the Mailgun API, using its own MAILGUN_API_KEY — a separate credential from the one mail-service uses to send mail, configured the same way (api/config/misc.js).