Skip to content

Latest commit

 

History

History
160 lines (114 loc) · 4.81 KB

File metadata and controls

160 lines (114 loc) · 4.81 KB
summary Email open tracking in gog (Gmail + Cloudflare Worker)
read_when
Adding/changing Gmail email open tracking
Deploying the tracking worker (Cloudflare D1)

Email tracking

Goal: track email opens for gog gmail send via a tiny tracking pixel served from a Cloudflare Worker.

High-level:

  • gog gmail send --track injects a 1×1 image URL into the HTML body.
  • The Worker receives the request, stores an “open” row in D1, and returns a transparent pixel.
  • gog gmail track opens … queries the Worker and prints opens.

Abuse controls:

  • Repeated opens for the same tracking id, IP, and user-agent are deduplicated within a one-hour window.
  • Each IP can record at most 100 opens per hour; excess requests still receive the transparent pixel but are not inserted into D1.

Privacy note:

  • Tracking is inherently sensitive. Treat this as instrumentation you opt into per email.
  • The Worker stores recipient email, subject hash, sent/open timestamps, IP, user-agent, bot classification, and coarse geo from Cloudflare request metadata when available.
  • The deployed Worker includes a daily cron trigger that deletes open rows older than 90 days.
  • Admin /opens queries default to 100 rows and are capped at 500 rows per request.

Setup (local)

Create per-account tracking config + keys:

gog gmail track setup --worker-url https://gog-email-tracker.<acct>.workers.dev

This writes a local config file containing:

  • worker_url (base URL)
  • the active tracking key version
  • per-account tracking/admin keys are stored in your keychain/keyring (not in the JSON file)

Optional: auto-provision + deploy with wrangler:

gog gmail track setup --worker-url https://gog-email-tracker.<acct>.workers.dev --deploy

Flags:

  • --worker-name: default gog-email-tracker-<account>.
  • --db-name: default to worker name.
  • --worker-dir: default internal/tracking/worker.

Re-run gog gmail track setup any time to re-print the current TRACKING_KEY / ADMIN_KEY values (it’s idempotent unless you pass explicit --tracking-key / --admin-key).

Deploy (Cloudflare Worker + D1)

From repo root:

cd internal/tracking/worker
pnpm install

Provision secrets (use values printed by gog gmail track setup):

pnpm exec wrangler secret put TRACKING_KEY
pnpm exec wrangler secret put TRACKING_KEY_V1
pnpm exec wrangler secret put TRACKING_CURRENT_KEY_VERSION
pnpm exec wrangler secret put ADMIN_KEY

Create D1:

pnpm exec wrangler d1 create gog-email-tracker

Update wrangler.toml to reference the D1 database_id, then migrate and deploy:

pnpm exec wrangler d1 execute gog-email-tracker --file schema.sql --remote
pnpm exec wrangler deploy

wrangler.toml includes a daily cron trigger for retention cleanup. After deploy, Cloudflare calls the Worker once per day and the Worker deletes open rows older than 90 days.

Rotate tracking keys

Rotate the pixel encryption key without invalidating old tracking ids:

gog gmail track key rotate

The command generates the next key version, deploys all active TRACKING_KEY_V<N> secrets plus TRACKING_CURRENT_KEY_VERSION, then stores the new current version in local config. Legacy unversioned tracking ids still decrypt through the stored TRACKING_KEY fallback.

For local-only testing:

gog gmail track key rotate --no-deploy

Do not send newly tracked mail after --no-deploy until the Worker has the matching versioned secret, or new pixels will not decrypt.

Send tracked mail

Tracked email constraints:

  • Exactly one recipient (--to; no cc/bcc).
  • HTML body required (--body-html).

Optional per-recipient sends:

gog gmail send \
  --to [email protected],[email protected] \
  --subject "Hello" \
  --body-html "<p>Hi!</p>" \
  --track \
  --track-split

--track-split sends separate messages per recipient (no CC/BCC; each message has a unique tracking id).

Example:

gog gmail send \
  --to [email protected] \
  --subject "Hello" \
  --body-html "<p>Hi!</p>" \
  --track

Query opens

By tracking id:

gog gmail track opens <tracking_id>

By recipient:

gog gmail track opens --to [email protected]

Status:

gog gmail track status

Troubleshooting

  • required: --worker-url: run gog gmail track setup --worker-url … first (or pass --worker-url again).
  • 401/403 on /opens: admin key mismatch; redeploy secrets and re-run track setup if needed.
  • New tracked messages do not show opens after key rotation: verify the Worker has TRACKING_KEY_V<N> for the current local gmail track status version and TRACKING_CURRENT_KEY_VERSION matches it.
  • No opens recorded:
    • ensure the HTML body contains the injected pixel (view “original” in your mail client).
    • some clients block images by default; “open” only happens after images load.