MailSignals

Guide

What a Gmail OAuth scope really costs: verification, CASA and the 100-user cap

Why commercial trackers ask for full mailbox access, what Google demands in return, and how a tracker can do the whole job from inside the Gmail page with no scope at all.

Why trackers ask for your whole mailbox

Install a commercial Gmail tracker and the consent screen asks you to let it "read, compose, send and permanently delete all your email from Gmail". That is the full Gmail scope, and vendors ask for it because their features need it:

  • Per-recipient tracking of group emails. One message carries one pixel, so to know which of five recipients opened it, the tracker re-creates the message as five messages through the Gmail API, each with its own pixel, and then deletes the duplicate copies from your Sent folder. Hence read, send and delete.
  • Hiding the pixel from you. To stop your own Sent copy loading the pixel, one vendor replaces that copy with a clean one, through the API.
  • Exact reply detection, thread and message ids, mailbox identity. All trivially available through the API.

What Google demands in return

Gmail scopes are classified as restricted. An app that requests one must go through Google's OAuth verification, and, because the scope is restricted, pass an annual third-party security assessment under the CASA framework (Tier 2 for these scopes), which costs a four-figure sum each year. Until verification completes, the app is capped at 100 lifetime users, and every user sees an "unverified app" warning on the consent screen.

For a company selling subscriptions, that is a cost of doing business. For a tool you run yourself, it buys nothing: you would be paying for an audit so that Google would let you grant your own software access to your own mailbox.

The alternatives, and what each costs

Ways to build a Gmail tracker, and what each costs
ApproachWhat it gives youWhat it costs
gmail.readonlyReply detection and self-open detection become trivialRestricted scope: verification, an annual CASA assessment, the 100-user cap until it passes
gmail.metadataHeaders and ids without bodiesStill restricted, same price
IMAP with an app passwordNo verificationNeeds your credentials, and cannot see what is on your screen, which is the one thing the self-open problem needs
No scope: integrate through the pageNo verification, no cap, no annual audit, no mailbox grantEverything the API would have given you has to be recovered from the DOM, and two things cannot be

Doing the job from inside the page

MailSignals takes the last row. Its extension runs inside the Gmail page through InboxSDK, a library that abstracts Gmail's changing DOM, and everything Gmail-shaped comes from what is on screen:

  • The sending mailbox and your send-as aliases, from the compose window's from-picker.
  • The message and thread ids, from the send hooks, raced against a timeout.
  • Replies, from a thread that gains a newer message from someone else, seen in the open thread or in the Inbox list.
  • Bounces, from Gmail's own delivery-failure notice filed into the thread.
  • Whether you archived or trashed a thread, from Gmail's "Conversation archived" toast.
  • Your own reads, from the extension reporting which sent messages are expanded on your screen, correlated with pixel fetches within 20 seconds.

The extension asks Chrome for five permissions (scripting, storage, identity, notifications and alarms) and for three hosts: Gmail, your dashboard and your tracking subdomain. The library it embeds is loaded with its crash reporting and usage telemetry switched off, and nothing in the extension talks to any host but those three.

What you lose, honestly

Two things, and the product says so in its interface rather than in a footnote.

  1. A reply on a thread Gmail never shows you. If a reply is filtered straight past the Inbox and you never open the thread, page-based detection cannot see it. A manual "mark as replied" exists for that case.
  2. Your own reads on a phone. The Gmail mobile app has no extension in it, so a self-open there looks like a recipient's proxied open. The dashboard offers "That open was me", and Gmail's "ask before displaying external images" setting removes the problem at the source.

There is a third, which is not a loss so much as a boundary: per-recipient tracking of group emails is not offered, because it needs the API. The tooltip on a group email says "N recipients, so we cannot tell which one", and per-contact statistics are only updated for messages with a single recipient.

In exchange: no verification, no cap, no annual audit, and nobody, including the software you installed, holding a grant to read, send or delete your mail.


Related: how the whole thing is put together · the comparison with commercial trackers · Article I of the project's constitution.

Run it in your own project.

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