Manage Gmail email — drafting, sending, organizing, filters, vacation replies, and inbox analysis

MITAuto-check passedProductivity & Automation

Install Gmail

skills CLI
$ npx skills add vellum-ai/vellum-assistant --skill gmail -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install vellum-ai/vellum-assistant gmail --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/vellum-ai/vellum-assistant.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/gmail .claude/skills/gmail && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
gmail
GitHub stars
1.4k
Token cost
~8.3k tokens
SKILL.md length
3,489 words
Files
18 (incl. scripts, assets)
Skills in repo
108
Repo updated
First seen
Licence
MIT

At a glance

Manage Gmail email — drafting, sending, organizing, filters, vacation replies, and inbox analysis

  • Works in 2 steps: Check connection health first. Run… → If no connection is found or the status…
  • Tasks that involve Email management
  • SKILL.md covers Script Reference, Email Routing Priority, Connection Setup and Error Recovery, plus 10 more sections
  • Runs TypeScript scripts from its folder; calls bun

What it does

Gmail is an agent skill from vellum-ai/vellum-assistant. Manage Gmail email — drafting, sending, organizing, filters, vacation replies, and inbox analysis

Its SKILL.md is about 8.3k tokens, which your agent loads only when the skill is triggered. The skill folder holds 20 other files, including scripts and assets (for example `scripts/gmail-archive.ts`, `scripts/gmail-auto-filters.ts` and `scripts/gmail-commit.ts`). Compatibility notes: Designed for Vellum personal assistants

It sits in Productivity & Automation, covering Email management. It works with Gmail. The repository describes itself as: An AI Assistant that’s easy to setup, does your work 24/7, knows your preferences and gets better over time. The licence is MIT.

When your agent uses it

  • Tasks that involve Email management

Example prompts

  • “/gmail”

Requirements

  • Node.js
  • Compatibility (from SKILL.md): Designed for Vellum personal assistants

Workflow steps

2 steps, taken from the first numbered list in SKILL.md.

  1. Check connection health first. Run assistant oauth status google. This checks whether the user's Google account is connected and the token…
  2. If no connection is found or the status check fails: Load the vellum-oauth-integrations skill. The skill will evaluate whether managed or…

What it can do on your machine

Read from SKILL.md and the folder at commit c92ead1. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Ships 16 files in scripts/ (TypeScript), which the agent can run.

    Shell commands in SKILL.md call:

    • bun

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

  • Compatibility

    Designed for Vellum personal assistants

    From compatibility in the SKILL.md frontmatter.

Context cost

Gmail loads about 8.3k tokens when it runs. Until then it costs about 26 tokens; SKILL.md has 3,489 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~26
When it runs · the whole SKILL.md, loaded when a task matches
~8.3k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); the scripts in this folder are not scanned.

SKILL.md

The full file from vellum-ai/vellum-assistant at commit c92ead1, republished under its MIT licence (© vellum-ai). 3,489 words, ~8,346 tokens.

Download SKILL.mdSave it as .claude/skills/gmail/SKILL.md (or your agent's skills folder). This skill also uses 17 other files; get the full folder from GitHub.
name
gmail
description
Manage Gmail email — drafting, sending, organizing, filters, vacation replies, and inbox analysis
compatibility
Designed for Vellum personal assistants
metadata.icon
assets/icon.svg
metadata.emoji
📨

This skill provides Gmail-specific operations beyond the shared messaging skill. For cross-platform messaging (send, read, search, reply), use the messaging skill. Gmail operations depend on the messaging skill's provider infrastructure - load messaging first if Gmail is not yet connected.

Script Reference

All operations use CLI scripts that return JSON:

  • Success: { "ok": true, "data": ... }
  • Failure: { "ok": false, "error": "..." }
ScriptOperationDescription
gmail-email.tsdraftCreate email drafts in the Drafts folder (including reply drafts)
gmail-email.tssend-draftSend an existing draft (requires explicit user confirmation)
gmail-email.tsforwardCreate forward drafts, preserving attachments
gmail-email.tstrashMove messages to Trash
gmail-manage.tslabelAdd or remove labels on messages
gmail-manage.tsfollow-upTrack/untrack messages for follow-up using a dedicated "Follow-up" label
gmail-manage.tsattachmentsList and download email attachments
gmail-manage.tsfiltersCreate, list, and delete Gmail filters
gmail-manage.tsvacationGet, enable, or disable the vacation auto-responder
gmail-manage.tsunsubscribeUnsubscribe from mailing lists (requires explicit user confirmation)
gmail-scan.tssender-digestScan inbox and group messages by sender for declutter workflows
gmail-scan.tsoutreach-scanIdentify cold outreach senders (no List-Unsubscribe header)
gmail-archive.tsarchiveArchive messages (single, batch message_ids, cache_key+sender-emails, query)
gmail-archive.tsarchive --dry-runPreview what would be archived without executing (writes staged ops to log)
gmail-archive.tsarchive --resumeResume an interrupted archive run from its last checkpoint
gmail-commit.tscommitExecute all staged ops from a dry-run
gmail-commit.tscancelDelete a run log without executing anything
gmail-runs.tslistList recent operation runs with status summaries
gmail-runs.tsinspectShow detailed log entries for a specific run
gmail-runs.tspruneDelete operation logs older than 30 days
gmail-reverse.ts--run-idReverse all committed ops in a run (un-archive, un-label, un-trash)
gmail-reverse.ts--run-id --threadReverse a specific message within a committed run
gmail-prefs.tslistList blocklist and safelist preferences
gmail-prefs.tsadd-blocklistAdd sender emails to the blocklist
gmail-prefs.tsadd-safelistAdd sender emails to the safelist
gmail-prefs.tsremove-blocklistRemove sender emails from the blocklist
gmail-prefs.tsremove-safelistRemove sender emails from the safelist
gmail-prefs.tsget-management-configGet inbox management config (stage, interrupt threshold, last run)
gmail-prefs.tsset-management-configUpdate inbox management config (--stage, --interrupt-threshold, --last-run)
Email Operations
bash
# Draft an email
bun run scripts/gmail-email.ts draft --to "user@example.com" --subject "Hello" --body "Message body"

# Draft a reply in a thread
bun run scripts/gmail-email.ts draft --to "user@example.com" --subject "Re: Hello" --body "Reply body" --thread-id "18f..." --in-reply-to "18f..."

# Send an existing draft (REQUIRES user confirmation before execution)
bun run scripts/gmail-email.ts send-draft --draft-id "r123..."

# Forward a message
bun run scripts/gmail-email.ts forward --message-id "18f..." --to "recipient@example.com" --text "FYI"

# Trash a message
bun run scripts/gmail-email.ts trash --message-id "18f..."
Management Operations
bash
# Label - add a label to a message
bun run scripts/gmail-manage.ts label --message-id "18f..." --add-labels "Work,Important"

# Follow-up - track a message for follow-up
bun run scripts/gmail-manage.ts follow-up --action track --message-id "18f..."

# Attachments - list attachments on a message
bun run scripts/gmail-manage.ts attachments --action list --message-id "18f..."

# Attachments - download a specific attachment
bun run scripts/gmail-manage.ts attachments --action download --message-id "18f..." --attachment-id "ANGj..." --filename "report.pdf"

# Filters - create a Gmail filter
bun run scripts/gmail-manage.ts filters --action create --from "newsletter@example.com" --remove-labels "INBOX"

# Vacation - enable auto-responder
bun run scripts/gmail-manage.ts vacation --action enable --message "I'm out of office until Monday"

# Unsubscribe from a mailing list (REQUIRES user confirmation before execution)
bun run scripts/gmail-manage.ts unsubscribe --message-id "18f..."
Scan Operations
bash
# Sender digest - scan inbox grouped by sender
bun run scripts/gmail-scan.ts sender-digest [--query "in:inbox category:promotions newer_than:90d"]

# Outreach scan - identify cold outreach senders
bun run scripts/gmail-scan.ts outreach-scan [--time-range "90d"]

Scan scripts store message IDs in the assistant's cache and return a lightweight summary with a cache_key. This keeps thousands of message IDs out of the conversation context. To retrieve cached message IDs for a specific sender:

bash
assistant cache get <cache_key> --json
# Returns: { "ok": true, "data": { "sender@example.com": ["msgId1", "msgId2", ...], ... } }
Archive Operations
bash
# Archive using cache_key + sender emails (preferred for declutter workflows)
bun run scripts/gmail-archive.ts archive --cache-key "scan:abc123" --sender-emails "news@example.com,promo@example.com"

# Archive specific message IDs
bun run scripts/gmail-archive.ts archive --message-ids "18f1...,18f2...,18f3..."

# Archive a single message
bun run scripts/gmail-archive.ts archive --message-id "18f..."

# Archive by query
bun run scripts/gmail-archive.ts archive --query "from:newsletter@example.com in:inbox"
Operation Runs

All destructive archive operations are logged to a JSONL operation log for resumability and auditing. Each batch of archives is tracked as a "run" with a unique ID.

bash
# List recent runs with status summaries
bun run scripts/gmail-runs.ts list [--limit 20]

# Show detailed log entries for a specific run
bun run scripts/gmail-runs.ts inspect --run-id "run_20260420_a1b2c3d4"

# Delete logs older than 30 days
bun run scripts/gmail-runs.ts prune
Dry-Run Mode

Dry-run mode runs the full pipeline (scanning, collecting message IDs) but skips all destructive API calls. Staged entries are written to the op log for review.

bash
# Preview what would be archived
bun run scripts/gmail-archive.ts archive --query "..." --dry-run

# Review the staged operations
bun run scripts/gmail-runs.ts inspect --run-id "<run-id>"

# Commit the staged operations (executes the archive)
bun run scripts/gmail-commit.ts commit --run-id "<run-id>"

# Cancel (delete the log, nothing executed)
bun run scripts/gmail-commit.ts cancel --run-id "<run-id>"

Label and filter operations also support --dry-run:

bash
bun run scripts/gmail-manage.ts label --message-ids "..." --add-labels "..." --dry-run
bun run scripts/gmail-manage.ts filters --action create --from "..." --remove-labels "INBOX" --dry-run

Archive operations now return a run_id in their output. Use this to resume interrupted runs:

bash
# Resume an interrupted run (e.g. after daily quota hit)
bun run scripts/gmail-archive.ts archive --resume "run_20260420_a1b2c3d4"

# Pass --run-id to group multiple archive calls under one run
bun run scripts/gmail-archive.ts archive --query "..." --run-id "run_20260420_a1b2c3d4" --phase "noise_archive"

When a run is interrupted (e.g. Gmail daily quota exceeded), the operation log records the interruption with a resume hint. The assistant should detect interrupted runs and offer to resume them rather than starting fresh.

Reversing a Run

If a committed run archived messages incorrectly, reverse it:

bash
# Reverse all committed operations in a run (requires confirmation)
bun run scripts/gmail-reverse.ts --run-id "run_20260420_a1b2c3d4"

# Reverse a specific message within a run (no confirmation needed)
bun run scripts/gmail-reverse.ts --run-id "run_20260420_a1b2c3d4" --thread "18f..."

Reversal semantics:

  • archive → adds INBOX label back (un-archives)
  • label_add → removes the labels that were added
  • label_remove → adds back the labels that were removed
  • trash → removes TRASH label and adds INBOX (un-trashes, within Gmail's 30-day window)
  • filter_create → not auto-reversible; delete manually via gmail-manage.ts filters --action delete

Reversals are themselves logged as runs (auditable, resumable). The reversal only touches labels/state that the original run modified — it does not touch user-applied labels.

Preferences Operations
bash
# List all preferences
bun run scripts/gmail-prefs.ts --action list

# Add senders to blocklist
bun run scripts/gmail-prefs.ts --action add-blocklist --emails "spam@example.com,junk@example.com"

# Add senders to safelist
bun run scripts/gmail-prefs.ts --action add-safelist --emails "important@example.com"

# Remove from blocklist
bun run scripts/gmail-prefs.ts --action remove-blocklist --emails "spam@example.com"

# Remove from safelist
bun run scripts/gmail-prefs.ts --action remove-safelist --emails "important@example.com"

Email Routing Priority

When the user mentions "email" - sending, reading, checking, decluttering, drafting, or anything else - always default to the user's own email (Gmail) unless they explicitly ask about the assistant's own email address (e.g., "set up your email", "send from your address", "check your inbox"). The vast majority of email requests are about the user's Gmail, not the assistant's @vellum.me address.

Do not offer the assistant's own email as an option unless the user specifically asks. If Gmail is not connected, guide them through Gmail setup.

Connection Setup

Gmail
  1. Check connection health first. Run assistant oauth status google. This checks whether the user's Google account is connected and the token is valid.
  2. If no connection is found or the status check fails: Load the vellum-oauth-integrations skill. The skill will evaluate whether managed or your-own mode is appropriate and guide the user accordingly.

Error Recovery

When a Gmail script fails with a token or authorization error:

  1. Try to reconnect silently. Run assistant oauth ping google. This often resolves expired tokens automatically.
  2. If reconnection fails, go straight to setup. Don't present options, ask which route the user prefers, or explain what went wrong technically. Just tell the user briefly (e.g., "Gmail needs to be reconnected - let me set that up") and immediately load the vellum-oauth-integrations skill. The user came to you to get something done, not to troubleshoot - make it seamless.
  3. Never try alternative approaches. Don't use curl, browser automation, or any workaround. If the scripts can't do it, the reconnection flow is the answer.
  4. Never expose error details. The user doesn't need to see error messages about tokens, OAuth, or API failures. Translate errors into plain language.

Safety: Send-Draft and Unsubscribe

Two operations are high-risk and require explicit user confirmation before execution:

  • send-draft: Always show the user what will be sent (recipients, subject, body summary) and wait for explicit confirmation ("yes", "send it", etc.) before running the send-draft script. The script gates on assistant ui confirm — it will present a confirmation dialog to the user and only proceed if approved. Never auto-send.
  • unsubscribe: Always tell the user which mailing list will be unsubscribed from and wait for explicit confirmation before running the unsubscribe script. The script gates on assistant ui confirm. Unsubscribe actions cannot be undone.

If the user has not explicitly confirmed, do not execute these operations. A general instruction like "clean up my inbox" is not confirmation to unsubscribe - it means scan and present options.

Drafting vs Sending (Gmail)

Gmail uses a draft-first workflow. All compose and reply operations create Gmail drafts automatically:

  • bun run scripts/gmail-email.ts draft creates a draft in Gmail Drafts
  • bun run scripts/gmail-email.ts draft with --thread-id and --in-reply-to creates a threaded reply draft
  • bun run scripts/gmail-email.ts forward creates a forward draft, preserving attachments
  • The messaging skill's send operation with Gmail also creates a draft

To actually send: Use bun run scripts/gmail-email.ts send-draft with the draft ID after the user has reviewed it. Only run send-draft when the user explicitly says "send it" or equivalent.

Email Threading (Gmail)

When replying to or continuing an email thread:

  • Preferred: Use the messaging skill's send with the thread's thread_id — it automatically handles threading, reply-all recipients, and subject lines.
  • Manual drafting: Use bun run scripts/gmail-email.ts draft with both --thread-id and --in-reply-to for full control. The thread_id places the draft in the correct Gmail thread; in_reply_to sets the RFC 822 threading headers.
  • Getting the Message-ID: Search and read results include rfc822MessageId in message metadata (looks like <CABx...@mail.gmail.com>). This is the value to pass as --in-reply-to. You can also pass a Gmail message ID directly — the draft script auto-resolves it to the RFC 822 header.

Gmail Search Syntax

When searching Gmail, the query uses Gmail's search operators:

OperatorExampleWhat it finds
from:from:alice@example.comMessages from a specific sender
to:to:bob@example.comMessages sent to a recipient
subject:subject:meetingMessages with a word in the subject
newer_than:newer_than:7dMessages from the last 7 days
older_than:older_than:30dMessages older than 30 days
is:unreadis:unreadUnread messages
has:attachmenthas:attachmentMessages with attachments
label:label:workMessages with a specific label

Email Decluttering

When a user asks to declutter, clean up, or organize their email - start scanning immediately. Don't ask what kind of cleanup they want or request permission to read their inbox. Go straight to scanning - but once results are ready, always present them and let the user choose actions before archiving or unsubscribing.

CRITICAL: Never archive, unsubscribe, or take similar bulk actions unless the user has explicitly confirmed for that specific batch. Each batch of results requires its own explicit user confirmation. If the user says "keep going" or "keep decluttering," that means scan and present new results - NOT auto-archive. Previous batch approvals do not carry forward, but deselections DO carry forward: when the user deselects senders from a cleanup batch, run bun run scripts/gmail-prefs.ts --action add-safelist with those sender emails. Before building the next cleanup table, run bun run scripts/gmail-prefs.ts --action list and exclude safelisted senders from the table — the user already indicated they want to keep those.

Inbox Recon (run before cleanup passes)

Before starting category-specific cleanup, understand the inbox.

Never run more than one gmail-scan.ts command in the same turn. Each scan already fans out authenticated Gmail requests. Parallel bash calls multiply that. Run the broad scan, then promotions, then the general-noise scan, one after another.

  1. Broad scan: Run bun run scripts/gmail-scan.ts sender-digest --query "in:inbox" with --max-senders 75. This surfaces the top senders across ALL categories, not just promotions.
  2. Identify cleanup buckets: Group the results mentally:
    • Newsletters/promotions (hasUnsubscribe: true) → handle in promotions pass
    • Mailing lists / automated forwards (group addresses like devops@, alerts@, noreply@) → handle in general noise pass
    • Reminder chains (DocuSign, GCP, Auth0 — same sender, many messages) → handle in general noise pass
    • Automated receipts (Brex, Stripe, OpenAI credits) → handle in general noise pass
    • Cold outreach (unfamiliar senders, no unsubscribe) → handle in outreach pass
    • Real correspondence → skip
  3. Design passes: Use the recon results to decide which passes to run and in what order. If 80% of the inbox is promotions, start there. If the biggest bucket is mailing-list forwards, start with a targeted query for that address.
  4. General noise pass: After promotions and before outreach, run bun run scripts/gmail-scan.ts sender-digest --query "in:inbox -category:promotions -category:personal" to catch mailing lists, reminder chains, and automated notifications that aren't categorized as promotions. Present as a table following the same pattern as the promotions pass. Pre-select automated/noise senders, deselect anything that looks like real correspondence.
Workflow
  1. Scan: Run bun run scripts/gmail-scan.ts sender-digest. Default query targets promotions currently in the inbox from the last 90 days (in:inbox category:promotions newer_than:90d). The script returns a cache_key plus a lightweight sender summary (counts, unsubscribe availability, sample subjects). Message IDs are stored in the assistant's cache — do NOT ask for them unless needed for archiving. Counts shown in the table reflect only what is currently in the inbox — these are the emails that will be archived.
  2. Present: Show results as a table with selectionMode: "multiple":
    • Columns (exactly 3): Sender, Emails Found, Unsub?
      • Unsub? cell values: Use rich cell format: { "text": "Yes", "icon": "checkmark.circle.fill", "iconColor": "success" } when hasUnsubscribe is true, { "text": "No", "icon": "minus.circle", "iconColor": "muted" } when false.
    • Pre-select all rows (selected: true) - users deselect what they want to keep
    • Caption: Include two parts separated by a newline: (1) data scope, e.g. "Newsletters, notifications, and outreach from last 90 days. Deselect anything you want to keep." (adjusted to match the query used), and (2) the Unsub? column legend: "Unsub? - "Yes" means these emails contain an unsubscribe link, so I can opt you out automatically. "No" means no unsubscribe link was found - these will be archived but you may continue receiving them."
    • Action buttons (exactly 2): "Archive & Unsubscribe" (primary), "Archive Only" (secondary). NEVER offer Delete, Trash, or any destructive action.
  3. Embed cache_key in button data: When constructing the action buttons, include the cache_key from the scan result in each button's data field. This ensures cache_key is forwarded automatically when the user clicks — the LLM does not need to recall it from earlier context:
    json
    {
      "id": "archive_unsubscribe",
      "label": "Archive & Unsubscribe",
      "style": "primary",
      "data": { "cache_key": "<cache_key value here>" }
    }
  4. Wait for user action: Stop and wait. Do NOT proceed to archiving or unsubscribing until the user explicitly confirms which senders to clean up and which action to take. When the user clicks an action button you will receive an action message containing action data: { cache_key, selectedIds }:
    • selectedIds are sender IDs (base64-encoded email addresses) — NOT Gmail message IDs. Always use them as sender emails with cache_key, never as message_ids.
    • Show progress with steps for each phase (e.g., "Archiving 89 senders (2,400 emails)", "Unsubscribing from 72 senders"). Update each step as each phase finishes.
  5. Act on selection - batch, don't loop:
    • Archive all at once: Run bun run scripts/gmail-archive.ts archive --skip-confirm once with --cache-key (from action data) + --sender-emails set to all selected sender emails. The script resolves message IDs from the cache and batches the Gmail API calls internally - never loop sender-by-sender. Use --skip-confirm because the user already confirmed via the UI table.
    • Unsubscribe in bulk: If the action is "Archive & Unsubscribe", run bun run scripts/gmail-manage.ts unsubscribe for each sender that has hasUnsubscribe: true — but emit all unsubscribe calls in a single assistant response (parallel tool use) rather than one-at-a-time across separate turns.
  6. Accurate summary: The scan counts are exact - the messageCount shown in the table matches the number of messages archived. Format: "Cleaned up [total_archived] emails from [sender_count] senders. Unsubscribed from [unsub_count]."
  7. Ongoing protection offer: After reporting results, offer auto-archive filters:
    • "Want me to set up auto-archive filters so future emails from these senders skip your inbox?"
    • If yes, run bun run scripts/gmail-manage.ts filters --action create for each sender with --from set to the sender's email and --remove-labels "INBOX".
    • Then offer a recurring declutter schedule: "Want me to scan for new clutter monthly?"
Show full SKILL.md (1,286 more words)Show less
Cold Outreach Cleanup

After the newsletter/promotions pass, offer to clean up cold outreach — unsolicited emails from senders without unsubscribe links. This catches sales pitches, recruiting spam, and mass outreach that newsletter filters miss.

  1. Scan: Run bun run scripts/gmail-scan.ts outreach-scan (default: last 90 days, senders without List-Unsubscribe headers). The scan includes a hasPriorReply flag per sender — true means the user has previously replied to that sender.
  2. Filter out known contacts: Exclude senders where hasPriorReply: true — these are conversations, not cold outreach. If the contacts skill is loaded, also cross-reference against Google Contacts and exclude matches.
  3. Classify senders using sample subjects, email domains, and message patterns. Categorize into:
    • Clear junk (pre-select for archive): loan/LOC offers, generic SaaS pitches, mass marketing from unknown domains, senders with random/concatenated domain names
    • Sales outreach (pre-select for archive): targeted product pitches with personalised subject lines ("Hi [name]", "for [company]"), outreach tool domains (apollo.io, outreach.io, lemlist.com, instantly.ai, etc.)
    • Potentially useful (deselect / keep by default): recruiting, investor outreach, partnership proposals, vendor introductions that reference the user's specific product or role
    • Ambiguous (deselect / keep by default): anything you're not confident about
  4. Present as a table following the same pattern as the newsletter workflow. Use two visual sections:
    • Pre-selected rows: clear junk + sales outreach
    • Deselected rows: potentially useful + ambiguous senders (user reviews these)
    • Caption: "Cold outreach from the last 90 days (senders without unsubscribe links). Pre-selected senders look like spam or sales pitches. Deselected senders may be useful — review before archiving."
  5. Archive on user action: Same flow as newsletter cleanup — wait for explicit user confirmation, then batch archive.

Key principle: Not all cold outreach is unwanted. Recruiting, investor, and partnership emails can be valuable. When uncertain, default to keeping the sender (deselected) and let the user decide.

Large Inbox Handling

When a scan returns truncated: true or timeBudgetExceeded: true, the inbox has more messages than a single scan pass can cover. Split subsequent scans by date range to ensure full coverage:

Pass 1: in:inbox older_than:90d                     (oldest backlog)
Pass 2: in:inbox newer_than:90d older_than:30d      (recent months)
Pass 3: in:inbox newer_than:30d older_than:7d       (recent weeks)
Pass 4: in:inbox newer_than:7d                      (this week)

Merge results from all passes before presenting the final table. Each pass covers a smaller window, reducing per-scan message count and avoiding timeouts. Only split when a scan actually reports truncation — most inboxes are handled fine in a single pass.

Edge Cases
  • Zero results: Tell the user "No newsletter emails found" and suggest broadening the query (e.g. removing the category filter or extending the date range)
  • Unsubscribe failures: Report per-sender success/failure; the unsubscribe script handles edge cases
  • Truncation handling: The scan covers up to 1,000 messages by default (cap 2,000). If truncated is true, the top senders are still captured. Offer to run additional date-range passes to cover the remaining messages (see Large Inbox Handling above).
  • Time budget exceeded: If the scan returns timeBudgetExceeded: true, present whatever results were collected. Offer to run additional date-range passes for uncovered periods.

Cleanup Preferences (Blocklist & Safelist)

The gmail-prefs.ts script persists sender preferences across cleanup sessions:

  • Blocklist: Sender emails archived in previous sessions. On future cleanups, pre-pass archive all blocklisted senders before scanning (use bun run scripts/gmail-archive.ts archive --query "from:email1 OR from:email2 ... in:inbox"). The user will see a confirmation prompt for the archive — once approved, the script proceeds.
  • Safelist: Sender emails the user explicitly deselected (chose to keep). Exclude these senders from future cleanup tables entirely.
Workflow integration
  1. Before scanning: Run bun run scripts/gmail-prefs.ts --action list. If blocklisted senders exist, offer to auto-archive them first ("I have N previously archived senders — want me to clean those up first?"). Remove safelisted senders from scan results before presenting the table.
  2. After archiving: Run bun run scripts/gmail-prefs.ts --action add-blocklist with the archived sender emails to persist them for future sessions.
  3. After user deselects: When the user deselects senders from a cleanup table, run bun run scripts/gmail-prefs.ts --action add-safelist with the deselected sender emails.
  4. User overrides: If the user asks to stop blocking or stop keeping a sender, use remove-blocklist or remove-safelist accordingly.
Company-Domain Sender Handling

When scan results include senders from the user's own company domain (e.g., @vellum.ai):

  • Protect individual colleagues: Cofounders, direct reports, teammates sending from their personal work address (e.g., akash@company.com, aaron@company.com) — deselect these from cleanup tables.
  • Archive mailing lists and group addresses: Addresses like devops@, alerts@, noreply@, security@, billing@ at the company domain are automated forwards, not personal correspondence. These are archivable by default — pre-select them in the cleanup table.
  • When uncertain: If a company-domain sender could be either a colleague or a mailing list (e.g., team@company.com), check sample subjects. Automated alerts, CI notifications, and vendor forwards → archivable. Direct messages with personal context → protect.

Do not blanket-protect an entire domain. The user's company domain often generates more automated noise than any external sender.

Scan Operations

Scan scripts (gmail-scan.ts sender-digest, gmail-scan.ts outreach-scan) return a cache_key that references message IDs stored in the assistant's cache. This keeps thousands of message IDs out of the conversation context.

  • Pass cache_key + sender emails to bun run scripts/gmail-archive.ts archive instead of individual message_ids
  • Cache entries expire after 30 minutes. When a cache entry expires, archiving automatically falls back to query-based archiving per sender.
  • To retrieve cached data: assistant cache get <cache_key> --json
  • Raw message_ids still work as a fallback for non-scan workflows

The outreach-scan operation enriches each sender with hasPriorReply (whether the user has ever sent an email to that address). Use this signal to filter out legitimate correspondents before classifying cold outreach.

Batch Operations

  • bun run scripts/gmail-archive.ts archive supports --cache-key + --sender-emails (preferred for declutter workflows), --message-ids, --message-id, or --query.
  • bun run scripts/gmail-manage.ts label supports --message-id or --message-ids only — it does not accept cache_key.
  • First scan to get a cache_key, then use the archive script to batch-archive by sender.
  • Always confirm with the user before batch operations on large numbers of messages.

Attachments

  • List attachments: bun run scripts/gmail-manage.ts attachments --action list --message-id "18f..." — returns filename, MIME type, size, and attachment ID for each attachment on a message.
  • Download attachment: bun run scripts/gmail-manage.ts attachments --action download --message-id "18f..." --attachment-id "ANGj..." --filename "report.pdf" — saves a specific attachment to disk.

Workflow: use attachments --action list to discover attachments, then attachments --action download to save them locally.

Common Workflows

Declutter Inbox
  1. Run bun run scripts/gmail-scan.ts sender-digest to scan for newsletters and promotions
  2. Present results showing senders, message counts, and unsubscribe availability
  3. Wait for user to select senders and confirm an action
  4. Archive selected senders and unsubscribe where available (if user chose "Archive & Unsubscribe")
  5. Offer to create filters for ongoing protection
Create a Gmail Filter
  1. User says "auto-archive emails from newsletters@example.com"
  2. Run bun run scripts/gmail-manage.ts filters --action create --from "newsletters@example.com" --remove-labels "INBOX"
  3. Confirm the filter was created and explain what it does
Set Vacation Auto-Reply
  1. User says "set my out-of-office for next week"
  2. Run bun run scripts/gmail-manage.ts vacation --action enable --message "I'm out of office until Monday"
  3. Confirm the auto-reply is active and when it expires
Manage Follow-ups
  1. User says "flag this email for follow-up" — run bun run scripts/gmail-manage.ts follow-up --action track --message-id "18f..."
  2. User says "what emails am I tracking?" — run bun run scripts/gmail-manage.ts follow-up --action list
  3. User says "mark that as done" — run bun run scripts/gmail-manage.ts follow-up --action untrack --message-id "18f..."
Identify Cold Outreach
  1. Run bun run scripts/gmail-scan.ts outreach-scan to find senders without unsubscribe headers
  2. Present results for review — these are likely cold outreach or unsolicited emails
  3. User can choose to archive, create filters to block, or ignore

Date Verification

Before composing any email that references a date or time:

  1. Check the current_time: field in the <turn_context> block for today's date and timezone
  2. Verify that "tomorrow" means the day after today's date, "next week" means the upcoming Monday–Friday, etc.
  3. If the email references a date from another message, cross-check it against the turn context to ensure it's in the future

© vellum-ai, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 17 other files (scripts, assets) in skills/gmail of vellum-ai/vellum-assistant.

  • SKILL.md
  • assets/icon.svg
  • scripts/gmail-archive.ts
  • scripts/gmail-auto-filters.ts
  • scripts/gmail-commit.ts
  • scripts/gmail-email.ts
  • scripts/gmail-manage.ts
  • scripts/gmail-prefs.ts
  • scripts/gmail-reverse.ts
  • scripts/gmail-runs.ts
  • scripts/gmail-scan.ts
  • scripts/lib/common.ts
  • scripts/lib/gmail-client.test.ts
  • scripts/lib/gmail-client.ts
  • scripts/lib/mime-builder.ts
  • scripts/lib/oauth-request-slot.test.ts
  • scripts/lib/oauth-request-slot.ts
  • scripts/lib/op-log.ts

Open the folder on GitHubat commit c92ead1

Compare with similar skills

Gmail next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Gmail compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Gmail this skillvellum-ai/vellum-assistant1.4k—~8.3kAutomated safety check: PassMIT
Career-Ops Gmail Lead Plugincareer-ops-hq/career-ops74k—~233Automated safety check: NotesMIT
Gmailteam-attention/plugins-for-claude-natives827—~967Automated safety check: PassMIT
Connect Apps with ComposioComposioHQ/awesome-claude-skills77k3 repos~557Automated safety check: PassNone
Gmail Emailopen-gitagent/gitagent710—~235Automated safety check: NotesMIT
Gmclibadlogic/pi-skills2.6k1 repos~470Automated safety check: PassMIT

Similar skills

  • Career-Ops Gmail Lead Plugin

    career-ops-hq/career-ops

    Pulls job leads from a Gmail label into the career-ops pipeline, extracting job URLs from DMARC-passing emails and de-duplicating against existing leads.

    74k GitHub stars~233 tokensUpdated today
    Productivity & AutomationAuto-check: notes
  • Gmail

    team-attention/plugins-for-claude-natives

    This skill should be used when the user asks to "check email", "read emails", "send email", "reply to email", "search inbox", or manages Gmail.

    827 GitHub stars~967 tokensUpdated 5 mo ago
    Productivity & AutomationAuto-check passed
  • Connect Apps with Composio

    ComposioHQ/awesome-claude-skills

    Connects an agent to 1000+ external apps through the Composio Tool Router plugin, so it can actually send emails, create issues and post messages instead of only drafting them.

    77k GitHub starsUsed in 3 repos~557 tokens
    Productivity & AutomationAuto-check passed
  • Gmail Email

    open-gitagent/gitagent

    Send emails via Gmail SMTP using App Password authentication.

    710 GitHub stars~235 tokensUpdated 1 mo ago
    Productivity & AutomationAuto-check: notes
  • Gmcli

    badlogic/pi-skills

    Gmail CLI for searching emails, reading threads, sending messages, managing drafts, and handling labels/attachments.

    2.6k GitHub starsUsed in 1 repo~470 tokens
    Productivity & AutomationAuto-check passed
  • Zele

    remorses/zele

    zele is a multi-account email and calendar CLI for Gmail, IMAP/SMTP (Fastmail, Outlook, any provider), and Google Calendar.

    299 GitHub stars~1.5k tokensUpdated yesterday
    Productivity & AutomationAuto-check passed

More from vellum-ai/vellum-assistant

All 108 skills in this repo
  • Vellum GitHub App Setup

    vellum-ai/vellum-assistant

    Create and configure a GitHub App so the assistant can push commits, open PRs, and comment under its own bot identity.

    1.4k GitHub stars~3.1k tokensUpdated today
    Auto-check passed
  • Discord App Setup

    vellum-ai/vellum-assistant

    Connect a Discord bot to the assistant via the Discord Gateway with guided application creation and intent configuration

    1.4k GitHub stars~4.2k tokensUpdated today
    Auto-check passed
  • Sentry App Setup

    vellum-ai/vellum-assistant

    Create and configure a Sentry internal integration so the assistant can manage issues, alerts, and releases under its own identity

    1.4k GitHub stars~1.3k tokensUpdated today
    Auto-check passed
  • Memory Corpus Ingest

    vellum-ai/vellum-assistant

    Ingest a large dataset into memory as a skimmed map. An agent skill from vellum-ai/vellum-assistant.

    1.4k GitHub stars~3k tokensUpdated today
    Auto-check: notes
  • Plugin Builder

    vellum-ai/vellum-assistant

    A skill your agent uses when the user wants to build, scaffold, ship, or edit a Vellum plugin that bundles multiple surfaces (hooks, tools, skills, and more) into one installable package.

    1.4k GitHub stars~3.1k tokensUpdated today
    Auto-check passed
  • Slack App Setup

    vellum-ai/vellum-assistant

    Connect a Slack app to the Vellum Assistant via Socket Mode.

    1.4k GitHub stars~2.5k tokensUpdated today
    Auto-check: warnings

Works with

Questions about Gmail

What does Gmail do?

Manage Gmail email — drafting, sending, organizing, filters, vacation replies, and inbox analysis. Gmail is an agent skill from vellum-ai/vellum-assistant.

When should I use Gmail?

Gmail fits situations like: tasks that involve Email management.

How do I install Gmail in Claude Code?

Run `npx skills add vellum-ai/vellum-assistant --skill gmail -a claude-code`. Or copy the skill folder (skills/gmail in vellum-ai/vellum-assistant) into .claude/skills/gmail in your project. Claude Code loads it when a task matches its description.

How do I install Gmail in Codex?

Run `npx skills add vellum-ai/vellum-assistant --skill gmail -a codex`. Or copy the skill folder (skills/gmail in vellum-ai/vellum-assistant) into .agents/skills/gmail in your project. Codex loads it when a task matches its description.

Can I use Gmail in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add vellum-ai/vellum-assistant --skill gmail -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/gmail, .gemini/skills/gmail, .github/skills/gmail and .opencode/skills/gmail in your project.

What does Gmail need to run?

Going by SKILL.md and its folder, Gmail needs TypeScript for the scripts in its folder and the command-line tools its instructions call (bun). Our summary lists: Node.js. Compatibility (from SKILL.md): Designed for Vellum personal assistants.

Does Gmail access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Gmail safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. The check reads SKILL.md only: the scripts in the folder are not scanned, so read them before running anything.

What licence does Gmail use?

Gmail is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Gmail use?

About 8.3k tokens (SKILL.md is roughly 33k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Gmail?

Skills that share tags, products or a category with Gmail: Career-Ops Gmail Lead Plugin (career-ops-hq/career-ops, 74k stars), Gmail (team-attention/plugins-for-claude-natives, 827 stars), Connect Apps with Composio (ComposioHQ/awesome-claude-skills, 77k stars) and Gmail Email (open-gitagent/gitagent, 710 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Gmail?

vellum-ai (a GitHub organization) maintains it in vellum-ai/vellum-assistant, which has 1,397 GitHub stars. The repository holds 108 skills in this directory. The repository was last updated on October 7, 2026.

Source: vellum-ai/vellum-assistant on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.