multi-email
Provides access to Gmail accounts for searching, reading, drafting, archiving, managing read state, and sending emails through independently authorized aliases.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@multi-email@multi-email find unread emails from my boss in work and draft a thank you reply"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Multi Email
Multi Email is an open-source Codex plugin and MCP server for independently authorized Gmail and Microsoft 365 mailboxes. Every operation names an explicit account_alias; there is no implicit active mailbox.
It supports searching, reading, drafting, archiving, read-state changes, Gmail labels, Microsoft categories, and sending through a server-enforced localhost review window.
Developer Preview — bring your own OAuth applications. Multi Email is intended for technical users who can configure provider applications and inspect account-by-account diagnostics. The release contains no shared Google OAuth client and is not a one-click Gmail connection or a way to bypass Google consent, verification, organization, or account policy.
Release status:
0.1.5is official only when installed from the annotatedv0.1.5tag or matching GitHub release underlanfuli/multi-email. Thecodex-multi-emailnpm package is not yet published; verify the repository owner and release tag before installation.
Why this exists
Most email integrations assume one active account. Multi Email keeps routing explicit so a request can cover several independently authorized accounts without mixing message IDs, drafts, labels, or credentials.
Codex task
-> Multi Email skill and MCP tools
-> local Node.js MCP process
-> Gmail API or Microsoft Graph
OAuth tokens -> macOS Keychain
Account aliases and OAuth app settings -> local mode-0600 config
Mailbox content returned by tools -> Codex conversation/model contextThe MCP process and credential store run on the Mac, but the end-to-end workflow is not necessarily local-only. Prompts and tool results, including selected mail content, may be processed by Codex/OpenAI according to the user's product, account, and data-control settings. Google and Microsoft also process provider API traffic. See Security, privacy, and data flow.
Related MCP server: Gmail Multi-Inbox MCP Server
Safety model
Every operation requires an explicit
account_alias.Reads are the skill default; mutations require a current, explicit user request.
Permanent deletion is not exposed.
Email bodies, attachments, quoted text, signatures, and links are treated as untrusted data, never as tool instructions.
Search, write-batch, recipient, body, and provider-response sizes are bounded; oversized Gmail, Microsoft identity, and Graph responses are rejected and abandoned at the transport boundary before application parsing.
Every MCP tool handler has one 108-second budget below the host's 120-second timeout. Provider HTTP calls receive the remaining timeout and an abort signal when supported; an SDK promise that cannot be cancelled is abandoned by the handler at the deadline but may settle later in the background. A timeout before send dispatch is reported as definitely unsent; after dispatch it is an unknown delivery result and is never retried automatically.
Microsoft batch mutations distinguish completed IDs, definite failures, in-flight unknown outcomes, and untouched remaining IDs so callers do not replay from an inaccurate receipt.
Sending is blocked until the user reviews the complete supported plain-text draft in a
127.0.0.1window and clicks Approve.A short-lived
approval_request_idis bound to an effective-send manifest: authenticated principal, mailbox, effective sender identity, draft and thread identity, every recipient, subject, complete body, provider revision, and the verified absence of attachments. Approval expires, is one-use, and is invalidated by any bound change.Version
0.1.5verifies the installed release manifest, every artifact hash and lazy chunk, the CommonJS package boundary, and the current-architecture Keychain runtime before starting. A damaged production install fails as a runtime error and never silently falls back to source or asks users to replace healthy credentials.Provider drafts containing HTML, multipart or unknown MIME, inline content, attachments, a malformed mailbox address, an unsupported From/Sender/Reply-To identity, or an incomplete provider revision fail closed before review or send.
The provider send request is built from the approved allowlisted plain-text fields. Gmail supplies that frozen raw message in the draft-send request; Microsoft uses one MIME
sendMailrequest instead of sending a mutable provider draft.No MCP tool can approve its own send request.
A send is never automatically retried after an ambiguous result because the provider may already have accepted it.
Provider HTTP redirects are rejected, preventing a 307/308 from automatically replaying a mutation, send, or token POST body.
These controls reduce accidental and prompt-injected actions; they do not make OAuth tokens read-only. Google gmail.modify and Microsoft Mail.ReadWrite plus Mail.Send grant material mailbox access.
Supported operations
Area | Gmail | Microsoft 365 |
Account identity check | Yes | Yes |
Credential, token, scope, and identity diagnosis | One alias or all, without reading mail | One alias or all, without reading mail |
Provider-native search and message read | Yes | Yes |
New and reply drafts | Yes | Yes |
Draft update | Yes | Yes |
Archive and read/unread | Yes | Yes |
Labels/categories | List and modify label IDs | Modify an exact known category name |
Human-reviewed frozen send | Local full-review window | Local full-review window; source draft is retained |
The plugin does not intentionally call provider attachment-content endpoints, expose attachment contents through MCP, permanently delete mail, operate calendars, expose arbitrary provider APIs, or automatically enable send-as aliases, delegated identities, or shared mailboxes. Gmail format=full responses can still deliver small inline MIME-part bytes to the local process; they are not returned by the tool. Message reads expose attachment names only. Drafts created by the plugin are plain text. Provider drafts containing HTML, inline content, attachments, malformed mailbox addresses, or unsupported identities cannot pass the send-review gate.
Search queries are provider-native: Gmail search syntax for Google and Microsoft Graph mail search syntax for Microsoft 365.
mail_list_accounts reports whether a local credential exists with credentialPresent and connectionStatus (credential_present_unverified or not_authorized). Those fields are not authentication claims. Use mail_diagnose_accounts to verify current token, scope, and provider-identity health.
Requirements
macOS on Apple Silicon or Intel
Node.js 22 or newer
Codex desktop or CLI with local stdio MCP and plugin support
A user-owned Google Cloud Desktop OAuth client with Gmail API enabled for Gmail accounts
A Microsoft Entra public-client application for Microsoft 365 accounts
The committed dist/ bundle contains its JavaScript dependencies and both macOS Keychain native binaries, so a Git marketplace snapshot can start without a committed node_modules/ directory. Development and npm-library imports still use normal npm dependencies.
Install from GitHub
The most transparent install is a local clone:
git clone https://github.com/lanfuli/multi-email.git
cd multi-email
git checkout --detach v0.1.5
node ./scripts/multi-email self-test
codex plugin marketplace add "$(pwd)"
codex plugin add multi-email@multi-emailself-test verifies the release bundle without reading config, Keychain, provider state, or mail. Start a new Codex task after installation so the skill and MCP tools are discovered, then call mail_get_runtime_info to confirm that the running MCP process reports the expected version and a verified build.
Codex also accepts a Git marketplace source once the repository exists:
codex plugin marketplace add lanfuli/multi-email --ref v0.1.5
codex plugin add multi-email@multi-emailThe explicit --ref keeps the installed snapshot on the reviewed release instead of the moving default branch. The repo marketplace entry uses the documented repo-root local source ("./"). The current documented Codex marketplace schema also has URL, git-subdir, and npm source forms; this repo does not use an npm source because no npm publication has occurred.
The marketplace installs the plugin skill and MCP server; it does not place the setup CLI on your shell PATH. The setup examples below therefore run from the matching reviewed local clone. A future npm installation can use the equivalent multi-email ... binary directly; do not run npm run setup from a consuming project.
Recommended guided setup (optional)
Computer Use can optionally guide the Google Cloud Console steps in the user's browser. It is a separate Codex plugin, not a Multi Email dependency. Install and enable it from Codex Plugins, turn on its server and skill toggles, and grant the documented macOS Screen Recording and Accessibility permissions; if it is unavailable or the user prefers not to grant browser control, follow the manual Google OAuth guide instead.
For the Google Auth Platform Desktop client used by this Gmail workflow, Google's supported setup is the Cloud Console rather than an API. IAM/IAP OAuth-client APIs are a different product surface and do not create this Gmail Desktop client. Computer Use can navigate and explain the page, but it cannot provision a client behind the user's back. See Google's OAuth best practices.
Paste this into a new Codex task after installing Multi Email and, for browser guidance, Computer Use:
Use $multi-email to set up my user-owned Google Cloud Desktop OAuth client, using Computer Use if available, then connect my requested Gmail aliases one at a time. Follow the assisted onboarding confirmation and credential-handling safeguards.
The user—not Computer Use or Multi Email—makes the publishing, credential-creation, legal, and Gmail-consent decisions. Computer Use stops before Create; the user clicks it, downloads the credential, and closes the dialog before returning control. Provide only the downloaded file's local path; Computer Use must not inspect, copy, or repeat any credential value. Guided setup does not change the Developer Preview or BYO OAuth boundaries above. For an External app, the guide also explains the seven-day Testing limit versus In production and asks before changing publishing status; it never treats Production as verification or submits legal/compliance claims automatically.
Configure OAuth
Run the non-interactive, read-only preflight first. It does not open a browser, read Keychain, or contact an email provider:
node ./scripts/multi-email setupFor the provider-side setup, follow the detailed Google OAuth guide or Microsoft Entra guide. Both use OAuth applications you control; the release package contains no shared Google client or maintainer-owned authorization fallback. Do not share client files, authorization URLs, codes, or tokens.
One Multi Email config has one Google OAuth client. Every Google alias in that config uses that same client, while each mailbox still receives and stores its own authorization. This intentionally keeps the connection model simple; it does not support selecting a different Google Cloud project per alias inside one config.
Importing the Desktop JSON stores its client ID and client secret in Multi Email's mode-0600 local
config; mailbox tokens are stored in macOS Keychain. The CLI does not delete the downloaded JSON.
After initialization and successful per-alias diagnosis, move it to an owner-only private location
or delete it yourself if you no longer want the extra copy; Multi Email never does that automatically.
The default config path is:
~/.config/codex-multi-email/config.jsonSet CODEX_MULTI_EMAIL_CONFIG to use another absolute path. The setup CLI creates a missing config directory with mode 0700, leaves an existing parent directory's permissions unchanged, writes the config file with mode 0600, and refuses a config target that is a symlink or non-regular file.
Initialize either provider independently, or supply both provider settings in one command.
Google only:
node ./scripts/multi-email init \
--google-client-json /absolute/path/to/desktop-oauth.jsonMicrosoft only:
node ./scripts/multi-email init \
--microsoft-client-id <entra-application-client-id> \
--microsoft-tenant organizationsBoth providers:
node ./scripts/multi-email init \
--google-client-json /absolute/path/to/desktop-oauth.json \
--microsoft-client-id <entra-application-client-id> \
--microsoft-tenant organizationsReplace an existing Google client
Changing the Google client affects every Google alias in the config. Schedule a maintenance window: the client setting changes before the aliases are reauthorized, so the migration is not one atomic all-account transaction.
Import the replacement Desktop client only when you intend to migrate the complete Google profile:
node ./scripts/multi-email init \
--google-client-json /absolute/private/path/to/replacement-desktop-client.json \
--confirm--confirm is required only when the imported Google client ID differs from the configured client.
It is not required for the first Google setup or when the same client is imported again.
Do not begin by running logout, revoke, deleting Keychain items, or removing aliases. Those
actions reduce the available recovery options without making the new client more likely to work.
After the client changes, reauthorize and diagnose every existing Google alias separately:
node ./scripts/multi-email auth <google-alias> --browser <default|safari|chrome> --force
node ./scripts/multi-email doctor <google-alias> --jsonRepeat those two commands for each Google alias, one at a time. The migration is complete only when
each one reports status=ok with credential, token, scope, and identity checks true. If migration
stops partway through, do not assume that restoring either client will restore the whole group:
credentials already replaced belong to the new client, while untouched credentials belong to the
old client. Restore deliberately and rerun doctor for every alias; there is no automatic
whole-profile rollback.
To add or replace Microsoft settings later:
node ./scripts/multi-email set-microsoft-client <entra-application-client-id> \
--microsoft-tenant organizationsAdd and authorize each mailbox independently. Choose the browser explicitly when browser session state matters; the allowed values are default, safari, and chrome:
node ./scripts/multi-email add-account gmail-01 <gmail-address> google
node ./scripts/multi-email auth gmail-01 --browser safari
node ./scripts/multi-email add-account m365-main <microsoft-365-address> microsoft
node ./scripts/multi-email auth m365-main --browser chrome
node ./scripts/multi-email list
node ./scripts/multi-email doctor
node ./scripts/multi-email doctor --jsonAuthorization starts with a local preflight that displays the exact alias, expected mailbox, provider, browser, requested scopes, and existing health. An alias whose credential, token, scopes, and identity are already healthy is skipped by default; use --force only when you intentionally want to replace that healthy authorization.
After the browser flow, run doctor for the same alias. Its human table shows both the configured EXPECTED EMAIL and a VERIFIED EMAIL; the latter is populated only after the credential, token, scopes, and provider identity all pass. doctor --json and mail_diagnose_accounts return the same allowlisted per-alias health record and safe next_step. One alias failing diagnosis does not hide the other aliases. The developer or support email shown on a Google consent screen identifies the OAuth application, not the mailbox being connected.
Credential replacement is verified as a Keychain transaction. If writing or reading back a new credential fails, Multi Email restores and verifies the previous value (or removes an unverifiable first value). CREDENTIAL_ROLLBACK_FAILED means the final Keychain state could not be confirmed; stop and inspect that alias instead of retrying OAuth.
Use placeholders only in documentation; do not commit real addresses, OAuth client JSON, generated config, authorization URLs, codes, or tokens.
Google OAuth
Google authorization requests openid, email, and gmail.modify through a loopback Desktop OAuth
flow with PKCE and explicit account selection. Token info must belong to the configured Google
client and contain the required scopes, the returned Gmail profile must exactly match the configured
address, and the Keychain write must be read back before success is reported.
See Configure Google OAuth for Gmail for the current Cloud Console checklist and common blockers.
Google classifies gmail.modify as a restricted scope. For an External app in Testing, Google
states that test-user authorizations expire seven days after consent, including an offline refresh
token; that mode is therefore unsuitable for a durable connection. See Google's
app-audience documentation. Moving an app to
Production changes the Testing lifecycle but does not make it verified, remove every warning, or
override account and organization policy.
Bring-your-own OAuth credentials do not exempt an app or user from Google's verification, consent-screen, test-user, restricted-scope, organization, quota, retention, or user-data requirements.
Microsoft OAuth
Microsoft authorization uses MSAL system-browser interactive authorization and requests delegated User.Read, Mail.ReadWrite, and Mail.Send. The /me profile must match the configured identity and the Keychain write must be verified before success is reported. Tenant policy or administrator consent can block these scopes.
See Configure Microsoft Entra for Microsoft 365 mail for the exact desktop redirect and delegated-permission setup.
Use in Codex
Always name the account alias:
“Use
gmail-01to find unread messages from the last two days.”“Across
gmail-01andm365-main, summarize messages that need my reply without making changes.”“Create a reply draft in
m365-main; do not send it.”“Diagnose all configured accounts without reading or changing mail.”
For a send:
Ask Codex to prepare the selected draft for review.
Inspect the authenticated identity, effective From/Sender/Reply-To, every recipient, subject, threading headers, format, attachment status, and complete plain-text body in the localhost window opened by the MCP server.
Click Approve or Reject in that window.
Return to Codex and explicitly confirm that the local review is complete.
The server rebuilds the effective-send manifest, spends the one-use approval, rechecks the provider revision, and freezes the approved allowlisted fields into one send request.
A Microsoft frozen send intentionally retains the original source draft because Graph's existing-draft send action has no conditional revision guard. Check the result field
sourceDraftRetained; do not send that retained draft again without a new review.
Do not paste the local review URL, cookies, nonces, fingerprints, OAuth values, or Keychain contents into Codex or an issue.
Update
For a local clone marketplace:
git fetch origin --tags
git checkout --detach v0.1.5
codex plugin add multi-email@multi-emailReplace v0.1.5 only with a newer annotated release tag that you have reviewed. A Git marketplace installed with --ref stays pinned, so move it to a new release explicitly:
codex plugin remove multi-email@multi-email
codex plugin marketplace remove multi-email
codex plugin marketplace add lanfuli/multi-email --ref v0.1.5
codex plugin add multi-email@multi-emailStart a new Codex task after reinstalling. Verify the new checkout with node ./scripts/multi-email self-test, confirm the live MCP build with mail_get_runtime_info, and then run doctor for each alias. Do not reauthorize an account merely because a previous damaged runtime reported a token error.
Uninstall and remove local data
Remove the plugin and marketplace:
codex plugin remove multi-email@multi-email
codex plugin marketplace remove multi-emailPlugin removal does not delete OAuth credentials or config. Prefer the guarded lifecycle commands before deleting the clone:
node ./scripts/multi-email logout <alias> --confirm
node ./scripts/multi-email revoke <alias> --confirmlogout removes local credentials. revoke also attempts provider-side revocation where the provider safely supports it; Microsoft may require removal through Microsoft My Apps followed by logout. Inspect the command result rather than assuming provider revocation succeeded.
Current Keychain items use service io.github.lanfuli.multi-email. Historical installations may also have verified legacy items under com.openai.codex.multi-email; the credential store migrates only after validating the provider identity, while doctor is deliberately read-only and never migrates. Use macOS Keychain Access for optional legacy cleanup, and inspect the exact config path before deleting ~/.config/codex-multi-email/config.json.
Development
npm ci
npm run validate
npm run pack:check
npm audit --omit=dev --audit-level=highnpm run build uses the exact @vercel/ncc version in package-lock.json, emits the CommonJS bundle dist/server.cjs, and includes both keyring.darwin-arm64.node and keyring.darwin-x64.node. CommonJS is intentional because the native Keychain loader relies on Node's __filename/createRequire behavior. The cold-install check tests both a dependency-free Git snapshot and an installed npm tarball.
The package metadata is structurally ready for a future public npm package named codex-multi-email, but this README does not claim that the name is reserved or that a package is published. A maintainer must authenticate, verify ownership, inspect npm publish --dry-run, and explicitly publish.
See CONTRIBUTING.md, SECURITY.md, and CHANGELOG.md.
Troubleshooting
Unknown alias: run
node ./scripts/multi-email list, then use the exact alias on every call.Plugin fails after install or restart: run
node ./scripts/multi-email self-test --jsonfrom the matching reviewed checkout and inspectmail_get_runtime_infowhen the MCP starts. The package, Plugin manifest, Skillmetadata.version, bundled runtime, and build manifest must identify the same release. On any mismatch, restart or reinstall that pinned release; do not reauthorize a mailbox.Connection health unclear: call
mail_diagnose_accountsfor one alias or all aliases; it checks credential presence, token usability, scopes, and identity without reading messages or making writes.CLI or automation diagnosis: run
node ./scripts/multi-email doctor --jsonfor stable JSON Lines with safe next steps. It does not read messages or migrate credentials.Not authorized or token expired: first run
doctorfor that alias. Reauthorize only when its result explicitly requires it, usingnode ./scripts/multi-email auth <alias> --browser default|safari|chrome; never paste a token into chat.Review request expired/rejected: prepare a new review and make a new decision in the local window.
Draft changed after approval: review the complete new draft again.
Draft not reviewable: remove HTML, inline content, attachments, alternate sender identities, or extra Reply-To values, or recreate it as a plain-text draft through Multi Email. Do not bypass the gate.
Send result uncertain: do not retry; inspect Drafts and Sent read-only first.
Partial Microsoft batch result: use
completedIdsandremainingIdsplus eitherfailedIdorunknownOutcomeIdfrom the error details. Inspect an unknown outcome read-only before deciding whether to retry, and never replay the full original batch.Gmail authorization warning or block: an app developer/support email is not the target mailbox. An unverified-app page that offers an Advanced continuation is a user trust decision that Multi Email never clicks; a hard “This app is blocked” result should stop browser-switch retries and trigger checks of audience, publishing state, test-user membership, scope, verification, and account/organization policy.
Microsoft consent blocked: verify public-client settings, tenant choice, delegated permissions, and administrator policy.
Shared mailbox or alternate From address: unsupported until the exact delegated identity and permissions are implemented and verified end to end.
License
MIT © 2026 Vincent_Lan. See LICENSE.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
No tool schema history has been recorded yet.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Manage Gmail end-to-end: search, read, send, draft, label, and organize threads. Automate workflow…
- PO6 MailboxOAuthcom.po6
Give AI agents secure access to your email via private aliases with dedicated mailbox storage.
Email infrastructure for AI agents — send, receive, search, and reply to email over MCP.
Read, organise and send from your existing email accounts. Nothing sends without your approval.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables interaction with Gmail through the Gmail API to read, send, and manage emails. Supports multiple Gmail accounts with real-time monitoring and advanced features for email search and attachment handling.17Apache 2.0
- AlicenseBqualityBmaintenanceEnables AI assistants to manage multiple Gmail accounts simultaneously with built-in OAuth authentication, supporting email reading, sending, drafts, labels, and account management.60482MIT
- FlicenseAqualityBmaintenanceConnects AI assistants to multiple Gmail accounts simultaneously, enabling search, read, draft, send, and reply operations with per-account permission controls.54-
- AlicenseAqualityBmaintenanceEnables connecting and searching multiple Gmail or Google Workspace accounts via friendly aliases, with read-only access and source mailbox attribution for each result.6MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/lanfuli/multi-email'
If you have feedback or need assistance with the MCP directory API, please join our Discord server