Repository files navigation

gmcli

Minimal Gmail CLI for searching, reading threads, managing labels, drafts, and sending emails.

Fork Notice: This is a fork of @mariozechner/gmcli by Mario Zechner with bug fixes for --reply-to thread ID handling and drafts send crash. See CHANGELOG.md for details.

Install

npm install -g @willtmc/gmcli

Setup

Before adding an account, you need OAuth2 credentials from Google Cloud Console:

  1. Create a new project (or select existing)
  2. Enable the Gmail API
  3. Set app name in OAuth branding
  4. Add test users (all Gmail addresses you want to use with gmcli)
  5. Create OAuth client:
    • Click "Create Client"
    • Application type: "Desktop app"
    • Download the JSON file

Then:

gmcli accounts credentials ~/path/to/credentials.json
gmcli accounts add you@gmail.com

Usage

gmcli accounts <action> Account management
gmcli <email> <command> [options] Gmail operations

Commands

accounts

gmcli accounts credentials <file.json># Set OAuth credentials (once)
gmcli accounts list # List configured accounts
gmcli accounts add <email># Add account (opens browser)
gmcli accounts add <email> --manual # Add account (browserless, paste redirect URL)
gmcli accounts remove <email># Remove account

search

Search threads using Gmail query syntax. Returns thread ID, date, sender, subject, and labels.

gmcli <email> search <query> [--max N] [--page TOKEN]

Query examples:

  • in:inbox, in:sent, in:drafts, in:trash, in:spam
  • is:unread, is:starred, is:important
  • from:sender@example.com, to:recipient@example.com
  • subject:keyword
  • has:attachment, filename:pdf
  • after:2024/01/01, before:2024/12/31
  • label:Work, label:UNREAD
  • Combine with spaces: in:inbox is:unread from:boss@company.com

Examples:

gmcli you@gmail.com search "in:inbox"
gmcli you@gmail.com search "is:unread" --max 50
gmcli you@gmail.com search "from:someone@example.com has:attachment"

thread

Get a thread with all messages. Shows Message-ID, headers, body, and attachments for each message.

gmcli <email> thread <threadId># View thread
gmcli <email> thread <threadId> --download # Download attachments

Attachments are saved to ~/.gmcli/attachments/.

labels

gmcli <email> labels list # List all labels (ID, name, type)
gmcli <email> labels <threadIds...> [--add L] [--remove L] # Modify labels on threads

You can use label names or IDs when modifying (names are case-insensitive).

System labels: INBOX, UNREAD, STARRED, IMPORTANT, TRASH, SPAM

Examples:

gmcli you@gmail.com labels list
gmcli you@gmail.com labels abc123 --remove UNREAD
gmcli you@gmail.com labels abc123 --add Work --remove INBOX
gmcli you@gmail.com labels abc123 def456 --add STARRED

drafts

gmcli <email> drafts list # List all drafts
gmcli <email> drafts get <draftId># View draft with attachments
gmcli <email> drafts get <draftId> --download # Download draft attachments
gmcli <email> drafts delete <draftId># Delete draft
gmcli <email> drafts send <draftId># Send draft
gmcli <email> drafts create --to <emails> --subject <s> --body <b> [options]

send

Send an email directly.

gmcli <email> send --to <emails> --subject <s> --body <b> [options]

Options for drafts create and send:

  • --to <emails> - Recipients (comma-separated, required)
  • --subject <s> - Subject line (required)
  • --body <b> - Message body (required)
  • --cc <emails> - CC recipients (comma-separated)
  • --bcc <emails> - BCC recipients (comma-separated)
  • --reply-to <messageId> - Reply to message (sets In-Reply-To/References headers and thread; accepts Gmail message ID or thread ID; canonicalizes equivalent reply subjects to Gmail's source thread subject)
  • --in-reply-to <messageId> - Alias for --reply-to
  • --thread <threadId> - Force a specific Gmail thread without setting reply headers; prefer --reply-to for normal replies
  • --attach <file> - Attach file (can be used multiple times)

Examples:

# Create draft
gmcli you@gmail.com drafts create --to a@x.com --subject "Hi" --body "Hello"# Create reply draft
gmcli you@gmail.com drafts create --to a@x.com --subject "Re: Topic" \
--body "My reply" --reply-to 19aea1f2f3532db5
# Send draft
gmcli you@gmail.com drafts send r1234567890
# Send directly
gmcli you@gmail.com send --to a@x.com --subject "Hi" --body "Hello"# Send reply with attachment
gmcli you@gmail.com send --to a@x.com --subject "Re: Topic" \
--body "See attached" --reply-to 19aea1f2f3532db5 --attach doc.pdf

url

Generate Gmail web URLs for threads. Uses canonical URL format with email parameter (works regardless of account order in browser).

gmcli <email> url <threadIds...>

Example:

gmcli you@gmail.com url 19aea1f2f3532db5 19aea1f2f3532db6

Data Storage

All data is stored in ~/.gmcli/:

  • credentials.json - OAuth client credentials
  • accounts.json - Account tokens
  • attachments/ - Downloaded attachments

Development

npm install
npm run build
npm run check

Publishing

# Update version in package.json and CHANGELOG.md
npm run build
npm publish --access public
git tag v<version>
git push --tags

License

MIT

About

Minimal Gmail CLI

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

gmcli

Minimal Gmail CLI for searching, reading threads, managing labels, drafts, and sending emails.

Fork Notice: This is a fork of @mariozechner/gmcli by Mario Zechner with bug fixes for --reply-to thread ID handling and drafts send crash. See CHANGELOG.md for details.

Install

npm install -g @willtmc/gmcli

Setup

Before adding an account, you need OAuth2 credentials from Google Cloud Console:

  1. Create a new project (or select existing)
  2. Enable the Gmail API
  3. Set app name in OAuth branding
  4. Add test users (all Gmail addresses you want to use with gmcli)
  5. Create OAuth client:
    • Click "Create Client"
    • Application type: "Desktop app"
    • Download the JSON file

Then:

gmcli accounts credentials ~/path/to/credentials.json
gmcli accounts add you@gmail.com

Usage

gmcli accounts <action> Account management
gmcli <email> <command> [options] Gmail operations

Commands

accounts

gmcli accounts credentials <file.json># Set OAuth credentials (once)
gmcli accounts list # List configured accounts
gmcli accounts add <email># Add account (opens browser)
gmcli accounts add <email> --manual # Add account (browserless, paste redirect URL)
gmcli accounts remove <email># Remove account

search

Search threads using Gmail query syntax. Returns thread ID, date, sender, subject, and labels.

gmcli <email> search <query> [--max N] [--page TOKEN]

Query examples:

  • in:inbox, in:sent, in:drafts, in:trash, in:spam
  • is:unread, is:starred, is:important
  • from:sender@example.com, to:recipient@example.com
  • subject:keyword
  • has:attachment, filename:pdf
  • after:2024/01/01, before:2024/12/31
  • label:Work, label:UNREAD
  • Combine with spaces: in:inbox is:unread from:boss@company.com

Examples:

gmcli you@gmail.com search "in:inbox"
gmcli you@gmail.com search "is:unread" --max 50
gmcli you@gmail.com search "from:someone@example.com has:attachment"

thread

Get a thread with all messages. Shows Message-ID, headers, body, and attachments for each message.

gmcli <email> thread <threadId># View thread
gmcli <email> thread <threadId> --download # Download attachments

Attachments are saved to ~/.gmcli/attachments/.

labels

gmcli <email> labels list # List all labels (ID, name, type)
gmcli <email> labels <threadIds...> [--add L] [--remove L] # Modify labels on threads

You can use label names or IDs when modifying (names are case-insensitive).

System labels: INBOX, UNREAD, STARRED, IMPORTANT, TRASH, SPAM

Examples:

gmcli you@gmail.com labels list
gmcli you@gmail.com labels abc123 --remove UNREAD
gmcli you@gmail.com labels abc123 --add Work --remove INBOX
gmcli you@gmail.com labels abc123 def456 --add STARRED

drafts

gmcli <email> drafts list # List all drafts
gmcli <email> drafts get <draftId># View draft with attachments
gmcli <email> drafts get <draftId> --download # Download draft attachments
gmcli <email> drafts delete <draftId># Delete draft
gmcli <email> drafts send <draftId># Send draft
gmcli <email> drafts create --to <emails> --subject <s> --body <b> [options]

send

Send an email directly.

gmcli <email> send --to <emails> --subject <s> --body <b> [options]

Options for drafts create and send:

  • --to <emails> - Recipients (comma-separated, required)
  • --subject <s> - Subject line (required)
  • --body <b> - Message body (required)
  • --cc <emails> - CC recipients (comma-separated)
  • --bcc <emails> - BCC recipients (comma-separated)
  • --reply-to <messageId> - Reply to message (sets In-Reply-To/References headers and thread; accepts Gmail message ID or thread ID; canonicalizes equivalent reply subjects to Gmail's source thread subject)
  • --in-reply-to <messageId> - Alias for --reply-to
  • --thread <threadId> - Force a specific Gmail thread without setting reply headers; prefer --reply-to for normal replies
  • --attach <file> - Attach file (can be used multiple times)

Examples:

# Create draft
gmcli you@gmail.com drafts create --to a@x.com --subject "Hi" --body "Hello"# Create reply draft
gmcli you@gmail.com drafts create --to a@x.com --subject "Re: Topic" \
--body "My reply" --reply-to 19aea1f2f3532db5
# Send draft
gmcli you@gmail.com drafts send r1234567890
# Send directly
gmcli you@gmail.com send --to a@x.com --subject "Hi" --body "Hello"# Send reply with attachment
gmcli you@gmail.com send --to a@x.com --subject "Re: Topic" \
--body "See attached" --reply-to 19aea1f2f3532db5 --attach doc.pdf

url

Generate Gmail web URLs for threads. Uses canonical URL format with email parameter (works regardless of account order in browser).

gmcli <email> url <threadIds...>

Example:

gmcli you@gmail.com url 19aea1f2f3532db5 19aea1f2f3532db6

Data Storage

All data is stored in ~/.gmcli/:

  • credentials.json - OAuth client credentials
  • accounts.json - Account tokens
  • attachments/ - Downloaded attachments

Development

npm install
npm run build
npm run check

Publishing

# Update version in package.json and CHANGELOG.md
npm run build
npm publish --access public
git tag v<version>
git push --tags

License

MIT

About

Minimal Gmail CLI

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

gmcli

Minimal Gmail CLI for searching, reading threads, managing labels, drafts, and sending emails.

Fork Notice: This is a fork of @mariozechner/gmcli by Mario Zechner with bug fixes for --reply-to thread ID handling and drafts send crash. See CHANGELOG.md for details.

Install

npm install -g @willtmc/gmcli

Setup

Before adding an account, you need OAuth2 credentials from Google Cloud Console:

  1. Create a new project (or select existing)
  2. Enable the Gmail API
  3. Set app name in OAuth branding
  4. Add test users (all Gmail addresses you want to use with gmcli)
  5. Create OAuth client:
    • Click "Create Client"
    • Application type: "Desktop app"
    • Download the JSON file

Then:

gmcli accounts credentials ~/path/to/credentials.json
gmcli accounts add you@gmail.com

Usage

gmcli accounts <action> Account management
gmcli <email> <command> [options] Gmail operations

Commands

accounts

gmcli accounts credentials <file.json># Set OAuth credentials (once)
gmcli accounts list # List configured accounts
gmcli accounts add <email># Add account (opens browser)
gmcli accounts add <email> --manual # Add account (browserless, paste redirect URL)
gmcli accounts remove <email># Remove account

search

Search threads using Gmail query syntax. Returns thread ID, date, sender, subject, and labels.

gmcli <email> search <query> [--max N] [--page TOKEN]

Query examples:

  • in:inbox, in:sent, in:drafts, in:trash, in:spam
  • is:unread, is:starred, is:important
  • from:sender@example.com, to:recipient@example.com
  • subject:keyword
  • has:attachment, filename:pdf
  • after:2024/01/01, before:2024/12/31
  • label:Work, label:UNREAD
  • Combine with spaces: in:inbox is:unread from:boss@company.com

Examples:

gmcli you@gmail.com search "in:inbox"
gmcli you@gmail.com search "is:unread" --max 50
gmcli you@gmail.com search "from:someone@example.com has:attachment"

thread

Get a thread with all messages. Shows Message-ID, headers, body, and attachments for each message.

gmcli <email> thread <threadId># View thread
gmcli <email> thread <threadId> --download # Download attachments

Attachments are saved to ~/.gmcli/attachments/.

labels

gmcli <email> labels list # List all labels (ID, name, type)
gmcli <email> labels <threadIds...> [--add L] [--remove L] # Modify labels on threads

You can use label names or IDs when modifying (names are case-insensitive).

System labels: INBOX, UNREAD, STARRED, IMPORTANT, TRASH, SPAM

Examples:

gmcli you@gmail.com labels list
gmcli you@gmail.com labels abc123 --remove UNREAD
gmcli you@gmail.com labels abc123 --add Work --remove INBOX
gmcli you@gmail.com labels abc123 def456 --add STARRED

drafts

gmcli <email> drafts list # List all drafts
gmcli <email> drafts get <draftId># View draft with attachments
gmcli <email> drafts get <draftId> --download # Download draft attachments
gmcli <email> drafts delete <draftId># Delete draft
gmcli <email> drafts send <draftId># Send draft
gmcli <email> drafts create --to <emails> --subject <s> --body <b> [options]

send

Send an email directly.

gmcli <email> send --to <emails> --subject <s> --body <b> [options]

Options for drafts create and send:

  • --to <emails> - Recipients (comma-separated, required)
  • --subject <s> - Subject line (required)
  • --body <b> - Message body (required)
  • --cc <emails> - CC recipients (comma-separated)
  • --bcc <emails> - BCC recipients (comma-separated)
  • --reply-to <messageId> - Reply to message (sets In-Reply-To/References headers and thread; accepts Gmail message ID or thread ID; canonicalizes equivalent reply subjects to Gmail's source thread subject)
  • --in-reply-to <messageId> - Alias for --reply-to
  • --thread <threadId> - Force a specific Gmail thread without setting reply headers; prefer --reply-to for normal replies
  • --attach <file> - Attach file (can be used multiple times)

Examples:

# Create draft
gmcli you@gmail.com drafts create --to a@x.com --subject "Hi" --body "Hello"# Create reply draft
gmcli you@gmail.com drafts create --to a@x.com --subject "Re: Topic" \
--body "My reply" --reply-to 19aea1f2f3532db5
# Send draft
gmcli you@gmail.com drafts send r1234567890
# Send directly
gmcli you@gmail.com send --to a@x.com --subject "Hi" --body "Hello"# Send reply with attachment
gmcli you@gmail.com send --to a@x.com --subject "Re: Topic" \
--body "See attached" --reply-to 19aea1f2f3532db5 --attach doc.pdf

url

Generate Gmail web URLs for threads. Uses canonical URL format with email parameter (works regardless of account order in browser).

gmcli <email> url <threadIds...>

Example:

gmcli you@gmail.com url 19aea1f2f3532db5 19aea1f2f3532db6

Data Storage

All data is stored in ~/.gmcli/:

  • credentials.json - OAuth client credentials
  • accounts.json - Account tokens
  • attachments/ - Downloaded attachments

Development

npm install
npm run build
npm run check

Publishing

# Update version in package.json and CHANGELOG.md
npm run build
npm publish --access public
git tag v<version>
git push --tags

License

MIT

About

Minimal Gmail CLI

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

gmcli

Minimal Gmail CLI for searching, reading threads, managing labels, drafts, and sending emails.

Fork Notice: This is a fork of @mariozechner/gmcli by Mario Zechner with bug fixes for --reply-to thread ID handling and drafts send crash. See CHANGELOG.md for details.

Install

npm install -g @willtmc/gmcli

Setup

Before adding an account, you need OAuth2 credentials from Google Cloud Console:

  1. Create a new project (or select existing)
  2. Enable the Gmail API
  3. Set app name in OAuth branding
  4. Add test users (all Gmail addresses you want to use with gmcli)
  5. Create OAuth client:
    • Click "Create Client"
    • Application type: "Desktop app"
    • Download the JSON file

Then:

gmcli accounts credentials ~/path/to/credentials.json
gmcli accounts add you@gmail.com

Usage

gmcli accounts <action> Account management
gmcli <email> <command> [options] Gmail operations

Commands

accounts

gmcli accounts credentials <file.json># Set OAuth credentials (once)
gmcli accounts list # List configured accounts
gmcli accounts add <email># Add account (opens browser)
gmcli accounts add <email> --manual # Add account (browserless, paste redirect URL)
gmcli accounts remove <email># Remove account

search

Search threads using Gmail query syntax. Returns thread ID, date, sender, subject, and labels.

gmcli <email> search <query> [--max N] [--page TOKEN]

Query examples:

  • in:inbox, in:sent, in:drafts, in:trash, in:spam
  • is:unread, is:starred, is:important
  • from:sender@example.com, to:recipient@example.com
  • subject:keyword
  • has:attachment, filename:pdf
  • after:2024/01/01, before:2024/12/31
  • label:Work, label:UNREAD
  • Combine with spaces: in:inbox is:unread from:boss@company.com

Examples:

gmcli you@gmail.com search "in:inbox"
gmcli you@gmail.com search "is:unread" --max 50
gmcli you@gmail.com search "from:someone@example.com has:attachment"

thread

Get a thread with all messages. Shows Message-ID, headers, body, and attachments for each message.

gmcli <email> thread <threadId># View thread
gmcli <email> thread <threadId> --download # Download attachments

Attachments are saved to ~/.gmcli/attachments/.

labels

gmcli <email> labels list # List all labels (ID, name, type)
gmcli <email> labels <threadIds...> [--add L] [--remove L] # Modify labels on threads

You can use label names or IDs when modifying (names are case-insensitive).

System labels: INBOX, UNREAD, STARRED, IMPORTANT, TRASH, SPAM

Examples:

gmcli you@gmail.com labels list
gmcli you@gmail.com labels abc123 --remove UNREAD
gmcli you@gmail.com labels abc123 --add Work --remove INBOX
gmcli you@gmail.com labels abc123 def456 --add STARRED

drafts

gmcli <email> drafts list # List all drafts
gmcli <email> drafts get <draftId># View draft with attachments
gmcli <email> drafts get <draftId> --download # Download draft attachments
gmcli <email> drafts delete <draftId># Delete draft
gmcli <email> drafts send <draftId># Send draft
gmcli <email> drafts create --to <emails> --subject <s> --body <b> [options]

send

Send an email directly.

gmcli <email> send --to <emails> --subject <s> --body <b> [options]

Options for drafts create and send:

  • --to <emails> - Recipients (comma-separated, required)
  • --subject <s> - Subject line (required)
  • --body <b> - Message body (required)
  • --cc <emails> - CC recipients (comma-separated)
  • --bcc <emails> - BCC recipients (comma-separated)
  • --reply-to <messageId> - Reply to message (sets In-Reply-To/References headers and thread; accepts Gmail message ID or thread ID; canonicalizes equivalent reply subjects to Gmail's source thread subject)
  • --in-reply-to <messageId> - Alias for --reply-to
  • --thread <threadId> - Force a specific Gmail thread without setting reply headers; prefer --reply-to for normal replies
  • --attach <file> - Attach file (can be used multiple times)

Examples:

# Create draft
gmcli you@gmail.com drafts create --to a@x.com --subject "Hi" --body "Hello"# Create reply draft
gmcli you@gmail.com drafts create --to a@x.com --subject "Re: Topic" \
--body "My reply" --reply-to 19aea1f2f3532db5
# Send draft
gmcli you@gmail.com drafts send r1234567890
# Send directly
gmcli you@gmail.com send --to a@x.com --subject "Hi" --body "Hello"# Send reply with attachment
gmcli you@gmail.com send --to a@x.com --subject "Re: Topic" \
--body "See attached" --reply-to 19aea1f2f3532db5 --attach doc.pdf

url

Generate Gmail web URLs for threads. Uses canonical URL format with email parameter (works regardless of account order in browser).

gmcli <email> url <threadIds...>

Example:

gmcli you@gmail.com url 19aea1f2f3532db5 19aea1f2f3532db6

Data Storage

All data is stored in ~/.gmcli/:

  • credentials.json - OAuth client credentials
  • accounts.json - Account tokens
  • attachments/ - Downloaded attachments

Development

npm install
npm run build
npm run check

Publishing

# Update version in package.json and CHANGELOG.md
npm run build
npm publish --access public
git tag v<version>
git push --tags

License

MIT

About

Minimal Gmail CLI

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

gmcli

Minimal Gmail CLI for searching, reading threads, managing labels, drafts, and sending emails.

Fork Notice: This is a fork of @mariozechner/gmcli by Mario Zechner with bug fixes for --reply-to thread ID handling and drafts send crash. See CHANGELOG.md for details.

Install

npm install -g @willtmc/gmcli

Setup

Before adding an account, you need OAuth2 credentials from Google Cloud Console:

  1. Create a new project (or select existing)
  2. Enable the Gmail API
  3. Set app name in OAuth branding
  4. Add test users (all Gmail addresses you want to use with gmcli)
  5. Create OAuth client:
    • Click "Create Client"
    • Application type: "Desktop app"
    • Download the JSON file

Then:

gmcli accounts credentials ~/path/to/credentials.json
gmcli accounts add you@gmail.com

Usage

gmcli accounts <action> Account management
gmcli <email> <command> [options] Gmail operations

Commands

accounts

gmcli accounts credentials <file.json># Set OAuth credentials (once)
gmcli accounts list # List configured accounts
gmcli accounts add <email># Add account (opens browser)
gmcli accounts add <email> --manual # Add account (browserless, paste redirect URL)
gmcli accounts remove <email># Remove account

search

Search threads using Gmail query syntax. Returns thread ID, date, sender, subject, and labels.

gmcli <email> search <query> [--max N] [--page TOKEN]

Query examples:

  • in:inbox, in:sent, in:drafts, in:trash, in:spam
  • is:unread, is:starred, is:important
  • from:sender@example.com, to:recipient@example.com
  • subject:keyword
  • has:attachment, filename:pdf
  • after:2024/01/01, before:2024/12/31
  • label:Work, label:UNREAD
  • Combine with spaces: in:inbox is:unread from:boss@company.com

Examples:

gmcli you@gmail.com search "in:inbox"
gmcli you@gmail.com search "is:unread" --max 50
gmcli you@gmail.com search "from:someone@example.com has:attachment"

thread

Get a thread with all messages. Shows Message-ID, headers, body, and attachments for each message.

gmcli <email> thread <threadId># View thread
gmcli <email> thread <threadId> --download # Download attachments

Attachments are saved to ~/.gmcli/attachments/.

labels

gmcli <email> labels list # List all labels (ID, name, type)
gmcli <email> labels <threadIds...> [--add L] [--remove L] # Modify labels on threads

You can use label names or IDs when modifying (names are case-insensitive).

System labels: INBOX, UNREAD, STARRED, IMPORTANT, TRASH, SPAM

Examples:

gmcli you@gmail.com labels list
gmcli you@gmail.com labels abc123 --remove UNREAD
gmcli you@gmail.com labels abc123 --add Work --remove INBOX
gmcli you@gmail.com labels abc123 def456 --add STARRED

drafts

gmcli <email> drafts list # List all drafts
gmcli <email> drafts get <draftId># View draft with attachments
gmcli <email> drafts get <draftId> --download # Download draft attachments
gmcli <email> drafts delete <draftId># Delete draft
gmcli <email> drafts send <draftId># Send draft
gmcli <email> drafts create --to <emails> --subject <s> --body <b> [options]

send

Send an email directly.

gmcli <email> send --to <emails> --subject <s> --body <b> [options]

Options for drafts create and send:

  • --to <emails> - Recipients (comma-separated, required)
  • --subject <s> - Subject line (required)
  • --body <b> - Message body (required)
  • --cc <emails> - CC recipients (comma-separated)
  • --bcc <emails> - BCC recipients (comma-separated)
  • --reply-to <messageId> - Reply to message (sets In-Reply-To/References headers and thread; accepts Gmail message ID or thread ID; canonicalizes equivalent reply subjects to Gmail's source thread subject)
  • --in-reply-to <messageId> - Alias for --reply-to
  • --thread <threadId> - Force a specific Gmail thread without setting reply headers; prefer --reply-to for normal replies
  • --attach <file> - Attach file (can be used multiple times)

Examples:

# Create draft
gmcli you@gmail.com drafts create --to a@x.com --subject "Hi" --body "Hello"# Create reply draft
gmcli you@gmail.com drafts create --to a@x.com --subject "Re: Topic" \
--body "My reply" --reply-to 19aea1f2f3532db5
# Send draft
gmcli you@gmail.com drafts send r1234567890
# Send directly
gmcli you@gmail.com send --to a@x.com --subject "Hi" --body "Hello"# Send reply with attachment
gmcli you@gmail.com send --to a@x.com --subject "Re: Topic" \
--body "See attached" --reply-to 19aea1f2f3532db5 --attach doc.pdf

url

Generate Gmail web URLs for threads. Uses canonical URL format with email parameter (works regardless of account order in browser).

gmcli <email> url <threadIds...>

Example:

gmcli you@gmail.com url 19aea1f2f3532db5 19aea1f2f3532db6

Data Storage

All data is stored in ~/.gmcli/:

  • credentials.json - OAuth client credentials
  • accounts.json - Account tokens
  • attachments/ - Downloaded attachments

Development

npm install
npm run build
npm run check

Publishing

# Update version in package.json and CHANGELOG.md
npm run build
npm publish --access public
git tag v<version>
git push --tags

License

MIT

About

Minimal Gmail CLI

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

gmcli

Minimal Gmail CLI for searching, reading threads, managing labels, drafts, and sending emails.

Fork Notice: This is a fork of @mariozechner/gmcli by Mario Zechner with bug fixes for --reply-to thread ID handling and drafts send crash. See CHANGELOG.md for details.

Install

npm install -g @willtmc/gmcli

Setup

Before adding an account, you need OAuth2 credentials from Google Cloud Console:

  1. Create a new project (or select existing)
  2. Enable the Gmail API
  3. Set app name in OAuth branding
  4. Add test users (all Gmail addresses you want to use with gmcli)
  5. Create OAuth client:
    • Click "Create Client"
    • Application type: "Desktop app"
    • Download the JSON file

Then:

gmcli accounts credentials ~/path/to/credentials.json
gmcli accounts add you@gmail.com

Usage

gmcli accounts <action> Account management
gmcli <email> <command> [options] Gmail operations

Commands

accounts

gmcli accounts credentials <file.json># Set OAuth credentials (once)
gmcli accounts list # List configured accounts
gmcli accounts add <email># Add account (opens browser)
gmcli accounts add <email> --manual # Add account (browserless, paste redirect URL)
gmcli accounts remove <email># Remove account

search

Search threads using Gmail query syntax. Returns thread ID, date, sender, subject, and labels.

gmcli <email> search <query> [--max N] [--page TOKEN]

Query examples:

  • in:inbox, in:sent, in:drafts, in:trash, in:spam
  • is:unread, is:starred, is:important
  • from:sender@example.com, to:recipient@example.com
  • subject:keyword
  • has:attachment, filename:pdf
  • after:2024/01/01, before:2024/12/31
  • label:Work, label:UNREAD
  • Combine with spaces: in:inbox is:unread from:boss@company.com

Examples:

gmcli you@gmail.com search "in:inbox"
gmcli you@gmail.com search "is:unread" --max 50
gmcli you@gmail.com search "from:someone@example.com has:attachment"

thread

Get a thread with all messages. Shows Message-ID, headers, body, and attachments for each message.

gmcli <email> thread <threadId># View thread
gmcli <email> thread <threadId> --download # Download attachments

Attachments are saved to ~/.gmcli/attachments/.

labels

gmcli <email> labels list # List all labels (ID, name, type)
gmcli <email> labels <threadIds...> [--add L] [--remove L] # Modify labels on threads

You can use label names or IDs when modifying (names are case-insensitive).

System labels: INBOX, UNREAD, STARRED, IMPORTANT, TRASH, SPAM

Examples:

gmcli you@gmail.com labels list
gmcli you@gmail.com labels abc123 --remove UNREAD
gmcli you@gmail.com labels abc123 --add Work --remove INBOX
gmcli you@gmail.com labels abc123 def456 --add STARRED

drafts

gmcli <email> drafts list # List all drafts
gmcli <email> drafts get <draftId># View draft with attachments
gmcli <email> drafts get <draftId> --download # Download draft attachments
gmcli <email> drafts delete <draftId># Delete draft
gmcli <email> drafts send <draftId># Send draft
gmcli <email> drafts create --to <emails> --subject <s> --body <b> [options]

send

Send an email directly.

gmcli <email> send --to <emails> --subject <s> --body <b> [options]

Options for drafts create and send:

  • --to <emails> - Recipients (comma-separated, required)
  • --subject <s> - Subject line (required)
  • --body <b> - Message body (required)
  • --cc <emails> - CC recipients (comma-separated)
  • --bcc <emails> - BCC recipients (comma-separated)
  • --reply-to <messageId> - Reply to message (sets In-Reply-To/References headers and thread; accepts Gmail message ID or thread ID; canonicalizes equivalent reply subjects to Gmail's source thread subject)
  • --in-reply-to <messageId> - Alias for --reply-to
  • --thread <threadId> - Force a specific Gmail thread without setting reply headers; prefer --reply-to for normal replies
  • --attach <file> - Attach file (can be used multiple times)

Examples:

# Create draft
gmcli you@gmail.com drafts create --to a@x.com --subject "Hi" --body "Hello"# Create reply draft
gmcli you@gmail.com drafts create --to a@x.com --subject "Re: Topic" \
--body "My reply" --reply-to 19aea1f2f3532db5
# Send draft
gmcli you@gmail.com drafts send r1234567890
# Send directly
gmcli you@gmail.com send --to a@x.com --subject "Hi" --body "Hello"# Send reply with attachment
gmcli you@gmail.com send --to a@x.com --subject "Re: Topic" \
--body "See attached" --reply-to 19aea1f2f3532db5 --attach doc.pdf

url

Generate Gmail web URLs for threads. Uses canonical URL format with email parameter (works regardless of account order in browser).

gmcli <email> url <threadIds...>

Example:

gmcli you@gmail.com url 19aea1f2f3532db5 19aea1f2f3532db6

Data Storage

All data is stored in ~/.gmcli/:

  • credentials.json - OAuth client credentials
  • accounts.json - Account tokens
  • attachments/ - Downloaded attachments

Development

npm install
npm run build
npm run check

Publishing

# Update version in package.json and CHANGELOG.md
npm run build
npm publish --access public
git tag v<version>
git push --tags

License

MIT

About

Minimal Gmail CLI

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

gmcli

Minimal Gmail CLI for searching, reading threads, managing labels, drafts, and sending emails.

Fork Notice: This is a fork of @mariozechner/gmcli by Mario Zechner with bug fixes for --reply-to thread ID handling and drafts send crash. See CHANGELOG.md for details.

Install

npm install -g @willtmc/gmcli

Setup

Before adding an account, you need OAuth2 credentials from Google Cloud Console:

  1. Create a new project (or select existing)
  2. Enable the Gmail API
  3. Set app name in OAuth branding
  4. Add test users (all Gmail addresses you want to use with gmcli)
  5. Create OAuth client:
    • Click "Create Client"
    • Application type: "Desktop app"
    • Download the JSON file

Then:

gmcli accounts credentials ~/path/to/credentials.json
gmcli accounts add you@gmail.com

Usage

gmcli accounts <action> Account management
gmcli <email> <command> [options] Gmail operations

Commands

accounts

gmcli accounts credentials <file.json># Set OAuth credentials (once)
gmcli accounts list # List configured accounts
gmcli accounts add <email># Add account (opens browser)
gmcli accounts add <email> --manual # Add account (browserless, paste redirect URL)
gmcli accounts remove <email># Remove account

search

Search threads using Gmail query syntax. Returns thread ID, date, sender, subject, and labels.

gmcli <email> search <query> [--max N] [--page TOKEN]

Query examples:

  • in:inbox, in:sent, in:drafts, in:trash, in:spam
  • is:unread, is:starred, is:important
  • from:sender@example.com, to:recipient@example.com
  • subject:keyword
  • has:attachment, filename:pdf
  • after:2024/01/01, before:2024/12/31
  • label:Work, label:UNREAD
  • Combine with spaces: in:inbox is:unread from:boss@company.com

Examples:

gmcli you@gmail.com search "in:inbox"
gmcli you@gmail.com search "is:unread" --max 50
gmcli you@gmail.com search "from:someone@example.com has:attachment"

thread

Get a thread with all messages. Shows Message-ID, headers, body, and attachments for each message.

gmcli <email> thread <threadId># View thread
gmcli <email> thread <threadId> --download # Download attachments

Attachments are saved to ~/.gmcli/attachments/.

labels

gmcli <email> labels list # List all labels (ID, name, type)
gmcli <email> labels <threadIds...> [--add L] [--remove L] # Modify labels on threads

You can use label names or IDs when modifying (names are case-insensitive).

System labels: INBOX, UNREAD, STARRED, IMPORTANT, TRASH, SPAM

Examples:

gmcli you@gmail.com labels list
gmcli you@gmail.com labels abc123 --remove UNREAD
gmcli you@gmail.com labels abc123 --add Work --remove INBOX
gmcli you@gmail.com labels abc123 def456 --add STARRED

drafts

gmcli <email> drafts list # List all drafts
gmcli <email> drafts get <draftId># View draft with attachments
gmcli <email> drafts get <draftId> --download # Download draft attachments
gmcli <email> drafts delete <draftId># Delete draft
gmcli <email> drafts send <draftId># Send draft
gmcli <email> drafts create --to <emails> --subject <s> --body <b> [options]

send

Send an email directly.

gmcli <email> send --to <emails> --subject <s> --body <b> [options]

Options for drafts create and send:

  • --to <emails> - Recipients (comma-separated, required)
  • --subject <s> - Subject line (required)
  • --body <b> - Message body (required)
  • --cc <emails> - CC recipients (comma-separated)
  • --bcc <emails> - BCC recipients (comma-separated)
  • --reply-to <messageId> - Reply to message (sets In-Reply-To/References headers and thread; accepts Gmail message ID or thread ID; canonicalizes equivalent reply subjects to Gmail's source thread subject)
  • --in-reply-to <messageId> - Alias for --reply-to
  • --thread <threadId> - Force a specific Gmail thread without setting reply headers; prefer --reply-to for normal replies
  • --attach <file> - Attach file (can be used multiple times)

Examples:

# Create draft
gmcli you@gmail.com drafts create --to a@x.com --subject "Hi" --body "Hello"# Create reply draft
gmcli you@gmail.com drafts create --to a@x.com --subject "Re: Topic" \
--body "My reply" --reply-to 19aea1f2f3532db5
# Send draft
gmcli you@gmail.com drafts send r1234567890
# Send directly
gmcli you@gmail.com send --to a@x.com --subject "Hi" --body "Hello"# Send reply with attachment
gmcli you@gmail.com send --to a@x.com --subject "Re: Topic" \
--body "See attached" --reply-to 19aea1f2f3532db5 --attach doc.pdf

url

Generate Gmail web URLs for threads. Uses canonical URL format with email parameter (works regardless of account order in browser).

gmcli <email> url <threadIds...>

Example:

gmcli you@gmail.com url 19aea1f2f3532db5 19aea1f2f3532db6

Data Storage

All data is stored in ~/.gmcli/:

  • credentials.json - OAuth client credentials
  • accounts.json - Account tokens
  • attachments/ - Downloaded attachments

Development

npm install
npm run build
npm run check

Publishing

# Update version in package.json and CHANGELOG.md
npm run build
npm publish --access public
git tag v<version>
git push --tags

License

MIT

About

Minimal Gmail CLI

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

gmcli

Minimal Gmail CLI for searching, reading threads, managing labels, drafts, and sending emails.

Fork Notice: This is a fork of @mariozechner/gmcli by Mario Zechner with bug fixes for --reply-to thread ID handling and drafts send crash. See CHANGELOG.md for details.

Install

npm install -g @willtmc/gmcli

Setup

Before adding an account, you need OAuth2 credentials from Google Cloud Console:

  1. Create a new project (or select existing)
  2. Enable the Gmail API
  3. Set app name in OAuth branding
  4. Add test users (all Gmail addresses you want to use with gmcli)
  5. Create OAuth client:
    • Click "Create Client"
    • Application type: "Desktop app"
    • Download the JSON file

Then:

gmcli accounts credentials ~/path/to/credentials.json
gmcli accounts add you@gmail.com

Usage

gmcli accounts <action> Account management
gmcli <email> <command> [options] Gmail operations

Commands

accounts

gmcli accounts credentials <file.json># Set OAuth credentials (once)
gmcli accounts list # List configured accounts
gmcli accounts add <email># Add account (opens browser)
gmcli accounts add <email> --manual # Add account (browserless, paste redirect URL)
gmcli accounts remove <email># Remove account

search

Search threads using Gmail query syntax. Returns thread ID, date, sender, subject, and labels.

gmcli <email> search <query> [--max N] [--page TOKEN]

Query examples:

  • in:inbox, in:sent, in:drafts, in:trash, in:spam
  • is:unread, is:starred, is:important
  • from:sender@example.com, to:recipient@example.com
  • subject:keyword
  • has:attachment, filename:pdf
  • after:2024/01/01, before:2024/12/31
  • label:Work, label:UNREAD
  • Combine with spaces: in:inbox is:unread from:boss@company.com

Examples:

gmcli you@gmail.com search "in:inbox"
gmcli you@gmail.com search "is:unread" --max 50
gmcli you@gmail.com search "from:someone@example.com has:attachment"

thread

Get a thread with all messages. Shows Message-ID, headers, body, and attachments for each message.

gmcli <email> thread <threadId># View thread
gmcli <email> thread <threadId> --download # Download attachments

Attachments are saved to ~/.gmcli/attachments/.

labels

gmcli <email> labels list # List all labels (ID, name, type)
gmcli <email> labels <threadIds...> [--add L] [--remove L] # Modify labels on threads

You can use label names or IDs when modifying (names are case-insensitive).

System labels: INBOX, UNREAD, STARRED, IMPORTANT, TRASH, SPAM

Examples:

gmcli you@gmail.com labels list
gmcli you@gmail.com labels abc123 --remove UNREAD
gmcli you@gmail.com labels abc123 --add Work --remove INBOX
gmcli you@gmail.com labels abc123 def456 --add STARRED

drafts

gmcli <email> drafts list # List all drafts
gmcli <email> drafts get <draftId># View draft with attachments
gmcli <email> drafts get <draftId> --download # Download draft attachments
gmcli <email> drafts delete <draftId># Delete draft
gmcli <email> drafts send <draftId># Send draft
gmcli <email> drafts create --to <emails> --subject <s> --body <b> [options]

send

Send an email directly.

gmcli <email> send --to <emails> --subject <s> --body <b> [options]

Options for drafts create and send:

  • --to <emails> - Recipients (comma-separated, required)
  • --subject <s> - Subject line (required)
  • --body <b> - Message body (required)
  • --cc <emails> - CC recipients (comma-separated)
  • --bcc <emails> - BCC recipients (comma-separated)
  • --reply-to <messageId> - Reply to message (sets In-Reply-To/References headers and thread; accepts Gmail message ID or thread ID; canonicalizes equivalent reply subjects to Gmail's source thread subject)
  • --in-reply-to <messageId> - Alias for --reply-to
  • --thread <threadId> - Force a specific Gmail thread without setting reply headers; prefer --reply-to for normal replies
  • --attach <file> - Attach file (can be used multiple times)

Examples:

# Create draft
gmcli you@gmail.com drafts create --to a@x.com --subject "Hi" --body "Hello"# Create reply draft
gmcli you@gmail.com drafts create --to a@x.com --subject "Re: Topic" \
--body "My reply" --reply-to 19aea1f2f3532db5
# Send draft
gmcli you@gmail.com drafts send r1234567890
# Send directly
gmcli you@gmail.com send --to a@x.com --subject "Hi" --body "Hello"# Send reply with attachment
gmcli you@gmail.com send --to a@x.com --subject "Re: Topic" \
--body "See attached" --reply-to 19aea1f2f3532db5 --attach doc.pdf

url

Generate Gmail web URLs for threads. Uses canonical URL format with email parameter (works regardless of account order in browser).

gmcli <email> url <threadIds...>

Example:

gmcli you@gmail.com url 19aea1f2f3532db5 19aea1f2f3532db6

Data Storage

All data is stored in ~/.gmcli/:

  • credentials.json - OAuth client credentials
  • accounts.json - Account tokens
  • attachments/ - Downloaded attachments

Development

npm install
npm run build
npm run check

Publishing

# Update version in package.json and CHANGELOG.md
npm run build
npm publish --access public
git tag v<version>
git push --tags

License

MIT

About

Minimal Gmail CLI

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages