TracSend: Mass Email Campaigns with Real-Time Analytics
Send personalised bulk email from your own Gmail and watch opens, clicks and bounces live.




The problem and context
Sending bulk communications from a standard or Google Workspace Gmail account is notoriously frustrating. Traditional mail-merge add-ons are clunky, prone to formatting breakages, and offer no reliable feedback on who opened, who clicked, or which addresses bounced. Furthermore, Google enforces strict daily sending limits (500 emails/day for standard accounts, 2,000/day for Google Workspace) and penalises bursty, unthrottled sending behaviour.
TracSend lets users authenticate securely with Google OAuth, compose campaigns in a rich-text editor, upload recipient CSVs with automated first/last-name personalisation, and choose between immediate sending or scheduled queues. Every message dispatches directly through the user's authentic Gmail mailbox, while opens, clicks, bounces, and unsubscribes stream to a live dashboard as they occur.
Stack and architecture
Role: Full-Stack Engineer & System Architect
Timeline: October 2025 – February 2026
Core Stack: Node.js, Express, PostgreSQL, Prisma ORM, Socket.IO, React, TypeScript, Tailwind CSS, Upstash Redis
The platform is designed around 6 core architectural decisions:
1. Gmail OAuth 2.0 & Token Mutex
User tokens are encrypted at rest using AES-256-GCM. Because batch dispatching fires concurrent requests, a module-level mutex guarantees that simultaneous sends within a batch trigger only a single token refresh cycle, preventing race conditions and token invalidation. Revoked grants (invalid_grant) immediately clear stored credentials and prompt safe re-authentication.
2. Throttled Sending Engine
Recipients are processed in small concurrent batches (defaulting to 3, capped strictly at 10) to respect Gmail's burst-rate thresholds. The dispatcher uses exponential backoff for transient network issues and longer backoff intervals for rate-limit warnings. Hard bounces are permanently suppressed from future attempts, and an automated suppression list is queried before every single dispatch.
3. Relational Schema & Hot-Path Indexing
The PostgreSQL database is managed via Prisma ORM across 12 relational models (users, campaigns, recipients, tracking events, tracking links, attachments, sender identities, signatures, templates, suppression lists, waitlist, and admins). Cascading deletes clean up child records automatically, while targeted database indexes accelerate hot query paths on campaignId, status, scheduledFor, opened, and clicked.
model Recipient {
id String @id @default(uuid()) @db.Uuid
campaignId String @map("campaign_id") @db.Uuid
email String @db.VarChar(255)
delivered Boolean @default(false)
opened Boolean @default(false)
openedAt DateTime? @map("opened_at")
clicked Boolean @default(false)
bounced Boolean @default(false)
unsubscribed Boolean @default(false)
campaign Campaign @relation(fields: [campaignId], references: [id], onDelete: Cascade)
@@unique([campaignId, email])
@@index([campaignId])
}
Prisma schema for campaign recipients with indexed query paths and cascade deletion.
4. Atomic Event Deduplication
Tracking endpoints serve transparent 1×1 pixels and wrapped click redirects from /track and /unsubscribe. To prevent metric inflation from mail clients requesting assets repeatedly, database records update conditionally in a single atomic query:
// Atomic dedupe: only the first open updates a row, so counts can't be inflated
const updateResult = await prisma.recipient.updateMany({
where: { id: recipientId, opened: false },
data: { opened: true, openedAt: new Date() },
});
if (updateResult.count === 0) return; // Repeat open, ignore
Atomic conditional update ensuring only the very first recorded open modifies the database.
5. Resilient Real-Time WebSocket Layer
Real-time progress streams via Socket.IO over JWT-authenticated connections. Rooms are scoped strictly per user (user:<id>) and per campaign (campaign:<id>), guaranteeing multi-tenant event isolation. A client-side SocketService singleton handles connection dropouts by reconnecting with jittered exponential backoff. Upon reconnection, it re-joins active rooms and re-synchronises server state without wiping in-progress optimistic React Query cache patches.
6. Background Scheduling & Asynchronous Bounce Ingestion
A lightweight node-cron daemon evaluates due campaigns and orchestrates execution queues, while renewing Gmail API watches every 6 hours. Bounce detection listens to Gmail Watch pushes via a Google Cloud Pub/Sub webhook, reading incoming messages through the Gmail History API and parsing Non-Delivery Reports (NDRs) with regex patterns to extract recipient addresses and bounce error classifications. If a history token expires, the service falls back to targeted Gmail searches.
Design and UX decisions
- Trustworthy Analytics: Raw pixel hits are notoriously misleading due to security scanners and mailbox proxies. TracSend filters known bots and prefetch hits, so the counts reflect real engagement far more closely than raw pixel hits. It enforces a strict post-delivery window (with tighter thresholds when sender equals recipient), ignores hits on bounced addresses, and records only the initial open per recipient.
- Live Feedback Without Refetching: Real-time WebSocket payloads directly update the client React Query cache (
setQueryData), dynamically incrementing counters across the dashboard, campaign index, and detail views without triggering full-page refetches. Analytics computations are debounced (2s) during active high-volume dispatches. - Resilient Connection Lifecycle: The interface never gets stuck in stale states during brief network disconnects. The connection manager recovers missed background events automatically upon reconnection.
- Actionable Insights: An analytics suite built with Recharts visualises deliverability time-series, optimal send times, bounce breakdowns, top-clicked links, and individual sender identity metrics.
- Familiar Composing: Includes a TipTap rich-text editor supporting custom formatting, tables, typography variables, CSV column mapping, draft autosaving, multiple sender identities verified via security codes, and custom HTML signatures.
- Safe by Default: Suppression lists and one-click unsubscription are honoured automatically. Bounced emails surface clear, human-readable explanations (e.g. "Recipient mailbox is full") instead of raw SMTP diagnostic codes.
Results
- Deployed to production and live at tracsend.com.
- Engineered to reliably dispatch batches of up to ~500 emails per send through Gmail's API with sub-second WebSocket metric delivery.
- Designing and implementing TracSend provided hands-on experience in managing third-party API rate limits, implementing resilient state synchronisation over WebSockets, and architecting tamper-resistant analytical pipelines.