gmail-multi-account

Multi-account Gmail management via himalaya CLI. Three accounts (aceengineer, achantav, skestates) with distinct triage rules, contact DBs, and tone profiles. Foundation skill for email automation.

5 stars

Best use case

gmail-multi-account is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Multi-account Gmail management via himalaya CLI. Three accounts (aceengineer, achantav, skestates) with distinct triage rules, contact DBs, and tone profiles. Foundation skill for email automation.

Teams using gmail-multi-account should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/gmail-multi-account/SKILL.md --create-dirs "https://raw.githubusercontent.com/vamseeachanta/workspace-hub/main/.agents/skills/email/gmail-multi-account/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/gmail-multi-account/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How gmail-multi-account Compares

Feature / Agentgmail-multi-accountStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Multi-account Gmail management via himalaya CLI. Three accounts (aceengineer, achantav, skestates) with distinct triage rules, contact DBs, and tone profiles. Foundation skill for email automation.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# Gmail Multi-Account Management

Three Gmail accounts managed from CLI via himalaya. Each account has distinct purpose, contacts, and handling rules.

## Accounts

| Alias | Email | Purpose | Contacts Repo |
|---|---|---|---|
| `ace` | vamsee.achanta@aceengineer.com | Engineering consulting, GTM, clients | aceengineer-admin |
| `personal` | achantav@gmail.com | Personal, networking, subscriptions | aceengineer-admin |
| `skestates` | skestatesinc@gmail.com | Real estate LLC, tenant/vendor | sabithaandkrishnaestates |

## Architecture Decision (April 2026)

### Tool Assessment Results (7 approaches evaluated)

| Tool | Downloads | Multi-Acct | Unsubscribe | Verdict |
|---|---|---|---|---|
| gmail-mcp-multiauth (npm) | 931/mo | YES (3 named servers) | NO (custom headers) | **WINNER — npm install** |
| @gongrzhe/gmail-mcp-autoauth | 381K/mo | NO (single) | NO | Rejected — single account |
| @shinzolabs/gmail-mcp | 5.6K/mo | Limited | NO | Rejected — complex auth |
| workspace-mcp (taylorwilsdon) | 2K stars | YES (OAuth 2.1) | NO | Rejected — overkill |
| himalaya CLI | N/A | YES native | NO (IMAP flags) | **FALLBACK — cron/scripts** |
| himalaya-mcp (Data-Wise) | 0 stars | YES | NO | Rejected — too many layers |
| google-workspace DIY | N/A | YES | YES (custom) | Rejected — high maintenance |

### Setup Architecture

**Primary:** gmail-mcp-multiauth (npm) for MCP tool access
- `npm install -g gmail-mcp-multiauth` (installed, 15s setup)
- Requires: GCP project + Gmail API enabled + OAuth Desktop App credentials
- Each account gets named MCP server: `gmail-ace`, `gmail-personal`, `gmail-skestates`
- Auth: OAuth2 browser flow per account (one-time, tokens persist with refresh)
- GCP project name: "Hermes Gmail Automation" (or user-provided)

**Fallback:** himalaya CLI (installed v1.2.0, Linux musl x86_64)
- `curl -sSL .../install.sh | PREFIX=~/.local sh` (installed, 30s setup)
- Auth: Gmail App Passwords (2FA required, Settings → App Passwords)
- Config: `~/.config/himalaya/config.toml` (TOML format)
- Uses `backend.auth.cmd` to read passwords from files (NOT keyring)
- Config syntax changed significantly in v1.x — don't use old v0 config docs

### Critical Config Gotcha (v1.2.0)
The himalaya v1.2.0 config schema is NOT compatible with v0 docs. Key differences:
- No `backend.auth.keyring` or `backend.auth.type = "cmd"` syntax
- Use `backend.auth.cmd = "cat /path/to/secret"` directly under account
- No `message.send.backend.*` — use `message.send.type`, `message.send.host`, etc.
- The account block is flat: `[accounts.name]` with keys directly inside
- Test connection: `himalaya envelope list --account ace --page-size 1`

### Credential Files
- Config: `~/.config/himalaya/config.toml` (created)
- Secret files: `~/.config/himalaya/.secret_{ace,personal,skestates}` (created, chmod 600)
- OAuth state: stored by gmail-mcp-multiauth per-account in `~/.gmail-mcp/` or similar

### Unsubscribe Gap
No MCP server or himalaya command has native List-Unsubscribe support.
Must parse headers manually: `himalaya message export ID --full | grep -i list-unsubscribe`
For gmail-mcp-multiauth: use the raw message body parsing tools to extract List-Unsubscribe headers.

## Gmail MCP on Headless Servers (IMPORTANT)

**gmail-mcp-multiauth will NOT work on headless servers.** The `setup`
command calls `open()` to launch a browser and listens on port 3000 for
the OAuth callback. This requires a running GUI browser.

### Manual OAuth Flow for Headless

If you need MCP OAuth without a browser:
1. Generate OAuth URLs using the OOB (out-of-band) redirect:
   ```
   https://accounts.google.com/o/oauth2/v2/auth?
     scope=https://www.googleapis.com/auth/gmail.modify+https://www.googleapis.com/auth/gmail.settings.basic
     &response_type=code
     &access_type=offline
     &client_id=YOUR_CLIENT_ID
     &redirect_uri=urn:ietf:wg:oauth:2.0:oob
   ```
2. Open URL → sign in → grant permission → copy the authorization code
3. Exchange code for tokens manually
4. Save tokens to `~/.gmail-<account>/credentials.json`

### himalaya Config Gotcha (v1.2.0)

The himalaya v1.2.0 config schema differs from the skill example below.
The actual working config is already at `~/.config/himalaya/config.toml`.
Key differences from v0:
- `message.send.type = "smtp"` not `message.send.backend.type`
- `message.send.auth.cmd = "cat ~/.config/himalaya/.secret_<acct>"` 
- No `backend.auth.keyring` or `\"cmd\"` workaround

## Setup

### Step 1: Install himalaya

```bash
curl -sSL https://raw.githubusercontent.com/pimalaya/himalaya/master/install.sh | PREFIX=~/.local sh
```

### Step 2: Generate Gmail App Passwords

For each account:
1. Go to https://myaccount.google.com/apppasswords (2FA must be enabled)
2. Create app password for "Mail" on "Other (Custom name)"
3. Store securely: `echo "APP_PASSWORD" > ~/.config/himalaya/.secret_<alias>`
4. `chmod 600 ~/.config/himalaya/.secret_*`

### Step 3: Configure himalaya

Create `~/.config/himalaya/config.toml`:

```toml
# Global defaults
display-name = "Vamsee Achanta"
downloads-dir = "~/.config/himalaya/downloads"

[accounts.ace]
default = true
email = "vamsee.achanta@aceengineer.com"
display-name = "Vamsee Achanta"
backend.type = "imap"
backend.host = "imap.gmail.com"
backend.port = 993
backend.encryption.type = "tls"
backend.login = "vamsee.achanta@aceengineer.com"
backend.auth.type = "password"
backend.auth.cmd = "cat ~/.config/himalaya/.secret_ace"
message.send.type = "smtp"
message.send.host = "smtp.gmail.com"
message.send.port = 587
message.send.encryption.type = "starttls"
message.send.login = "vamsee.achanta@aceengineer.com"
message.send.auth.type = "password"
message.send.auth.cmd = "cat ~/.config/himalaya/.secret_ace"

[accounts.personal]
email = "achantav@gmail.com"
display-name = "Vamsee Achanta"
backend.type = "imap"
backend.host = "imap.gmail.com"
backend.port = 993
backend.encryption.type = "tls"
backend.login = "achantav@gmail.com"
backend.auth.type = "password"
backend.auth.cmd = "cat ~/.config/himalaya/.secret_personal"
message.send.type = "smtp"
message.send.host = "smtp.gmail.com"
message.send.port = 587
message.send.encryption.type = "starttls"
message.send.login = "achantav@gmail.com"
message.send.auth.type = "password"
message.send.auth.cmd = "cat ~/.config/himalaya/.secret_personal"

[accounts.skestates]
email = "skestatesinc@gmail.com"
display-name = "SKEstates Inc"
backend.type = "imap"
backend.host = "imap.gmail.com"
backend.port = 993
backend.encryption.type = "tls"
backend.login = "skestatesinc@gmail.com"
backend.auth.type = "password"
backend.auth.cmd = "cat ~/.config/himalaya/.secret_skestates"
message.send.type = "smtp"
message.send.host = "smtp.gmail.com"
message.send.port = 587
message.send.encryption.type = "starttls"
message.send.login = "skestatesinc@gmail.com"
message.send.auth.type = "password"
message.send.auth.cmd = "cat ~/.config/himalaya/.secret_skestates"
```

### Step 4: Verify

```bash
himalaya --account ace envelope list --page-size 5
himalaya --account personal envelope list --page-size 5
himalaya --account skestates envelope list --page-size 5
```

## Usage Patterns

### Quick scan all accounts
```bash
for acct in ace personal skestates; do
  echo "=== $acct ==="
  himalaya --account $acct envelope list --page-size 10 --output json 2>/dev/null
done
```

### Read specific message
```bash
himalaya --account ace message read 42
```

### Send (always confirm with user first)
```bash
cat << 'EOF' | himalaya --account ace template send
From: vamsee.achanta@aceengineer.com
To: recipient@example.com
Subject: Subject Line

Body text here.
EOF
```

## Account-Specific Rules

### ace (vamsee.achanta@aceengineer.com)
- PRIORITY: client emails, RFPs, invoice responses, GTM prospects
- TONE: Professional engineering — P.E. credentials, technical precision
- CONTACTS: aceengineer-admin/admin/contacts/aceengineer_contacts.csv (1,306 entries)
- LINK TO: aceengineer-strategy/ prospect pipeline
- TOUCHBASE: engineering contacts, potential clients

### personal (achantav@gmail.com)
- PRIORITY: personal finance, family, career networking
- TONE: Casual/personal, warm
- CONTACTS: aceengineer-admin/admin/contacts/achantav_contacts.csv (1,157 entries)
- AGGRESSIVE UNSUBSCRIBE: marketing, social media notifications
- TOUCHBASE: close professional network, alumni, friends

### skestates (skestatesinc@gmail.com)
- PRIORITY: tenant communications (Family Dollar Store #30150), tax/legal, insurance
- TONE: Business formal, landlord correspondence
- CONTACTS: sabithaandkrishnaestates/admin/contacts/skestates_contacts.csv
- KEY CONTACT: TX_Rents@familydollar.com (tenant)
- LINK TO: sabithaandkrishnaestates/ deal files, tax docs

## Contact Database Locations (normalized + deduped)

| Account | CSV Path | Count |
|---|---|---|
| ace | aceengineer-admin/admin/contacts/aceengineer_normalized.csv | 1,281 |
| personal | aceengineer-admin/admin/contacts/achantav_normalized.csv | 994 |
| skestates | sabithaandkrishnaestates/admin/contacts/skestates_contacts.csv | 25 |

Cross-file dedup: 132 overlaps resolved (see reports/email/contact-dedup-report.md)

## Live Status (as of 2026-04-06)

All 3 accounts fully connected:
- ace: OAuth2 ✅ + himalaya (App Password) ✅
- personal: OAuth2 ✅ + himalaya (App Password) ✅
- skestates: OAuth2 ✅ + himalaya ❌ (App Passwords unavailable for this account)

Credential paths:
- OAuth tokens: ~/.gmail-{ace,personal,skestates}/credentials.json
- OAuth config: ~/.gmail-mcp/oauth-env.json (client_id + client_secret)
- Himalaya secrets: ~/.config/himalaya/.secret_{ace,personal}
- Himalaya config: ~/.config/himalaya/config.toml
- MCP start scripts: ~/.gmail-{ace,personal,skestates}/start-mcp.sh

Digest script: scripts/email/gmail-digest.py (run with uv)
Cron: daily at 12 PM CT (job id: 908c4afa32cf)

GCP Project: hermes-gmail-automation
OAuth consent: External, test users added (all 3 emails)

## Pitfalls

1. Gmail IMAP must be enabled: Settings > Forwarding and POP/IMAP > Enable IMAP
2. App Passwords only work with 2FA enabled
3. Google may block "less secure" access — App Passwords bypass this
4. himalaya message IDs are folder-relative — re-list after folder changes
5. Never send email without user confirmation — show draft first
6. Rate limit: don't rapid-fire API calls; batch reads
7. The skestatesinc email was "skestatesinc.gmail.com" — correct is "skestatesinc@gmail.com"
8. **himalaya v1.2.0 config schema changed** — `backend.auth.type = "cmd"` is INVALID (duplicate key error with `backend.auth.type = "password"`). Use only `backend.auth.cmd` under the password type.
9. gmail-mcp-multiauth setup requires browser — use manual OOB flow on headless servers
10. External repo contacts must be committed from within their respective repo dirs (not workspace-hub root)

Related Skills

multi-year-tax-filing-verification-workflow

5
from vamseeachanta/workspace-hub

Verify and reconcile complex multi-form tax filings by cross-referencing source documents, identifying data dependencies, and validating line-by-line against authoritative records.

multi-source-tax-document-reconciliation

5
from vamseeachanta/workspace-hub

Verify generated tax forms against source documents by line-by-line comparison, not just totals

multi-role-agent-contract-review-pipeline

5
from vamseeachanta/workspace-hub

Execute a 4-role agent team (Planner/Architect/Reviewer/Integrator) pipeline for self-reviewing knowledge artifacts before delivery

multi-repo-sync-diagnosis-repair

5
from vamseeachanta/workspace-hub

Diagnose and repair failed pulls across multi-repo ecosystems with stale locks, submodule conflicts, and untracked files

multi-repo-sync-diagnosis-and-repair

5
from vamseeachanta/workspace-hub

Systematic approach to diagnosing and repairing failures across a multi-repo workspace

multi-repo-stale-lock-recovery

5
from vamseeachanta/workspace-hub

Diagnose and recover from stale git lock files in multi-repo workspaces, especially with submodules

multi-repo-pull-with-untracked-conflict-recovery

5
from vamseeachanta/workspace-hub

Diagnose and resolve multi-repo pull failures caused by untracked files conflicting with remote changes

multi-repo-git-recovery

5
from vamseeachanta/workspace-hub

Diagnose and recover from stale lock files, diverged branches, and untracked file conflicts across multiple repos in a workspace ecosystem

multi-repo-branch-hygiene-at-scale

5
from vamseeachanta/workspace-hub

Systematic approach to cleaning stale branches, resolving merge conflicts, and syncing multiple repos

multi-layer-stale-state-debugging

5
from vamseeachanta/workspace-hub

Detect and clear stale state persisting across multiple storage layers (auth files, cache, code logic)

multi-format-transaction-parser

5
from vamseeachanta/workspace-hub

Parse and consolidate financial transaction data across multiple CSV formats and years

multi-format-csv-parser-with-deduplication

5
from vamseeachanta/workspace-hub

Parse brokerage CSV exports that exist in multiple formats with overlapping data across files