CLI for Gmail API - sync emails locally, search, send, manage labels. Supports multiple accounts.
- Sync emails locally as JSON for offline access and searching
- Search with DuckDB across thousands of messages instantly
- Stats dashboard with analytics (top senders, domains, activity patterns)
- Multi-account support with easy switching
- Rate limit handling - auto-retry with exponential backoff
- Resumable sync - interrupted syncs continue where they left off
- Attachments - optionally download all attachments
- Mutations - archive, trash, mark read/unread, label management
- Smart filtering - spam and trash automatically excluded from sync
npm install -g @rusintez/gmail
# Requires duckdb for stats command
brew install duckdb- Go to Google Cloud Console
- Create a new project (or select existing)
- Go to APIs & Services → Enable APIs → Search "Gmail API" → Enable
- Go to APIs & Services → OAuth consent screen:
- Select "External" user type
- Fill in app name, support email
- Add your email as test user (while in testing mode)
- Go to APIs & Services → Credentials:
- Click Create Credentials → OAuth 2.0 Client ID
- Application type: Desktop app
- Copy the Client ID and Client Secret
gmail auth setup <client-id> <client-secret>
gmail auth login # Opens browser for OAuth consentgmail auth login # Repeat for each account
gmail auth list # List all accounts
gmail auth default user@gmail.com # Set defaultNote: While your OAuth app is in "Testing" mode, only emails added as test users can authenticate.
gmail sync # Incremental sync (newest 100)
gmail sync --full # Full sync (all messages)
gmail sync --include-attachments # Download attachments too
gmail sync -a user@gmail.com # Sync specific accountSync is resumable - if interrupted, it continues where it left off.
Exclusions: Spam and trash messages are automatically excluded from sync. Attachments from promotional emails are skipped (security).
Data is stored at ~/.local/share/gmail/{account}/
gmail stats # Stats for default account
gmail stats user@gmail.com # Stats for specific accountShows: message counts, top senders, domains, activity by time, labels, largest senders by size.
gmail inbox # Recent inbox messages
gmail inbox -u # Unread only
gmail inbox -l STARRED # Starred messages
gmail inbox -n 50 # Limit results
gmail inbox -q "from:boss" # Gmail search query
gmail message <id> # Full message content
gmail thread <id> # Full conversation thread
gmail search "subject:invoice" # Search messagesgmail send --to user@example.com --subject "Hi" --body "Hello!"
gmail send --to a@x.com --cc b@x.com --subject "Meeting" --body "Let's meet"gmail archive <id> # Remove from inbox (stays in All Mail)
gmail trash <id> # Move to trash (auto-deleted in 30 days)
gmail mark-read <id> # Mark as read
gmail mark-unread <id> # Mark as unread
gmail label <id> STARRED # Add label
gmail unlabel <id> STARRED # Remove labelRead/unread: Tracked via the UNREAD label in labelIds. Query with is:unread or check labelIds in JSON.
Archive vs Delete: Archive keeps the message accessible in All Mail and search. Trash eventually deletes it.
gmail labels # List all labelsgmail sync-status # List synced accounts
gmail sync-status user@gmail.com # Status for specific account
gmail sync-reset user@gmail.com # Reset state (next sync = full)gmail migrate decode-body # Decode body in all accounts
gmail migrate decode-body user@gmail.com # Specific accountAfter syncing, query your emails with SQL:
cd ~/.local/share/gmail/user_at_gmail_com
duckdb-- Search message body
SELECT _headers.subject, _body[1:100] as preview
FROM read_json_auto('messages/*.json', maximum_object_size=10485760)
WHERE _body ILIKE '%invoice%';
-- Top senders
SELECT _headers.from, count(*) as count
FROM read_json_auto('messages/*.json', maximum_object_size=10485760)
GROUP BY 1 ORDER BY 2 DESC LIMIT 10;
-- Messages by month
SELECT strftime(to_timestamp(internalDate::bigint/1000), '%Y-%m') as month, count(*)
FROM read_json_auto('messages/*.json', maximum_object_size=10485760)
GROUP BY 1 ORDER BY 1 DESC;See schema.md for full data schema and more query examples.
gmail inbox # Markdown table (default)
gmail inbox -f json # JSON - for scripting
gmail inbox -f minimal # Tab-separatedgmail -a work@company.com inbox # Use specific account
gmail -a personal@gmail.com search "receipts"Use Gmail's powerful search in -q or search command:
gmail search "from:user@example.com"
gmail search "subject:invoice after:2024/01/01"
gmail search "has:attachment filename:pdf"
gmail search "is:unread category:primary"See Gmail search operators for full syntax.
- Config:
~/.config/gmail-cli/config.json - Synced data:
~/.local/share/gmail/ - Schema: schema.md
MIT