MailSignals

Self-hosted · open source · no Gmail permission

Honest email tracking for Gmail, hosted by you.

See when the email you send is opened, clicked, replied to or bounced, with the reason behind every verdict. MailSignals runs in a Firebase project you own and never asks for access to your mailbox.

  • No Gmail OAuth scope, ever
  • Your data in your Firebase project
  • Your own tracking domain
  • MIT licence, 371 unit tests
  • ✓✓ Ada Lovelace Proposal: analytics engine, phase two — Attached the revised scope and the numbers we discussed 10:42 Opened twice · last 14 minutes ago · through a mail proxy, so the count is a lower bound
  • Grace Hopper Re: Compiler talk on Thursday — Yes, 3pm works. I will bring the slides 09:15
  • Noor Haddad Onboarding checklist for the pilot — Everything you need is in the doc linked below Yesterday
  • ✓✓ Kenji Sato Invoice 0142 — Payment terms as agreed, 30 days Yesterday
  • Priya Raman Quick question about the API limits — Before I commit to the batch size Mon
  • ops@oldvendor Renewal — Following up on the quote from March Mon
Checkmarks in your Sent list, drawn by the extension. Hover one and the tooltip says what is known and, when it is uncertain, why.

Why it exists

Commercial trackers ask for your whole mailbox. This one asks for nothing.

They need the full Gmail scope because they rebuild group emails and rewrite your Sent copy through the Gmail API. MailSignals does everything inside the Gmail page instead, through the InboxSDK library, so sign-in asks for openid, email and profile and stops there.

Commercial trackers compared with MailSignals
Commercial trackersMailSignals
Gmail OAuth scopeFull mailbox accessNone
Google verificationAnnual CASA Tier 2 security assessmentNot required
Where your data livesVendor's serversYour Firebase project
Tracking domainShared, on every blocklistYours alone
Cost$36–72 per user per yearAbout $0–3 a month, mostly the domain

The full comparison, including what MailSignals gives up →

The differentiator

Every number is defensible in one sentence.

A pixel request tells you far less than a green tick implies. Gmail fetches every image through a proxy. Apple downloads images on delivery, before anyone reads. Corporate gateways follow every link. Your own Gmail fetches the pixel too.

So every recorded hit gets a verdict from a 15-rule classifier, a confidence, and a plain-English reason that is shown as body text next to the event, followed by a "Who" line. An Apple prefetch is called a prefetch. A proxied open is called a lower bound. An unrecognised client is recorded and counted nowhere.

Replies beat clicks beat opens, and the interface is built to say so.

The rules, in order, with their confidences →
  1. +0.6 s Your own view Pixel loaded Your own Gmail loaded the image while showing the copy in your Sent folder. Who: You.
  2. +3 s Delivered, open unconfirmed · 80% sure Pixel loaded Apple Mail Privacy Protection downloaded the image on delivery. The message reached the device, but we cannot tell whether it was read. Who: Nobody yet: the recipient's mail app fetched it on delivery.
  3. +14 min Opened (proxied) Pixel loaded Gmail loaded the image through its proxy while showing the message. Gmail hides the reader's device and location. Who: Gmail hides who read it. The recipient — or you, if you opened this on a device without MailSignals.
  4. +1 d 3 h Opened Reply received A reply arrived in this thread. Who: The recipient, on their own device.
The detail page for one message. The reason is the body text of each entry, not a tooltip; the Who line says who was plausibly behind it.

How it works

Nothing changes about how you send. Three things happen underneath.

You press Send

The extension plants a 42-byte pixel, linkifies URLs you typed as text, signs eligible links through your own tracking host, and registers the message with your project before Gmail acknowledges the send. If any of that fails, the mail goes out unchanged.

Someone opens it

Their client fetches the pixel or follows a link. The endpoint answers first and records second, classifies the request against what it knows about proxies, prefetchers, scanners and you, and writes an event with its reason.

You find out

A green tick in Gmail within a minute, a desktop notification if you asked for one, a daily digest if you prefer, and a dashboard that shows the whole history with every verdict justified.

The architecture, the flows and the reasons behind them →

The hardest problem

It does not turn green when you open your own Sent folder.

The most common complaint about every tracker on the market. When you look at a sent message, your Gmail fetches the pixel through the same proxy a recipient would use: same user agent, same IP, same referrer. Nothing in the request tells the two apart.

MailSignals knows two things the request does not say: the extension can see what is on your screen, and the message was registered from your network. Any pixel hit within 20 seconds of you viewing the message is withdrawn as your own, in whichever order the two arrive, with a trigger-side backstop for the race in between. A direct fetch from your own network with a Gmail referrer is recognised without any of that.

On a phone without the extension the ambiguity is real and the product says so: the dashboard offers "That open was me", and after two of those it points you at the one setting that removes the problem at the source.

The four paths, and the one that only appeared in production →

Desktop notifications, filtered by your preferences and quiet hours, computed in your timezone rather than the machine's. An alert that fires on a scanner's fetch would teach you to ignore alerts, so only counted events can raise one.

Privacy

Never the body. Never a full IP address. Never a third party.

The people who open your email did not install anything and did not agree to anything, so what is kept about them is the minimum that still lets the classifier work.

  • A timestamp, the user agent, an IP truncated to a /24 and a salted hash of it. The full address exists only as a local variable in the request handler and is never written.
  • No location, even though a setting for it exists; no code path records one today, and the privacy page says so.
  • For mail sent from Gmail in a browser, the body is never read, transmitted or stored.
  • Nothing is sent anywhere but your own Firebase project and Google itself. The one third-party library is loaded with its telemetry switched off.
  • A do-not-track domain list, an optional disclosure footer and a per-message off switch, so you can comply with ePrivacy and the CNIL where you must.
To: me@mycompany.example
Draft for tomorrow

Notes for the morning: the numbers are in the shared sheet and the summary is below.

Not tracking: every recipient is one of your own addresses, so an open would only ever be you.
Send✓ Tracking off
The compose toolbar carries a per-message toggle, and a notice explains every refusal. Mail to yourself is never tracked, with no way to override it.

Cost

Free software. About the price of a domain to run.

The software. MIT licence.
$0
A month to run, almost all of it the domain
$0–3
For a first deployment, mostly waiting for DNS
1 h
End-to-end checks against production, all green
240

One Firebase project on the pay-as-you-go plan, whose free quotas cover a person's email with room to spare. No seats, no tiers, no history cap. The bill, line by line →

Questions

The five people ask first.

Why does it not just use the Gmail API?

Because a Gmail scope is a restricted scope. It triggers Google's OAuth verification, an annual third-party CASA security assessment, and a hard cap of 100 lifetime users until that completes. For a tool you host yourself that price buys nothing: everything it needs is on screen in front of you already. The trade is that replies, bounces and your own reads have to be recovered from the page, which is most of what makes MailSignals interesting.

What do the checkmarks mean?

Grey ✓ is sent. Green ✓✓ is opened by a person, as far as the evidence supports. Amber ✓✓ is delivered to Apple Mail, which loads images before anyone reads. ↗ is a link clicked, ↩ is a reply, ✕ is a bounce. Hover any of them and the tooltip says what is known and, when the answer is uncertain, why.

How much work is self-hosting?

About an hour the first time, mostly waiting for DNS and certificates. You create a Firebase project, point two subdomains at it, create an OAuth client and two secrets, run one deploy script, and load the extension. The guide on this site walks through every step and the troubleshooting table covers what usually goes wrong.

Can other people on my machine end up in my history?

No. A browser can hold several Gmail accounts, and the extension runs in all of them, so only a Gmail address you have explicitly linked to your MailSignals account is tracked. The server refuses everything else before writing anything.

Is there a catch?

Two honest ones. Reply detection reads the Gmail page, so a reply on a thread you never open can be missed; there is a manual mark for that. And on a phone without the extension your own reads of your sent mail look like a recipient's, so Gmail's "ask before displaying external images" setting is the real fix. Both follow directly from not having a Gmail scope.

All 23 questions, answered without hedging →

Run it in your own project.

One Firebase project, two subdomains, one deploy script. About an hour the first time, and no subscription afterwards.