Gmail Automation
Project Review

For Paige & Aparna — June 2026

What this does: Every 5 minutes, fetch Paige's unread emails, classify each through a 5-engine rules system backed by Gemini AI, then route to one of 5 outcomes — auto-reply, draft, flag, archive, or forward. Human-in-the-loop from day one. Paige reviews drafts before anything sends.

~11h
Estimated Build
5
Open Decisions
10
Email Categories
100–200
LLM Calls / Day
$0–10
Monthly Cost
      graph TD
        A[Trigger — every 5 min]:::step --> B[Fetch unread emails]:::step
        B --> C[Pre-filter — remove self, bots]:::step
        C --> D{Triage Engine}:::triage

        R1[Sender Rules]:::rule -.-> D
        R2[Intent Classify — Gemini]:::ai -.-> D
        R3[Content Rules]:::rule -.-> D
        R4[Thread Context]:::rule -.-> D
        R5[Sentiment + Urgency]:::rule -.-> D

        D -->|"client inquiry"| F1[Auto-Reply]:::auto
        D -->|"needs thought"| F2[Draft Response]:::draft
        D -->|"urgent, VIP"| F3[Flag for Review]:::flag
        D -->|"newsletter, noise"| F4[Archive / Skip]:::skip
        D -->|"wrong person"| F5[Forward / Escalate]:::fwd

        F1 --> G[Gemini — generate reply]:::ai
        F2 --> G
        G --> H[Gmail API — execute action]:::step
        F3 --> H
        F4 --> H
        F5 --> H

        H --> L[Audit Log — JSONL]:::step

        classDef step fill:var(--mermaid-node),stroke:var(--mermaid-step),color:var(--text),stroke-width:2px
        classDef triage fill:var(--mermaid-node),stroke:var(--mermaid-ai),color:var(--text),stroke-width:3px
        classDef rule fill:var(--mermaid-node),stroke:var(--mermaid-draft),color:var(--text-dim),stroke-width:1px,stroke-dasharray:4 3
        classDef ai fill:var(--mermaid-node),stroke:var(--mermaid-ai),color:var(--text),stroke-width:2px
        classDef auto fill:var(--mermaid-node),stroke:var(--mermaid-auto),color:var(--text),stroke-width:2px
        classDef draft fill:var(--mermaid-node),stroke:var(--mermaid-draft),color:var(--text),stroke-width:2px
        classDef flag fill:var(--mermaid-node),stroke:var(--mermaid-flag),color:var(--text),stroke-width:2px
        classDef skip fill:var(--mermaid-node),stroke:var(--mermaid-skip),color:var(--text),stroke-width:2px
        classDef fwd fill:var(--mermaid-node),stroke:var(--mermaid-fwd),color:var(--text),stroke-width:2px
    
Auto-reply
Draft for review
Flag for attention
Archive & skip
Forward / escalate
Gemini AI step

Decision Matrix — 10 Categories × 5 Outcomes

Email Category Auto-Reply Draft Flag Archive Forward
Client inquiry — new
Client inquiry — existing thread
Internal team update
Scheduling / calendar
Invoice / billing
Newsletter / marketing
Urgent / escalation
Personal / unknown
Spam / junk
System notification
Always
Draft
Flag
Conditional
Never

What Makes This Complex

This is not a simple filter → reply script. The architecture has real moving parts that compound:
5 distinct rule engines feeding one decision point — each with its own config, failure modes, and edge cases
Gemini called 2× per email (intent classification + sentiment/urgency) — 100–200 LLM calls/day on ~50–100 emails
Error surface: API failures, rate limits, malformed responses, OAuth token expiry, network timeouts — every path needs handling
Config maintenance: sender lists, keyword configs, routing rules, tone guide — all need Paige (or someone) to define and keep current
Gemini quality variance: classification accuracy, tone appropriateness, hallucination risk — all need monitoring and tuning over time

Runtime Tradeoff

Google Apps Script
Zero infrastructure
  • Zero hosting cost — runs on Google's infra
  • Built-in GmailApp — no REST API complexity
  • 5-minute triggers native to platform
  • No OAuth headaches for Gmail
  • Config in Google Sheets (Paige can edit)
  • Difficult to test — no local dev loop
  • No CI/CD — manual deploys via clasp
  • Harder to debug — limited logging
  • Slower iteration — edit in browser IDE
  • 6-minute execution timeout
  • Quota limits on UrlFetchApp calls
Python + Railway
Full control, ~$5–10/mo
  • Full test harness — deterministic mocks, CI
  • Structured JSONL logging — every decision auditable
  • Version control + GitHub Actions deploy
  • Fast iteration — local dev, push to deploy
  • No execution timeout
  • Portable — can move off Railway anytime
  • ~$5–10/month Railway hosting
  • OAuth for server-side Gmail is more complex
  • Rate limit: 10,000 Gmail API calls/day
  • Token refresh logic required
  • Monitoring / alerting responsibility

Risk Profile

Low Risk

Archive / Draft / Flag

Safe by design — human reviews drafts before anything sends. Misclassification means an email gets flagged that shouldn't, or archived that should've been seen. Paige can recover by checking the daily summary. These cover 8 of 10 categories.

Medium Risk

Auto-Reply to Known Clients

Wrong tone could be embarrassing. Mitigation: start in draft-only mode, graduate to auto-send only for high-confidence classifications, require Paige's tone guide as input, A/B test reply quality before enabling.

High Risk

False Negative on Urgent

If the system misclassifies an urgent email as a newsletter and archives it, Paige misses a critical message. Mitigation: daily summary email of everything processed, urgency detection threshold tuned conservatively, dry-run mode against real inbox first.

5 Decisions Paige Needs to Make

1

Runtime: Apps Script or Python?

Zero-infra simplicity (but harder to test) vs. full control (but ~$5–10/mo hosting). See tradeoff comparison above.

2

Tone Guide for Auto-Replies

What style/voice should AI-generated replies use? Need examples of Paige's actual replies to clients — 5–10 representative emails.

3

Auto-Send Threshold

Which categories are safe to auto-send (after testing) vs. always stay as drafts? Start conservative — only client inquiries after 2-week dry-run.

4

Sender Whitelist

Which senders/domains get auto-replies? Client domains? Internal TBG team? Vendors? Start with a small, known-safe list and expand.

5

Escalation Channel

When something is flagged urgent, how should Paige be notified? Email forward? Slack DM? SMS? Email is simplest to start.

Implementation Plan — ~11 Hours

1
Foundation
~2 hours
OAuth, Gemini API helper, fetch loop, pre-filter, structured logging system built first.
2
Triage Engine
~3 hours
All 5 rule engines, Gemini classification prompt, decision function, config sheets.
3
Actions
~2 hours
Auto-reply generation, draft creation, flag/archive/forward. All human-reviewable.
4
Test Harness
~3 hours
15+ email fixtures, deterministic Gemini mocks, dry-run mode, automated test suite.
5
Deploy
~1 hour
Install trigger, daily summary sheet, graduate to production. Draft-only for first 48h.
Non-Negotiable Requirements (4 items)
1. Structured JSONL Logging. Every decision fully traceable — email ID, sender, classification, confidence, action taken, latency. No "black box" processing.

2. Automated Test Harness. 15+ canned email fixtures with deterministic Gemini mocks. Single command to run all tests. Must pass before any deploy.

3. Dry-Run Mode. Process real inbox but never send. All writes become drafts labeled "AI-DryRun." Paige reviews before enabling live mode.

4. Gradual Rollout. Start draft-only → enable auto-send for 1–2 safe categories → expand weekly as confidence builds. No big-bang activation.
Bottom line: This is a ~11-hour build with real moving parts — 5 rule engines, 2 LLM calls per email, 10-category decision matrix, and a test harness that proves it works before it touches a real inbox. The two biggest variables are runtime choice (Apps Script simplicity vs. Python control) and Paige's availability to define tone, senders, and thresholds. Once those 5 decisions are made, build can start immediately. The non-negotiables (logging, testing, dry-run, gradual rollout) ensure we never send a bad email.