Someone asks how many people opened the invoice email. Mailgun has a switch for that, it is one line of code, and turning it on is the wrong first move, not because tracking is forbidden, but because the two features hiding behind that switch do more than count.
What "tracking" actually does to your message
Open tracking appends a 1×1 transparent image to the HTML body, hosted on a Mailgun domain with a unique identifier per message. When a mail client loads images, Mailgun records a timestamp, the requesting IP address and the user-agent. So an "open" is: the recipient's approximate location, the time they read their mail, and the device they read it on.
Click tracking rewrites every href in your message to point at a Mailgun
redirect, which logs the click and forwards on. Your carefully written
https://app.example.com/invoice/1234 becomes something like
https://email.mg.example.com/c/eJx….
Both are useful for a marketing campaign. Both have costs that are easy to discover late.
Cost one: it is personal data
An IP address is personal data under GDPR, and so is a record of when a named person read a message. Turning on open tracking means you are collecting behavioural data about identified individuals, which needs a lawful basis, an entry in your record of processing, a line in your privacy policy, and an answer when someone files a subject access request asking what you know about them.
For transactional mail this is a bad trade. Legitimate interest is a defensible basis for sending a receipt. It is much harder to argue for logging where the recipient was standing when they read it.
Cost two: it hurts deliverability
Click tracking rewrites links so that the visible text and the destination disagree. That is the exact shape of a phishing email, and filters score it that way. You are also inheriting the reputation of the tracking domain, if it is Mailgun's shared one, that reputation is shared with every other account using it; if it is yours, you now have a second domain to warm up and monitor.
Open-rate numbers have also been unreliable since Apple's Mail Privacy Protection began pre-fetching images for anyone using Apple Mail. Those opens are recorded whether or not a human looked. You are paying the deliverability and privacy costs of tracking to receive a number that is inflated by an unknown amount.
Cost three: it can break the thing the email is for
Corporate mail security (Defender, Proofpoint, Mimecast) follows every link in an incoming message before delivery, to check where it goes. With click tracking on, each of those checks is a recorded click. Your "click rate" now includes robots.
Worse, if the link is single-use, the scanner burns it. The user clicks a perfectly good magic link and is told it has already been used. Tracking did not cause that problem, but it adds a redirect hop to a URL that was already fragile.
The wrong way
// Tracking on globally, because someone wanted a dashboard.
await client().messages.create(domain, {
from, to, subject, html,
"o:tracking": "yes",
"o:tracking-clicks": "yes",
"o:tracking-opens": "yes",
});
Now every password reset carries a pixel and every sign-in link is rewritten. Nobody decided that; it was a default applied to everything.
The right way: off by default, opt in per send
Make tracking a parameter with a safe default, so enabling it is always a visible decision in a diff:
export interface SendEmailOptions {
// ...
/** Off by default. See the tracking-and-privacy doc before turning it on. */
tracking?: boolean;
}
await client().messages.create(sendingDomain(), {
from: fromAddress(),
to,
subject: options.subject,
html,
text,
"h:Reply-To": replyTo,
"o:tracking": options.tracking ? "yes" : "no",
});
Note that the per-message setting overrides the domain's default, which is exactly what you want: the domain can be configured however the dashboard was left, and your code still sends what it intended.
Then hold the line on three categories, permanently:
- Magic links and password resets. No pixel, no rewritten URL. The link is a credential and every extra hop is a place for it to be consumed early.
- Receipts and invoices. They are financial records. A tracking pixel in one is indefensible and a rewritten link in one looks like fraud.
- Anything to a recipient in a jurisdiction whose consent you do not have.
What to measure instead
The questions people actually want answered rarely need a pixel:
- "Did it arrive?": that is a Mailgun
deliveredevent, from the webhook. No pixel involved, no personal data beyond the address you already have. - "Did it bounce or get reported?":
failedandcomplainedevents. These are the ones worth alerting on. - "Did they do the thing?": measure the outcome in your own product. A signed URL with a campaign parameter that lands on your page gives you a conversion number you own, tied to an action rather than an image load, and it is not inflated by Apple's pre-fetching.
That last substitution is the important one. "Opened the email" is a proxy for "the email worked". You can measure the real thing on your own domain, where you already have consent and a privacy policy that covers it.
If you do turn it on
For genuine marketing sends, to a list that consented:
- Set up a custom tracking domain (a
CNAMEon something likeemail.yourdomain.com) so you are not sharing reputation with strangers. - Say so in your privacy policy, in words a person can read.
- Scope it to the campaign:
tracking: trueon that send, not on the domain default. - Set a retention period for the events and honour it.
- Never re-use the same domain for transactional mail.
The default stays off. That way, the day someone asks "do we track opens on password resets?", the answer is a one-word no rather than an audit.