--- name: gmail description: Gmail read access via direct Python API - search, check unread, detect urgent emails allowed-tools: - Bash --- # Gmail Skill Access Gmail via direct Python API calls. Uses OAuth credentials at `~/.gmail-mcp/`. ## Delegated Operations (Recommended) Use the tiered delegation helper for cost-efficient operations. Uses Claude CLI with your subscription (no API key needed): ```bash GMAIL_PY=~/.claude/mcp/gmail/venv/bin/python HELPER=~/.claude/mcp/delegation/gmail_delegate.py # Haiku tier - list unread (no LLM call, just fetches) $GMAIL_PY $HELPER check-unread --days 7 # Sonnet tier - summarize emails (spawns claude --model sonnet) $GMAIL_PY $HELPER summarize --query "from:github.com" # Sonnet tier - triage urgent (spawns claude --model sonnet) $GMAIL_PY $HELPER urgent ``` ### When to Use Each Tier | Request Type | Command | Model | |--------------|---------|-------| | "Check my email" | `check-unread` | Haiku | | "How many unread?" | `check-unread` | Haiku | | "Summarize X" | `summarize --query "X"` | Sonnet | | "What's urgent?" | `urgent` | Sonnet | | "What should I prioritize?" | (PA direct) | Opus | ## Usage For any Gmail request, use Bash to run the Python helper: ```bash GMAIL_CREDENTIALS_PATH=~/.gmail-mcp/credentials.json ~/.claude/mcp/gmail/venv/bin/python << 'EOF' from gmail_mcp.utils.GCP.gmail_auth import get_gmail_service from collections import defaultdict service = get_gmail_service() # Your query here results = service.users().messages().list(userId='me', q='is:unread newer_than:3d', maxResults=25).execute() messages = results.get('messages', []) for msg in messages: detail = service.users().messages().get(userId='me', id=msg['id'], format='metadata', metadataHeaders=['From', 'Subject', 'Date']).execute() headers = {h['name']: h['value'] for h in detail['payload']['headers']} print(f"From: {headers.get('From', 'Unknown')}") print(f"Subject: {headers.get('Subject', '(no subject)')}") print(f"Date: {headers.get('Date', 'Unknown')}") print("---") EOF ``` ## Query Patterns | Request | Gmail Query | |---------|-------------| | Unread | `is:unread` | | Last N days | `newer_than:Nd` | | From sender | `from:email@example.com` | | With attachments | `has:attachment` | | Important | `is:important` | | Urgent keywords | `subject:(urgent OR asap OR "action required")` | ## Common Tasks ### Check unread (grouped by sender) ```bash GMAIL_CREDENTIALS_PATH=~/.gmail-mcp/credentials.json ~/.claude/mcp/gmail/venv/bin/python << 'EOF' from gmail_mcp.utils.GCP.gmail_auth import get_gmail_service from collections import defaultdict service = get_gmail_service() results = service.users().messages().list(userId='me', q='is:unread newer_than:7d', maxResults=25).execute() by_sender = defaultdict(list) for msg in results.get('messages', []): detail = service.users().messages().get(userId='me', id=msg['id'], format='metadata', metadataHeaders=['From', 'Subject']).execute() headers = {h['name']: h['value'] for h in detail['payload']['headers']} sender = headers.get('From', 'Unknown').split('<')[0].strip().strip('"') by_sender[sender].append(headers.get('Subject', '(no subject)')[:50]) for sender, subjects in sorted(by_sender.items(), key=lambda x: -len(x[1])): print(f"* {sender} ({len(subjects)})") for s in subjects[:2]: print(f" - {s}") if len(subjects) > 2: print(f" - ...+{len(subjects)-2} more") EOF ``` ### Check urgent ```bash GMAIL_CREDENTIALS_PATH=~/.gmail-mcp/credentials.json ~/.claude/mcp/gmail/venv/bin/python << 'EOF' from gmail_mcp.utils.GCP.gmail_auth import get_gmail_service service = get_gmail_service() results = service.users().messages().list(userId='me', q='is:unread newer_than:3d (subject:urgent OR subject:asap OR subject:"action required" OR is:important)', maxResults=15).execute() for msg in results.get('messages', []): detail = service.users().messages().get(userId='me', id=msg['id'], format='metadata', metadataHeaders=['From', 'Subject', 'Date']).execute() headers = {h['name']: h['value'] for h in detail['payload']['headers']} print(f"From: {headers.get('From', 'Unknown')}") print(f"Subject: {headers.get('Subject', '(no subject)')}") print(f"Date: {headers.get('Date', 'Unknown')}") print("---") EOF ``` ## Model Selection Gmail operations use tiered delegation per `model-policy.json`: | Model | Use For | Examples | |-------|---------|----------| | **Haiku** | Fetch, count, list, simple search | "How many unread?", "List from X" | | **Sonnet** | Summarize, categorize, extract | "Summarize this email", "Group by topic" | | **Opus** | Prioritize, analyze, cross-reference | "What should I handle first?" | ### Delegation Pattern When invoking gmail operations, the PA should: 1. **Classify the request** — Is it fetch-only, summarization, or analysis? 2. **Delegate appropriately**: - Haiku: API calls + simple formatting - Sonnet: API calls + content understanding - Opus: Only for strategic reasoning 3. **Escalate if needed** — If lower tier can't handle it, escalate ### Implementation Note Until Task tool delegation is available, the PA executes gmail operations directly but should mentally "account" for which tier the work belongs to. This policy enables future cost optimization when subagent spawning is implemented. ## Policy - Read-only operations only - Summarize results (don't dump raw content) - Report metadata, not full body unless asked - Start with lowest capable model tier - Escalate only when task complexity requires