Add Gmail Filter CoWork Guide (methodology reference)
This commit is contained in:
@@ -0,0 +1,368 @@
|
|||||||
|
# Building a Gmail Classification Pipeline with Claude CoWork
|
||||||
|
|
||||||
|
**A practical guide for organizing your inbox with AI-assisted filters**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What This Guide Covers
|
||||||
|
|
||||||
|
This guide walks through the full process of building a systematic Gmail classification system using Claude CoWork. By the end, every email arriving in your inbox will be automatically labeled by sender, type, and purpose — making triage, search, and AI processing dramatically faster.
|
||||||
|
|
||||||
|
This is not about a one-time cleanup. It's about building a durable, extensible system that improves over time.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Why Filters, Not LLMs
|
||||||
|
|
||||||
|
An AI tool can absolutely classify every email in your inbox. It can read each message, reason about its content, and apply a label. The problem is that this is extraordinarily expensive in both time and tokens — and it happens after the fact, not at the moment of receipt.
|
||||||
|
|
||||||
|
Gmail's native filter system is free, instant, and runs 24 hours a day on Google's infrastructure without any involvement from you or any AI tool. A filter created once will correctly classify every matching email for years with zero ongoing cost and zero risk of hallucination. It doesn't get tired, doesn't lose context, and doesn't charge per token.
|
||||||
|
|
||||||
|
The goal of this process is to transfer as much classification work as possible to Gmail filters first, then to Google Apps Script for cases filters can't handle, and only then to an LLM for the genuinely hard cases that require semantic reasoning. This creates a tiered system where:
|
||||||
|
|
||||||
|
| Tier | Tool | Cost | Speed | What it handles |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| 1 | Gmail Filters | Free | Instant, at receipt | Sender domain, subject keywords, participant patterns |
|
||||||
|
| 2 | Apps Script | Free | Near-real-time (hourly) | Attachment filename/type, body keyword combinations |
|
||||||
|
| 3 | LLM | Per token | On-demand | Semantic content, ambiguous cases, summaries, routing decisions |
|
||||||
|
|
||||||
|
The payoff of a well-built filter layer isn't just labeling — it's that every downstream AI workflow becomes dramatically more efficient. Instead of having an AI read every email in your inbox looking for invoices, it can simply process `label:Finance/Invoices-Vendor-Payable`. The signal is already there. The expensive reasoning work gets applied only to the emails that actually need it.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- **Claude CoWork** with Google Workspace MCP connected
|
||||||
|
- Gmail account (Google Workspace or personal)
|
||||||
|
- About 2–4 hours for the initial setup session
|
||||||
|
- Basic familiarity with Gmail labels
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 1 — Start With Your Existing Labels
|
||||||
|
|
||||||
|
Most people who have used Gmail for years already have a label structure — even if it's inconsistent, sparse, or partially applied. This is one of the most valuable inputs to the process. Your existing labels represent organic organizational decisions made over time. They tell you what categories actually matter to you in practice, not just in theory.
|
||||||
|
|
||||||
|
**The architecting process:**
|
||||||
|
|
||||||
|
1. **Audit what exists.** Have Claude pull your full label list and inventory every label, how many messages it contains, and how recently it was used. Labels with significant message counts represent real categories worth preserving.
|
||||||
|
|
||||||
|
2. **Expand or contract.** Some labels will be too broad (everything lumped under "Vendors"), some too narrow (a label for a single sender that should be a sublabel). Decide which to split, merge, rename, or retire.
|
||||||
|
|
||||||
|
3. **Set bylaws.** For each label, define precisely what belongs in it — and what doesn't. This is the most important architectural work. A label without a clear definition will drift over time and lose its value as a signal.
|
||||||
|
|
||||||
|
4. **Build filters to enforce consistency.** Once the taxonomy is defined, filters make it automatic and retroactive. Every new email is classified instantly on arrival. You can also backfill existing mail to bring historical threads in line with the new structure.
|
||||||
|
|
||||||
|
The goal is to turn an ad-hoc manual labeling habit into a system with rules — so the labels stay meaningful without ongoing effort.
|
||||||
|
|
||||||
|
**The daily payoff:**
|
||||||
|
|
||||||
|
Once filters are running, emails arrive pre-labeled. When you open your inbox to review, you can read a message and archive it immediately — no separate step to apply a label before filing it away. For high-volume inboxes, this eliminates a significant fraction of the manual overhead of email triage. The label is already there; you just decide whether to act or archive.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 2 — Design Your Label Taxonomy
|
||||||
|
|
||||||
|
With your existing labels audited and your bylaws drafted, formalize the taxonomy before deploying any filters. A bad taxonomy is expensive to undo once filters are live.
|
||||||
|
|
||||||
|
**Principles:**
|
||||||
|
|
||||||
|
- **Hierarchical**: Use parent/child labels (`Finance/AMEX`, not just `AMEX`)
|
||||||
|
- **Mutually exclusive at the top level**: Each top-level label represents a distinct domain of your life/work
|
||||||
|
- **Stable**: Labels should be meaningful in 2 years, not just today
|
||||||
|
- **Not too deep**: 2–3 levels is usually enough
|
||||||
|
- **Bylaw-driven**: Every label should have a clear definition of what belongs in it
|
||||||
|
|
||||||
|
**Recommended top-level categories for a business owner:**
|
||||||
|
|
||||||
|
```
|
||||||
|
Finance/
|
||||||
|
AMEX, Ramp, Invoices, Receipts, Purchase-Orders
|
||||||
|
Operations/
|
||||||
|
Benefits, Insurance, HR-Payroll, Legal, Facilities
|
||||||
|
Vendors/
|
||||||
|
Hardware, Software, Shipping, Services
|
||||||
|
Clients/
|
||||||
|
Resellers/, Transit/, Corporate/
|
||||||
|
Development/
|
||||||
|
GitHub, GitLab, Odoo
|
||||||
|
Marketing/
|
||||||
|
Trade Shows/, Events/
|
||||||
|
Sales/
|
||||||
|
RFPs, Quotes, Prospects
|
||||||
|
Travel/
|
||||||
|
Air, Hotel, Car
|
||||||
|
Personal/
|
||||||
|
Notifications/
|
||||||
|
System, Shipping, Order-Confirmations
|
||||||
|
Support/
|
||||||
|
Documentation/
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 3 — Build the Master Workbook
|
||||||
|
|
||||||
|
Create an Excel or Google Sheet to track every rule before deploying anything. This is your source of truth.
|
||||||
|
|
||||||
|
**Required columns:**
|
||||||
|
|
||||||
|
| Column | Purpose |
|
||||||
|
|---|---|
|
||||||
|
| `rule_id` | Unique ID (e.g., `GF-FINANCE-AMEX`) |
|
||||||
|
| `enabled` | TRUE/FALSE |
|
||||||
|
| `rule_name` | Human-readable name |
|
||||||
|
| `from_domain` | Sender domain(s) |
|
||||||
|
| `subject_contains` | Subject keyword filter (optional) |
|
||||||
|
| `base_label` | Target Gmail label |
|
||||||
|
| `archive` | Should the filter skip inbox? |
|
||||||
|
| `mark_read` | Auto-mark read? (use sparingly) |
|
||||||
|
| `deployability` | `gmail_filter_safe` or `apps_script_needed` |
|
||||||
|
| `notes` | Decisions, edge cases, exceptions |
|
||||||
|
|
||||||
|
**Deployability rule:**
|
||||||
|
- `gmail_filter_safe` = anything expressible in Gmail's search syntax (from:, to:, subject:, OR, AND, -)
|
||||||
|
- `apps_script_needed` = attachment filename/extension inspection only (e.g., `.PDF`, `.STP`, keyword inside attachment)
|
||||||
|
|
||||||
|
> **Common mistake:** Multi-domain OR rules don't require Apps Script. Gmail's query field handles `(from:domain1.com OR from:domain2.com OR from:domain3.com)` natively.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 4 — Classify Your Email
|
||||||
|
|
||||||
|
Before building rules, sample your inbox to understand what's actually arriving.
|
||||||
|
|
||||||
|
Ask Claude to:
|
||||||
|
|
||||||
|
```
|
||||||
|
Search my Gmail for the 50 most recent unique sender domains
|
||||||
|
and group them by likely category.
|
||||||
|
```
|
||||||
|
|
||||||
|
Then for each meaningful sender, add a row to your workbook with the appropriate label, domain pattern, and any subject qualifiers needed to avoid false positives.
|
||||||
|
|
||||||
|
**Watch out for:**
|
||||||
|
- Vendors who send from multiple domains (e.g., marketing vs. transactional)
|
||||||
|
- Services that route through shared platforms (e.g., SendGrid, Mailchimp, Amazon SES)
|
||||||
|
- Internal alias addresses that appear as external senders
|
||||||
|
- Google Groups that mask the real sender's domain
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Cost Optimization — Offloading Discovery Work
|
||||||
|
|
||||||
|
The classification discovery phase (scanning your inbox, identifying sender patterns, proposing candidate rules) is repetitive and token-intensive but not architecturally complex. It doesn't require Claude's full reasoning capability. You can reduce cost significantly by offloading the analysis work to a cheaper or flat-rate tool while keeping Claude as the organizer, architect, and executor.
|
||||||
|
|
||||||
|
**Recommended division of labor:**
|
||||||
|
|
||||||
|
| Role | Tool | What it does |
|
||||||
|
|---|---|---|
|
||||||
|
| **Analyst** | ChatGPT Team, Gemini, or local LLM | Walks inbox directly, identifies sender patterns, drafts candidate rules in workbook format |
|
||||||
|
| **Architect / Executor** | Claude CoWork | Reviews analyst output, makes final decisions, resolves edge cases, deploys filters, writes Apps Script, maintains the master workbook |
|
||||||
|
|
||||||
|
**Tool options for the analyst role:**
|
||||||
|
|
||||||
|
- **ChatGPT Team** (flat-rate subscription): ChatGPT has a capable native Gmail skill that can directly read and walk your full Gmail structure — no data export required. Feed it your taxonomy and ask it to identify unclassified senders and propose rules. Flat-rate pricing means no per-token anxiety during a long discovery run across hundreds of senders.
|
||||||
|
|
||||||
|
- **Gemini** (Google account): As a Google product, Gemini has native Gmail integration and can directly query your inbox. Its depth of Gmail access is similar in concept but the practical limits of its analysis capability are less tested at scale. Worth evaluating for your use case given it's included with Google Workspace.
|
||||||
|
|
||||||
|
- **Local LLM (Gemma, Qwen, Mistral via Ollama or LM Studio)**: A local model can be connected to the same Google Workspace MCP that Claude uses, giving it equivalent Gmail read access via an orchestrator tool (such as n8n or a custom MCP client). Speed and reasoning quality will be lower than a hosted model, but the marginal cost is zero. Best suited for structured, repetitive classification tasks where the prompt is well-defined and the output format is rigid.
|
||||||
|
|
||||||
|
**How the handoff works:**
|
||||||
|
|
||||||
|
1. Assign the analyst tool your taxonomy and a prompt such as:
|
||||||
|
```
|
||||||
|
Review my Gmail inbox. For each unique sender domain that doesn't already
|
||||||
|
match a label in this taxonomy, propose a rule. Output as a table:
|
||||||
|
domain, suggested_label, filter_type (from-only or participant),
|
||||||
|
subject_qualifier (if needed), notes.
|
||||||
|
```
|
||||||
|
2. The analyst walks Gmail directly and returns a candidate rule table
|
||||||
|
3. Paste the output into your master workbook as pending candidates
|
||||||
|
4. Bring the workbook to Claude CoWork for review, edge case resolution, and deployment
|
||||||
|
|
||||||
|
**What stays with Claude CoWork — always:**
|
||||||
|
- Final review and approval of all rules before any Gmail mutation
|
||||||
|
- All Gmail mutations (creating labels, creating filters) — never delegate execution to another tool
|
||||||
|
- Apps Script authoring and debugging
|
||||||
|
- Master workbook maintenance and documentation
|
||||||
|
- Architectural decisions: taxonomy design, bylaw definition, edge cases, exception handling
|
||||||
|
|
||||||
|
This hybrid approach can cut the token cost of the discovery phase by 80–90% while keeping all high-stakes execution in Claude's hands.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 5 — Deploy Gmail Filters via CoWork
|
||||||
|
|
||||||
|
With your workbook ready, have Claude deploy filters tree by tree — one top-level category at a time. Review each batch before approving.
|
||||||
|
|
||||||
|
**Critical safety rules:**
|
||||||
|
- Never approve bulk mutations without reviewing the rule list first
|
||||||
|
- Deploy one label tree at a time, not everything at once
|
||||||
|
- Keep mark-read off by default — enable only where truly noise-free
|
||||||
|
|
||||||
|
**How CoWork creates a filter:**
|
||||||
|
|
||||||
|
```
|
||||||
|
Create a Gmail filter:
|
||||||
|
- Criteria: from:(domain.com) OR to:(domain.com) OR cc:(domain.com)
|
||||||
|
- Action: add label "Vendors/Shipping"
|
||||||
|
```
|
||||||
|
|
||||||
|
For multi-label rules, create one filter per label (Gmail's API has rate limits on parallel multi-label creation).
|
||||||
|
|
||||||
|
**Participant domain pattern** (best for business relationships):
|
||||||
|
```
|
||||||
|
from:(domain.com) OR to:(domain.com) OR cc:(domain.com)
|
||||||
|
```
|
||||||
|
|
||||||
|
**From-only pattern** (best for inbound-only services):
|
||||||
|
```
|
||||||
|
from:(domain.com)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Subject qualifier** (to avoid over-labeling broad senders like google.com):
|
||||||
|
```
|
||||||
|
from:(google.com) subject:("Google Workspace" OR "invoice is available")
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 6 — Handle Attachment-Based Rules with Apps Script
|
||||||
|
|
||||||
|
Gmail's native filter system cannot inspect attachment filenames or file contents. For rules like "label this if it has a .STP file attached" or "label this if it has a PDF and says 'diagram'", you need a Google Apps Script.
|
||||||
|
|
||||||
|
**Basic approach:**
|
||||||
|
|
||||||
|
1. Open [script.google.com](https://script.google.com) and create a new project
|
||||||
|
2. Paste the scanner function (see below)
|
||||||
|
3. Run once manually to authorize Gmail scope
|
||||||
|
4. Add a time-driven trigger (every 1 hour is typical)
|
||||||
|
|
||||||
|
**Minimal scanner template:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
function scanAttachments() {
|
||||||
|
const TARGET_LABEL = getLabel_("Your/Label/Here");
|
||||||
|
const SCAN_GUARD = getLabel_("Z-Archive/ScanGuard"); // hidden guard label
|
||||||
|
|
||||||
|
const threads = GmailApp.search(
|
||||||
|
'newer_than:14d has:attachment -in:trash -in:spam -label:"Z-Archive/ScanGuard"',
|
||||||
|
0, 50
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const thread of threads) {
|
||||||
|
let matched = false;
|
||||||
|
for (const message of thread.getMessages()) {
|
||||||
|
const text = `${message.getSubject()}\n${message.getPlainBody()}`;
|
||||||
|
for (const att of message.getAttachments({ includeInlineImages: false })) {
|
||||||
|
const name = att.getName().toLowerCase();
|
||||||
|
const mime = att.getContentType().toLowerCase();
|
||||||
|
// Add your detection logic here:
|
||||||
|
if (/\.(stp|step)$/.test(name)) matched = true;
|
||||||
|
if (/diagram/i.test(text) && mime === "application/pdf") matched = true;
|
||||||
|
if (/inv[-_]\d+/.test(name)) matched = true; // vendor invoice
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (matched) thread.addLabel(TARGET_LABEL);
|
||||||
|
thread.addLabel(SCAN_GUARD); // always mark scanned
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLabel_(name) {
|
||||||
|
const label = GmailApp.getUserLabelByName(name);
|
||||||
|
if (!label) throw new Error(`Label not found: "${name}"`);
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Key points:**
|
||||||
|
- The script reads attachment filename (`getName()`) and MIME type (`getContentType()`) — it cannot read inside a PDF
|
||||||
|
- The guard label (`Z-Archive/ScanGuard`) prevents re-scanning and should be set to hidden
|
||||||
|
- "diagram" or other keywords are matched against subject + body text, not attachment content
|
||||||
|
- Stars applied by Apps Script do NOT trigger Gmail Studio flows — those only fire at receipt time
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## The Star and Studio Flows
|
||||||
|
|
||||||
|
Gmail Studio flows are Google's native automation layer that runs immediately after the filter step — at the moment of email receipt, before the message ever lands in your inbox. This makes them uniquely powerful for taking actions that require understanding the content of an email, not just its sender or subject. Studio can evaluate context, make decisions, and trigger downstream Google actions: creating Tasks, filing attachments to Drive folders, forwarding to specific people, or invoking other Google Workspace automations.
|
||||||
|
|
||||||
|
**However, Studio flows are limited in number and carry a cost. They must be used very sparingly.**
|
||||||
|
|
||||||
|
Do not treat Studio as a general-purpose automation layer for all classified mail. Reserve it for cases where a filter alone cannot make the decision — specifically, where the action depends on the content or context of the email rather than just who sent it.
|
||||||
|
|
||||||
|
### The Filter → Star → Studio Pipeline
|
||||||
|
|
||||||
|
The only durable signal that can be shared between Gmail filters and Studio is the **star**. Gmail filters can apply a star to a message, and Studio can use the starred state as its trigger condition. This creates a clean handoff:
|
||||||
|
|
||||||
|
1. A Gmail filter matches an email (by sender, subject, or pattern) and applies both a label and a star
|
||||||
|
2. Studio detects the star at receipt time and runs its flow — evaluating content, making decisions, triggering actions
|
||||||
|
3. Studio removes the star when it finishes, freeing it for personal use
|
||||||
|
|
||||||
|
This pipeline works because filters and Studio run at different points in the receipt sequence — filters fire first, Studio fires immediately after. There is no race condition under normal operation.
|
||||||
|
|
||||||
|
### Cautions
|
||||||
|
|
||||||
|
- **Broken flows leave stars in place.** If a Studio flow fails partway through, the star may not be removed. If you also use stars as a personal organization signal, this can create confusion. Design flows to be idempotent where possible, and monitor for stale stars.
|
||||||
|
- **Avoid stars entirely if you can.** If you don't rely on stars for personal organization and your Studio flows are reliable, this is a non-issue. But if stars carry meaning for you, consider the tradeoff carefully before building star-triggered automations.
|
||||||
|
- **Apps Script cannot reliably drive Studio.** Apps Script runs on a schedule (hourly, at best), not at receipt time. By the time Apps Script stars a message, the receipt event is gone and Studio will not fire. Building a true near-real-time Apps Script trigger requires the Gmail `watch()` API with Google Cloud Pub/Sub — a significantly more complex architecture that is currently untested at production scale for this purpose.
|
||||||
|
|
||||||
|
### What Belongs in Studio vs. Filters
|
||||||
|
|
||||||
|
| Belongs in a Filter | Belongs in Studio |
|
||||||
|
|---|---|
|
||||||
|
| Sender domain → label | Read email body → decide label or action |
|
||||||
|
| Subject keyword → label | Create a Google Task from email content |
|
||||||
|
| Participant pattern → label | File attachment to a specific Drive folder |
|
||||||
|
| Star to signal Studio | Forward with context-aware routing |
|
||||||
|
| Mark as read (noise) | Classify ambiguous content before labeling |
|
||||||
|
|
||||||
|
Designing effective Studio flows — including how to use Claude to help build and test them — is a separate topic not covered in this guide.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 7 — Continuous Improvement with "! Rule Needed"
|
||||||
|
|
||||||
|
Create a Gmail label called `! Rule Needed`. Whenever you notice an email that should be automatically classified but isn't, apply this label to it.
|
||||||
|
|
||||||
|
Periodically (weekly or monthly), review the label with Claude:
|
||||||
|
|
||||||
|
```
|
||||||
|
Pull all messages labeled "! Rule Needed" and identify patterns
|
||||||
|
we could turn into Gmail filters or Apps Script rules.
|
||||||
|
```
|
||||||
|
|
||||||
|
For each candidate:
|
||||||
|
1. Identify the sender domain and pattern
|
||||||
|
2. Decide: gmail_filter_safe or apps_script_needed?
|
||||||
|
3. Add to the master workbook
|
||||||
|
4. Deploy and remove the `! Rule Needed` label from processed threads
|
||||||
|
|
||||||
|
This creates a continuous improvement loop — your system gets smarter over time without requiring a large upfront effort to catch everything.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tips and Gotchas
|
||||||
|
|
||||||
|
**BidPrime-style routing:** Some services send mail through Google Groups or shared platforms. The From: address in Gmail won't match the vendor's domain. Check the raw message headers to find the actual sender. In Gmail: open message → three dots → "Show original."
|
||||||
|
|
||||||
|
**Rate limits:** Gmail's API rejects creating many filters in parallel with multiple labels each. Create filters sequentially, one label per filter.
|
||||||
|
|
||||||
|
**Mark-read:** Use sparingly. Once enabled on a filter, you won't notice if something important slips through. Only mark-read for truly low-signal streams (loyalty programs, automated receipts you never need to act on).
|
||||||
|
|
||||||
|
**Domain coverage:** Many vendors use separate transactional domains (e.g., `notifications.vendor.com`, `mail.vendor.com`). Check a few actual message headers before assuming all mail comes from the main domain.
|
||||||
|
|
||||||
|
**Label naming:** Choose names you'll still understand in 2 years. Avoid abbreviations that only make sense today.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What You'll End Up With
|
||||||
|
|
||||||
|
- Every email automatically labeled within seconds of arrival
|
||||||
|
- A master workbook that documents every decision made
|
||||||
|
- An Apps Script that catches document types Gmail can't filter natively
|
||||||
|
- A `! Rule Needed` process that keeps the system improving
|
||||||
|
- A foundation for AI-powered inbox triage (Claude can process labeled mail in batches)
|
||||||
|
|
||||||
|
The upfront investment is 2–4 hours. The payoff is an inbox where nothing gets lost and everything is findable.
|
||||||
Reference in New Issue
Block a user