7.9 KiB
Phantom Opens & Clicks from Email Security Scanners
Date: 2026-07-03
In plain English (no tech background needed)
When we send a marketing email, most of the businesses we email use a security guard for their inbox (Microsoft, Proofpoint, Mimecast, and similar). Before a real person ever sees our email, that guard opens the email and clicks every link in it first, just to make sure nothing is dangerous. Think of it like the mailroom in a big office opening and X-raying a package before handing it to the employee.
Here is the problem: our tools can't easily tell the difference between the guard and a real person. When the guard opens the email, it counts as an "open." When the guard clicks the link to inspect it, it can count as a "click." So our reports can say "30% of people opened it and some clicked!" when in reality it was mostly robots checking for viruses, and no actual human was interested.
That's why we don't trust "opens" or even raw "clicks" as proof that the campaign is working. A robot opening an email doesn't pay us. So instead we look at things a robot almost never does:
- Did someone reach the order page for a service?
- Did they start checkout?
- Did they actually pay?
Those are the numbers that matter. If a campaign shows lots of opens and clicks but nobody reached the order page, that's a strong sign it was mostly the robot security guards, not real customers. We also run a filter that spots the tell-tale signs of these robots and quietly ignores them, so our real numbers only count real people.
Bottom line: "opens" and "clicks" look impressive but are mostly robots. Real interest = order-page visits, checkouts, and payments.
The short version
Email opens, and even clicks, are unreliable signals because email security gateways automatically fetch and render every link in a message to scan it for malware, before the human ever sees the email. Those automated fetches fire the same tracking pixels and, for the advanced scanners that drive a real headless browser, the same JavaScript pageviews/clicks that a human would. So a campaign can show 20-40% "opens" and a handful of "clicks" with zero real human engagement.
This is why we treat Listmonk opens as noise, do our conversion tracking in Umami with a bot filter, and judge campaigns on human clicks → order-page views → checkout → paid orders, never on opens.
Who does this and how
| Gateway | Product | Behavior |
|---|---|---|
| Microsoft | Defender for O365 "Safe Links" / ATP detonation | Rewrites every URL, fetches it, and detonates suspicious ones in a real browser sandbox. Very common on business/outlook/M365 tenants. |
| Proofpoint | URL Defense (urldefense.com / pphosted.com) |
Rewrites and pre-fetches every link; re-scans on click. |
| Mimecast | URL Protect / Attachment Protect | Pre-fetches and rewrites links. |
| Barracuda | Link Protect | Fetches links at delivery. |
| Cisco / Symantec / MessageLabs | Secure Email / ClickTime | Scan-on-delivery and scan-on-click. |
Gmail image proxy (GoogleImageProxy) |
Pre-fetches images (inflates opens, not usually JS clicks). |
Two distinct effects:
- Inflated opens. Any gateway that loads the tracking pixel (or Gmail's image proxy caching it) counts as an "open" in Listmonk. This happens on a large fraction of B2B mail. Opens are therefore close to meaningless.
- Phantom clicks / pageviews. The advanced scanners (Microsoft ATP, Proofpoint, Mimecast) run a headless browser that executes JavaScript. That fires a real Umami pageview and can trip click events, so the visit looks human. This is the dangerous one because it corrupts the metric we actually rely on (clicks), not just the one we already ignore (opens).
Extra wrinkles:
- Scanners often fetch within seconds of delivery, in bulk, from datacenter IPs, before any human could plausibly read the email.
- They may fetch every link, so a "click" on a deep CTA can be a scanner walking all URLs, not a human choosing one.
- Microsoft rewrites the URL, so the referrer/host can look like
*.safelinks.protection.outlook.com; Proofpoint usesurldefense.com.
How we defend against it
1. Listmonk click tracking is intentionally OFF on per-subscriber CTAs
Our conversion CTAs are per-subscriber links (?dot=, ?npi=, {{ lp_link }}).
Listmonk's @TrackLink was removed from those (it caused a 404 + collapse bug),
so "0 clicks" in Listmonk is expected and not a real signal. Real clicks are
attributed in Umami via the campaign-click event. See the runbook incident
"Jun 22 2026 — @TrackLink on per-subscriber CTAs".
2. Umami has a headless/scanner bot filter
site/public/js/pw-bot-filter.js (loaded before the Umami script on every page,
wired via data-before-send="umamiBeforeSend") scores each visit for
automation/headless signals and drops the event when it looks like a bot, so
scanner traffic never reaches analytics. It is designed to fail open: any
uncertainty counts as human, so we never undercount real people.
Signals it uses (see the file for the full, commented list):
- Decisive (any one suppresses):
navigator.webdriver === true(Selenium/Puppeteer/Playwright, Chrome headless)- Headless/automation user-agents (
HeadlessChrome,PhantomJS,Electron, ...) - Known scanner UAs (
Proofpoint,Mimecast,Barracuda,Cisco,Symantec,MessageLabs,GoogleImageProxy,Microsoft Office, ...) - Zero/collapsed screen or viewport, or a window bigger than the monitor
(
outer-gt-screen) — classic headless geometry - A software WebGL rasterizer (
SwiftShader,llvmpipe,swrast) on a desktop-class UA — the single hardest signal to spoof; headless/VM scanners fall back to software rendering - Zero logical CPUs (
hardwareConcurrency === 0)
- Soft (need two to corroborate): tiny screen, low color depth, empty
navigator.languages, no pointer/hover/touch input surface, no WebGL at all.
The result is exposed as window.pwIsBot / window.pwBotReasons for debugging.
3. Server-side scanner exclusion
Most known scanner user-agents are already excluded server-side, and the MX-tag
pipeline classifies each recipient's receiving operator
(google/microsoft/proofpoint/mimecast/barracuda/...) so campaign
builders can throttle per operator. See scripts/mx_tag_carriers.py,
scripts/mail_reputation_monitor.py, and infra/cron/pw-mx-tag.
4. We measure conversion, not opens
The A/B scoreboard (scripts/coupon_ab_scoreboard.py) explicitly counts human
clicks (Umami, bot-filtered) + paid orders, never opens. The funnel we watch
is:
sent → accepted → HUMAN clicks (Umami) → order-page views → checkout starts → paid orders
What this means in practice
- Never celebrate an open rate. On a B2B list heavy with Microsoft/Proofpoint MX, 20-40% opens can be almost entirely scanners.
- Even a raw click number can be inflated if it comes from Listmonk link
tracking or an un-filtered analytics setup. Trust the Umami
campaign-clickcount (bot-filtered) and, above all, order-page views and paid orders. - Instant, bulk, datacenter-sourced "engagement" right after send = scanners. Real humans trickle in over hours/days from residential/mobile networks.
- If a campaign shows opens/clicks but zero order-page views, that is the signature of scanner-only traffic, not a landing-page problem.
Related docs
docs/email-deliverability-runbook.md— sending infra, warmup, incidents (including the@TrackLinkclick-tracking incident and the clean-pool decay fix).docs/email-no-sales-action-plan-2026-07-02.md— conversion playbook; item #2 ("opens inflated by bots/scanners") is exactly this problem.site/public/js/pw-bot-filter.js— the implementation.site/public/js/pw-analytics.js— thecampaign-click/checkout-page-viewevent definitions.