Skip to content

Gmail: multi-account support - #259

Open
hilash wants to merge 2 commits into
fix/gmail-setup-guide-and-decryptfrom
feat/gmail-multi-account
Open

Gmail: multi-account support#259
hilash wants to merge 2 commits into
fix/gmail-setup-guide-and-decryptfrom
feat/gmail-multi-account

Conversation

@hilash

@hilash hilash commented Jul 18, 2026

Copy link
Copy Markdown
Collaborator

What

Gmail integration now supports connecting multiple accounts simultaneously. Stacked on #258 (base branch); retargets to main automatically when that merges.

Storage

  • gmail_credentials rows are keyed by lowercased email instead of the single 'default' row. Migration 005_gmail_multi_account.sql rewrites the existing row in place.
  • gmail_index gains an account column ('' = pre-migration rows).

Back-compat by construction

Every imap-client function (searchEmails, readThread, listLabels, createLabel, applyLabel, getUnread) takes an optional account (email). Omitted = the first-connected account (ORDER BY rowid), so single-account installs and existing consumers — Mailroom, the Gmail skill, anything calling the routes without an account — keep working with zero changes.

API

  • GET /api/gmail/search|thread/:id|labels accept ?account=; POST /api/gmail/label|labels|index accept body.account.
  • POST /api/gmail/connect keys the row by email — each connect adds or refreshes one account without touching others.
  • DELETE /api/gmail/disconnect?account=x removes one account; no param removes all (pre-multi-account behavior). The Gmail skill is only uninstalled when no accounts remain.
  • GET /api/gmail/status returns accounts: [{email, needsReconnect, lastIndexed}] while keeping the old top-level shape (describing the primary account) for existing consumers.

UI

GmailSection shows per-account rows — green when healthy, amber "Reconnect needed" with a pre-filling Re-enter link when the stored password can't be decrypted — each with its own disconnect button, plus an "Add another account" flow.

Verification

  • npx tsc --noEmit clean; npm run lint 0 errors; crypto tests 3/3
  • Live on the dev server (migration applied): status lists the existing account with per-account needsReconnect; search with an unknown account returns Gmail account X not connected; scoped disconnect of an unknown account no-ops without touching real accounts

🤖 Generated with Claude Code

- gmail_credentials keyed by lowercased email (migration 005 migrates the
  'default' row in place); gmail_index gains an account column.
- imap-client functions take an optional account; omitted = the
  first-connected account, so existing consumers work unchanged.
- Routes accept ?account= / body.account; disconnect without a param
  removes everything (old behavior) and the Gmail skill is only
  uninstalled when no accounts remain.
- /api/gmail/status returns accounts[] with per-account needsReconnect
  and lastIndexed, keeping the old top-level shape for the primary
  account.
- GmailSection lists accounts with per-account disconnect/reconnect and
  an 'Add another account' flow.
@hilash
hilash requested a review from a team as a code owner July 18, 2026 18:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant