# Fluxmail > Self-hosted email infrastructure for agents and apps. Access your Gmail, Outlook, Exchange, and IMAP email accounts through MCP, REST API, or CLI. Fluxmail is self-hosted email infrastructure for agents and apps. It connects Gmail, Outlook, Exchange, and IMAP mailboxes through MCP, a versioned REST API, and a CLI. All three interfaces can search, read, draft, send, schedule, and organize email. AI agents can connect over local stdio or Streamable HTTP, while apps and backend workflows can use REST. The CLI includes Fluxmail-managed Gmail OAuth and also accepts custom Google credentials. Fluxmail encrypts provider credentials in local storage. Installation instructions are available at /docs/quickstart. Fluxmail Desktop is an upcoming local-first email client available for preview at /desktop. It will use the same local Fluxmail service as the CLI, MCP server, and REST API, so people and agents can work with the same connected mailboxes and permission model. ## Key facts - Self-hosted server: Fluxmail packages its CLI, MCP server, and REST API in the `fluxmail` npm package (Node.js 20.20.x or 22.22+) and a Docker image, with source available on GitHub. - Self-hosted transports: `fluxmail stdio` connects local agents (Claude Code, Claude Desktop, Cursor, Codex, Gemini CLI, VS Code Copilot); `fluxmail serve` runs a Streamable HTTP MCP endpoint authenticated with `fmk_` API keys. - Self-hosted email operations: MCP, REST API, and CLI can read and search threads, manage drafts, send and forward email, organize messages, and handle attachments. - Gmail OAuth: the Fluxmail CLI includes a managed OAuth flow and a bundled local OAuth client, and it also accepts custom Google credentials. - Self-hosted privacy: Google and Microsoft OAuth tokens and IMAP/SMTP passwords are stored locally in SQLite and encrypted with AES-256-GCM, with no Fluxmail cloud involved. - Self-hosted providers: Gmail, Google Workspace, Outlook, Exchange, and mailboxes with IMAP and SMTP access are supported today. - Self-hosted pricing: the free Personal plan includes 1 member and 3 mailboxes; Pro is $15/month or $120/year (1 member, 10 mailboxes); Business is $25/month or $240/year per member (up to 50 members, with 20 mailbox connections per member added to the instance limit); Enterprise is custom (contact sales). - Fluxmail Desktop status: the desktop email client is in development and does not have a public release date yet. - Fluxmail Desktop architecture: the app will use the local Fluxmail REST API while AI agents connect to the same service over MCP. ## Blog posts - [Triage your Outlook inbox with Claude Code](https://fluxmail.ai/blog/triage-outlook-with-claude-code): Connect Outlook.com, Hotmail, or Microsoft 365 mail to Claude Code, sort what needs a reply, archive the rest, and draft answers for review. Works with personal Microsoft accounts. - [Triage your Gmail inbox with Claude Code](https://fluxmail.ai/blog/triage-gmail-with-claude-code): Connect Gmail to Claude Code, sort unread mail into what needs a reply, what to read later, and what to archive, and turn the routine into a one-word command. - [How to give an AI agent access to your email safely](https://fluxmail.ai/blog/give-ai-agent-email-access-safely): Anyone can send your agent an email. Limit which mailboxes it reaches and what it can do, keep a person in the loop for sending, and separate each agent so you can revoke one. - [Introducing Fluxmail MCP: connect email to your AI agent](https://fluxmail.ai/blog/introducing-fluxmail-mcp): Fluxmail MCP is a self-hosted server that lets AI agents read, search, draft, send, and organize mail across Gmail, Outlook, Exchange, and IMAP accounts. # Integrations ## Email for Claude Code URL: https://fluxmail.ai/integrations/claude-code Fluxmail is a self-hosted MCP server that lets Claude Code search, read, draft, and send email in your Gmail, Outlook, Exchange, or IMAP mailboxes. It runs on your machine, and you decide which mailboxes and actions Claude Code can use. When Fluxmail and Claude Code run on the same computer, add the stdio server: claude mcp add fluxmail -- fluxmail stdio When Fluxmail runs in Docker or on another machine, create an API key with `fluxmail apikey create --name claude-code`. Start the server with `fluxmail serve` unless Docker is already running it, then connect over Streamable HTTP: claude mcp add --transport http fluxmail http://localhost:8977/mcp \ --header "Authorization: Bearer fmk_..." Q: Does Claude Code have built-in Gmail access? A: Claude Code connects to email through MCP servers you add. Fluxmail is one option. It works with Gmail and also with Outlook, Exchange, and IMAP mailboxes. Q: Can Claude Code send email through Fluxmail? A: Yes, when the connection allows the `mail.send` capability. The default `full` profile allows it. With the `read-write` profile, Claude Code can draft but not send. Q: Where is my email stored? A: Fluxmail runs on your computer or server and connects directly to your email provider. Provider credentials are encrypted in a local SQLite database. Claude Code sends the email content it reads to Anthropic, as it does with any tool output. --- ## Email for Codex URL: https://fluxmail.ai/integrations/codex Fluxmail gives Codex CLI and the Codex app access to your Gmail, Outlook, Exchange, or IMAP mailboxes through MCP. Codex can search, read, draft, and send email, limited to the mailboxes and actions you allow. For Codex CLI on the same computer as Fluxmail, add the stdio server: codex mcp add fluxmail -- fluxmail stdio To connect over Streamable HTTP, create an API key with `fluxmail apikey create --name codex`. Start the server with `fluxmail serve` unless Docker is already running it, then add it to `~/.codex/config.toml`: [mcp_servers.fluxmail] url = "http://localhost:8977/mcp" http_headers = { Authorization = "Bearer fmk_..." } Q: Does this work with both Codex CLI and the Codex app? A: Yes. Codex CLI reads MCP servers from `~/.codex/config.toml` or `codex mcp add`. The Codex app has its own MCP settings. Both can use stdio or Streamable HTTP. Q: Can I keep Codex read-only? A: Yes. Add `--profile read-only` to the stdio arguments, or create the HTTP API key with `--profile read-only`. Codex can then search and read but cannot draft, send, or change mail. Q: Which email providers can Codex reach? A: Any mailbox connected to Fluxmail: Gmail and Google Workspace, Outlook and Exchange through Microsoft Graph, and other providers through IMAP and SMTP. --- ## Email for Cursor URL: https://fluxmail.ai/integrations/cursor Fluxmail lets Cursor's agent search, read, draft, and send email in your Gmail, Outlook, Exchange, or IMAP mailboxes. Add it once in mcp.json for every project, or per project when only one codebase needs email. Add the stdio server to `~/.cursor/mcp.json`, or to `.cursor/mcp.json` in a project: { "mcpServers": { "fluxmail": { "command": "fluxmail", "args": ["stdio"] } } } To connect over Streamable HTTP, create an API key with `fluxmail apikey create --name cursor`. Start the server with `fluxmail serve` unless Docker is already running it, then use the server URL instead: { "mcpServers": { "fluxmail": { "url": "http://localhost:8977/mcp", "headers": { "Authorization": "Bearer fmk_..." } } } } Q: Should I configure Fluxmail globally or per project? A: Use `~/.cursor/mcp.json` when you want email in every project. Use `.cursor/mcp.json` in a repository when only that project needs it, and keep API keys out of version control. Q: Can Cursor send email? A: Yes, if the connection allows the `mail.send` capability. The default `full` profile allows it. Use the `read-write` profile if Cursor should draft without sending. Q: Does Fluxmail work with Cursor on Windows and Linux? A: Yes. Fluxmail runs anywhere Node.js 20.20.x or 22.22 and newer runs, and it can also run in Docker. Cursor connects to it through stdio or Streamable HTTP. # Comparisons ## Fluxmail vs Google Gmail MCP Server URL: https://fluxmail.ai/compare/gmail-mcp (reviewed July 18, 2026) Both products let an AI agent search and act on Gmail. Google runs its server as a remote endpoint in developer preview. Fluxmail runs on your computer or server and uses the same email tools across Gmail, Outlook, Exchange, and IMAP. Verdict: Choose Fluxmail when the agent must send, schedule, handle attachments, work across providers, or run on infrastructure you control. Choose Google's server when its current Gmail tools cover the job and you want a Google-operated endpoint. Q: Can the Gmail MCP Server send email? A: Google's current Gmail MCP reference does not list a send or reply tool. It can create a draft in Gmail for a person to review and send. Fluxmail can send directly, send an existing draft, reply, reply-all, or schedule delivery when the connection has mail.send permission. Q: Does the Gmail MCP Server support Outlook? A: No. Google's server is for Gmail and Google Workspace. Fluxmail also supports Microsoft 365, Outlook.com, Exchange through Microsoft Graph, and other mailboxes through IMAP and SMTP. Q: Which one is easier to maintain? A: Google operates its remote endpoint, so it has less server maintenance after setup. Fluxmail gives you local or Docker deployment and control over the data path, but you must keep the service updated and running. --- ## Fluxmail vs Microsoft Work IQ MCP URL: https://fluxmail.ai/compare/outlook-mcp (reviewed September 22, 2026) Both products let an AI agent read and act on Outlook mail. Microsoft's Work IQ MCP is a remote server with 10 generic tools that call Microsoft Graph paths across mail, calendar, files, Teams, and people. Fluxmail runs on your computer or server and gives agents dedicated email tools for Outlook, Exchange, Gmail, and IMAP. Verdict: Choose Fluxmail when the agent needs ready-made email tools, per-client permissions, personal Outlook.com accounts, or mailboxes outside Microsoft 365. Choose Work IQ MCP when your organization is on Microsoft 365 and the agent also needs calendar, Teams, SharePoint, or OneDrive data. Q: Can Work IQ MCP send Outlook email? A: Yes, through the do_action tool on a Graph path such as /me/sendMail. Microsoft blocks create, update, delete, and action requests by default, so a tenant administrator must allow them in the Microsoft 365 admin center first. Fluxmail can send, reply, forward, or schedule delivery when the connection has mail.send permission. Q: Does Work IQ MCP work with personal Outlook.com accounts? A: Microsoft's Work IQ documentation does not cover personal Outlook.com accounts. Its setup steps assume a Microsoft 365 tenant with a Global Administrator and usage-based billing. Fluxmail supports Microsoft 365, Outlook.com, and Hotmail through Microsoft Graph when the Entra app allows personal accounts. Q: Which one is easier to maintain? A: Microsoft operates the Work IQ endpoint, so there is no server to run after the tenant is set up. Fluxmail gives you local or Docker deployment and control over the data path, but you must keep the service updated and running. --- ## Fluxmail vs AgentMail URL: https://fluxmail.ai/compare/agentmail (reviewed September 22, 2026) AgentMail is a hosted email provider that creates new inboxes for agents on agentmail.to or your own domain. Fluxmail runs on your machine or server and connects agents to Gmail, Outlook, Exchange, and IMAP mailboxes you already have, through MCP, REST, and CLI. Verdict: Choose Fluxmail when agents should work in existing mailboxes, email data should stay on infrastructure you control, or each client needs narrow mailbox permissions. Choose AgentMail when every agent needs its own new address, inbound mail should arrive by webhook, and you do not want to run a server. Q: What is the best email API for AI agents? A: It depends on whose mailbox the agent uses. AgentMail fits agents that need their own new inboxes, with hosted delivery and webhooks for inbound mail. Fluxmail fits agents that work in existing Gmail, Outlook, Exchange, or IMAP mailboxes from infrastructure you run. Q: Can AgentMail connect to my existing Gmail or Outlook inbox? A: AgentMail documents new inboxes on agentmail.to or a custom domain, and a Google Workspace setup that routes unrecognized addresses on a shared domain to AgentMail. Connecting an existing Gmail or Outlook mailbox is not documented. Fluxmail connects existing mailboxes through Gmail OAuth, Microsoft Graph, or IMAP and SMTP. Q: Does Fluxmail have webhooks like AgentMail? A: No. AgentMail delivers message events through webhooks and WebSockets. Fluxmail has no built-in inbound events, so agents and apps list or search for new mail through MCP, REST, or the CLI. --- ## Fluxmail vs EmailEngine URL: https://fluxmail.ai/compare/emailengine (reviewed July 18, 2026) Fluxmail and EmailEngine both connect existing mailboxes from infrastructure you run. EmailEngine is a REST and webhook gateway with deep application controls. Fluxmail starts from AI-agent workflows, then exposes the same email model through MCP, REST, and CLI. Verdict: Choose Fluxmail when AI agents are the main callers, least-privilege mailbox access matters, or one service must cover MCP, REST, and operator workflows. Choose EmailEngine for a mature REST gateway, real-time webhooks, and application-level email automation. Q: Is Fluxmail an EmailEngine alternative? A: Yes, when the goal is to connect existing mailboxes through a self-hosted service. Fluxmail supports REST applications and is the closer fit when those applications share email infrastructure with MCP clients or need email-specific permissions. EmailEngine is the closer fit for webhook-heavy backends, queues, templates, and mail merge. Q: Does EmailEngine support MCP? A: EmailEngine does not document a native MCP server. An application can place an MCP adapter in front of its REST API. Fluxmail ships stdio and Streamable HTTP MCP transports as part of the product. Q: Which one is free? A: Fluxmail has an ongoing free Personal plan for one member and three mailboxes. EmailEngine provides a fourteen-day full trial, then costs $995 a year for production use. --- ## Fluxmail vs ChatGPT Gmail app URL: https://fluxmail.ai/compare/chatgpt-gmail (reviewed July 18, 2026) ChatGPT can search Gmail, summarize threads, prepare replies, and let paid web users confirm and send a draft without leaving the chat. Fluxmail runs as email infrastructure that you control and can serve ChatGPT, other MCP clients, REST applications, or the CLI. Verdict: Choose Fluxmail when you need programmatic mailbox operations, providers beyond Gmail, more than one client, or a self-hosted data path. Choose the ChatGPT Gmail app when your email work stays inside ChatGPT and you want almost no setup. Q: Can Fluxmail connect Gmail to ChatGPT? A: Yes. Run Fluxmail over Streamable HTTP, create a suitably scoped API key, and add the endpoint as a custom MCP connector in a ChatGPT plan that supports custom connectors. Q: Is Fluxmail a replacement for the ChatGPT Gmail app? A: It can replace the email connection when you need actions outside ChatGPT or self-hosting, but it does not reproduce the native ChatGPT app experience. Fluxmail is a server that ChatGPT and other clients call. Q: Does ChatGPT store connected Gmail data? A: OpenAI says a connected Google app may create and synchronize an indexed copy. It says that indexed copy is deleted within thirty days after disconnection. Review the current OpenAI data-controls page for plan-specific details. --- ## Fluxmail vs Claude Gmail connector URL: https://fluxmail.ai/compare/claude-gmail (reviewed July 18, 2026) Claude has a built-in Gmail connector that can search and read email, create drafts, and manage labels with user approval. If that covers your needs, it is the simplest option because there is nothing to install. Fluxmail requires installation, but it adds sending, scheduling, attachment downloads, more email providers, and a server that other agents and applications can use. Verdict: Choose Fluxmail when the workflow must send mail, read attachment contents, cross providers, or serve clients beyond Claude. Choose Claude Gmail when you only need Gmail inside Claude and want no server to run. Q: Can Claude send Gmail messages with its connector? A: No. Anthropic states that Claude can create drafts in Gmail but cannot send them. The user must send each draft manually from Gmail. Fluxmail can send when the connection has mail.send permission. Q: Can Claude read Gmail attachments? A: The built-in Gmail connector exposes attachment metadata, not the file content. Fluxmail can download attachment content as an MCP resource for a compatible client. Q: Can Fluxmail be used with Claude? A: Yes. Claude Desktop and Claude.ai can connect to Fluxmail through MCP, depending on the Claude plan and connector support. Local clients can use stdio, while remote connectors use Streamable HTTP. --- ## Fluxmail vs Composio Gmail URL: https://fluxmail.ai/compare/composio-gmail (reviewed July 21, 2026) Composio gives agents hosted MCP access to Gmail and a large catalog of other applications, with managed authentication and dozens of Gmail actions. Fluxmail focuses on email, with managed Gmail OAuth in the CLI, a bundled local OAuth client, self-hosted token storage, and sixteen normalized tools across Gmail, Outlook, Exchange, and IMAP, plus REST and CLI access. Verdict: Choose Fluxmail when email depth, self-hosting, provider portability, and mailbox-specific access controls matter more than a broad app catalog. Choose Composio when Gmail is one integration in a much larger agent stack and you want hosted access to that broader catalog. Q: Is Fluxmail a self-hosted Composio alternative? A: For email, yes. Fluxmail can replace the Gmail, Outlook, and IMAP part of an agent stack with a self-hosted service. It does not replace Composio's broader catalog of non-email integrations. Q: Can Composio use custom Gmail OAuth credentials? A: Yes. Composio supports its managed Gmail OAuth app and custom auth configurations. Custom credentials are useful for consent-screen branding, scopes, and dedicated quota. Q: Which product stores Gmail tokens? A: Fluxmail's local and managed Gmail OAuth flows encrypt and store provider tokens on the machine where you run it. With Composio managed auth, Composio stores and refreshes connected-account tokens. Composio also supports custom OAuth credentials, but the connected account still runs through its platform. # Documentation # Architecture URL: https://fluxmail.ai/docs/architecture ## Where your data lives [#where-your-data-lives] Fluxmail keeps its SQLite database on the machine where it runs. Google and Microsoft OAuth tokens, OAuth application secrets, license state, and IMAP/SMTP passwords are encrypted at rest with AES-256-GCM. Restart-bound deployment settings live in `/config.toml`; the encryption key remains outside that file. Your client talks to your email provider through the self-hosted Fluxmail process. Fluxmail does not copy email content to a service operated by Fluxmail. Content returned through MCP may be sent to the client's model provider, depending on how that client runs. The [code is source available](https://github.com/churichard/fluxmail) under the [Elastic License 2.0](https://github.com/churichard/fluxmail/blob/main/LICENSE.md). ## How requests flow [#how-requests-flow] Agents connect through MCP, apps and backend workflows use REST, and people or scripts can use the CLI. All three interfaces send email requests through the same service. Fluxmail selects the mailbox, checks access and plan limits, then passes the operation to Gmail, Microsoft Graph, or an IMAP/SMTP server. Mailbox routing, replies, forwards, and provider capabilities stay consistent across CLI, MCP, and REST. The CLI also connects mailboxes, manages members and API keys, changes configuration, and starts the MCP and REST services. Local CLI commands call route handlers in the Fluxmail process. Remote CLI profiles call the same routes over HTTPS. Each route resolves the member session or API key, applies the centralized access policy, and then calls the account, member, license, or mail service. ```text Local CLI --------------------\ Remote CLI and REST -----------> routes -> principal -> policy -> services -> SQLite HTTP MCP with an API key ------/ ``` CLI commands use the same REST operations, database, and provider connections as the running server. The CLI only handles terminal concerns such as flags, JSON input, local attachment files, and formatted output. Provider differences still affect the available behavior. Folders are places you can navigate, such as Inbox or Archive. Labels are tags that a message can have alongside its folder. Gmail user labels work as both navigable views and tags, so they appear in folder and label listings. Outlook folders appear as folders, while Outlook categories appear as labels. IMAP has folders but does not support label actions. It also uses the mail server's basic search and has no server-side thread model. Fluxmail reconstructs IMAP threads from standard email headers. ## How permissions are enforced [#how-permissions-are-enforced] Every authenticated request acts for one active member. Fluxmail first checks whether the member owns the mailbox, has an explicit grant, or can use it through `sharedWithAll`. It then applies an API key's optional account allowlist. An administrator can manage members and mailbox access, but the role does not grant access to private mailboxes. Stdio reads the selected local member session. HTTP MCP accepts scoped API keys. REST accepts sessions and API keys. Session authority follows the member's current role. API key authority is the intersection of its stored capabilities, its optional account allowlist, and its owner's current role and mailbox access. Administrative REST routes add a second check. A session owner must currently be an administrator. An API key also needs the capability for that route. Fluxmail has no memberless keys or unauthenticated mail mode. Authentication and management operations append rows to `admin_audit_events`. Database triggers prevent these rows from being changed or deleted. The table stores stable identifiers and outcome codes, not passwords, tokens, request bodies, or provider credentials. Fluxmail does not send actor or resource identifiers through anonymous telemetry. Attachments are returned as embedded MCP resources or raw REST responses. Attachment IDs are opaque strings and can contain punctuation such as `part:1.2`. Every provider enforces the configured decoded-size limit before returning the file. The default limit is 10 MB, and the hard maximum is 25 MB. Sends and forwards through REST, MCP, and CLI use delivery operations in SQLite. Each idempotency key is scoped to the authenticated credential and has no automatic expiry. Reusing a key with the same request returns the saved operation without sending again. If an operation is uncertain, check the Sent folder or recipient before creating another request. REST keys created before the delivery-operation upgrade keep their original 24 hour lifetime. --- # Authentication and instances URL: https://fluxmail.ai/docs/authentication-and-instances Fluxmail uses member sessions for people and API keys for MCP clients, scripts, and other automation. A member session follows the member's current role and mailbox access. An API key is narrower: Fluxmail also checks its capabilities and optional mailbox allowlist on every request. ## Set up a local instance [#set-up-a-local-instance] Run this once on a fresh instance: ```bash fluxmail setup --name "Your name" --email you@example.com ``` Fluxmail asks for a password without displaying it. The command creates the first administrator, adds a CLI profile named `local`, and saves a 90-day device session. Passwords must contain 8 to 256 Unicode characters. Fluxmail rejects common passwords and passwords based on the member's name or email address. It does not require a mix of uppercase letters, numbers, and symbols. ## Log in to an existing local instance [#log-in-to-an-existing-local-instance] If the instance is already set up but the CLI has no `local` profile (for example after the profile was removed or the CLI files were lost), login recreates it: ```bash fluxmail --instance local login ``` On a machine with no CLI profiles at all, bare `fluxmail login` recreates the `local` profile and logs in there. If other profiles exist, name the local one explicitly as above. ## Log in to a remote instance [#log-in-to-a-remote-instance] Name the profile when you add a server: ```bash fluxmail --instance work login --server https://mail.example.com ``` Fluxmail asks for the member email and password. After the profile exists, the server URL is no longer needed: ```bash fluxmail --instance work login ``` Remote profiles require HTTPS. Plain HTTP is accepted only for loopback addresses such as `http://127.0.0.1:8977`. The CLI refuses redirects for authenticated remote requests so it cannot forward a session to another origin. If a reverse proxy terminates TLS and connects to Fluxmail from a non-loopback address, set `FLUXMAIL_TRUST_PROXY=1`. Fluxmail will then use the forwarded protocol and client address for HTTPS checks and login throttling. Enable this only when the proxy overwrites forwarded headers and blocks direct access to Fluxmail. List, select, or remove profiles with: ```bash fluxmail instances list fluxmail instances use work fluxmail instances remove work ``` `--instance ` overrides the selected profile for one command. Removing a profile deletes its local session secret but does not change the server or its data. ## Invite and enroll a member [#invite-and-enroll-a-member] An administrator creates a pending member: ```bash fluxmail members add --name "Grace Hopper" --email grace@example.com ``` The command prints a one-time enrollment code. It expires after seven days. Send it to the member through a private channel. The member enrolls with: ```bash fluxmail --instance work login --server https://mail.example.com --enroll ``` Fluxmail asks for the code and a new password without putting either secret in shell history. If the profile already exists, omit `--server`. Administrators can replace an unused or expired code with `fluxmail members invite `. Enrollment is only needed for the first password. Members use normal login afterward. ## Manage sessions [#manage-sessions] Member sessions have a server-enforced 90-day lifetime. Logout, suspension, removal, password reset, and explicit revocation take effect immediately. ```bash fluxmail auth sessions fluxmail auth revoke-session fluxmail logout ``` Administrators can inspect or revoke another member's sessions: ```bash fluxmail members sessions fluxmail members revoke-session ``` Password reset codes last for one hour: ```bash fluxmail members password-reset ``` The member redeems the code with `fluxmail --instance login --reset`. Email delivery is not built in, so the administrator must send the code privately. ## Use API keys for automation [#use-api-keys-for-automation] Create a key while logged in: ```bash fluxmail apikey create --name research-agent --profile read-only ``` The key belongs to the current member and is shown once. It can only reach mailboxes available to that member. Use repeated `--account` options to narrow it to specific mailboxes. Administrators can issue a key for another member with `--member `. Administrative capabilities require an administrator owner and an explicit `admin.*` capability. Demoting or suspending the owner removes that authority immediately. HTTP MCP accepts API keys, not member sessions: ```http Authorization: Bearer fmk_... ``` REST accepts either an API key or the `fms_...` session used by the CLI. A future web dashboard can use the same REST operations through a browser cookie adapter. ## Local stdio [#local-stdio] `fluxmail stdio` uses the authenticated member session from the selected local profile. It does not accept a member override: ```bash fluxmail stdio --profile read-only ``` Stdio is local only. Use the HTTP MCP endpoint and a scoped API key for remote MCP clients. ## Stored CLI files [#stored-cli-files] Fluxmail keeps profile metadata and session secrets in separate files under `/cli`. Both files are readable only by their owner, and the directory uses owner-only permissions. The session file contains the bearer secret. Copying the profile file alone does not copy a login. ## Recover a local administrator [#recover-a-local-administrator] If every administrator session is unavailable, someone with filesystem access to the instance can reset an existing administrator: ```bash fluxmail auth recover-admin ``` The command is local only. It sets a new password, reactivates that administrator if needed, revokes their sessions, and writes a security audit event. It cannot create a member or bypass plan limits. Finish `fluxmail setup` before using administrator recovery. Migrated instances must claim an existing administrator during setup first. --- # Build with REST URL: https://fluxmail.ai/docs/build-with-rest Fluxmail provides the same REST API for Gmail, Outlook, and IMAP/SMTP mailboxes. This guide follows a common workflow: find a mailbox, list its messages, fetch one message, and mark it as read. Errors include a safe code and request ID. Fluxmail input errors describe how to fix the request; search syntax errors also include `error.data.diagnostics`. Provider error text is not returned. ## Start the API [#start-the-api] Complete the [Quickstart](/docs/quickstart), then create an API key for your app and start the server: ```bash fluxmail apikey create --name local-app fluxmail serve ``` Fluxmail displays the key once. Store it as a secret, then set the API key and base URL in the shell where you will make requests: ```bash export FLUXMAIL_API_KEY='fmk_...' export FLUXMAIL_API_URL='http://localhost:8977/api/v1' ``` Use HTTPS when the server runs on another machine. If Fluxmail runs in Docker, create the key inside the container. Docker Compose already runs the server: ```bash docker compose exec fluxmail \ fluxmail apikey create --name local-app ``` Set `FLUXMAIL_API_URL` to the public URL from [Deploy with Docker](/docs/deploy-with-docker), followed by `/api/v1`. ## Find the mailbox [#find-the-mailbox] List the mailboxes available to the API key: ```bash curl "$FLUXMAIL_API_URL/accounts" \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` Copy the account ID from `data`. You will use it in mailbox requests. API keys can be limited to selected mailboxes and permission profiles through [Permissions](/docs/permissions). Folders and labels are separate resources. Use `/accounts//folders` for navigable mailbox locations. Use `/accounts//labels` for Gmail user labels or Outlook categories. Gmail user labels appear in both responses because they are navigable views and message tags. IMAP accounts return an unsupported capability error for labels. ## List messages [#list-messages] Get the 10 most recent inbox messages: ```bash curl "$FLUXMAIL_API_URL/accounts//messages?folder=inbox&pageSize=10" \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` List responses contain message metadata. Gmail and Outlook include their native snippets by default. Add `includeSnippet=true` to request IMAP previews, or use `includeSnippet=false` to suppress previews from every provider. Add `includeSearchContext=true` with a literal text query to return an excerpt around the body match. Filters such as `read=false`, `from=person@example.com`, or `text=invoice` narrow the results. The `query` parameter accepts [portable search syntax](/docs/email-search). If the response includes `meta.nextPageToken`, pass it as `pageToken` with the same account, query, page size, snippet setting, and search context setting. Treat an empty page as a confirmed negative result only when `meta.exhausted` is `true`. See [List messages](/docs/rest-api/list-messages) for all filters. Search several accounts with one request: ```bash curl "$FLUXMAIL_API_URL/messages/search" \ -X POST \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" \ -H "Content-Type: application/json" \ --data '{ "accounts": [{"accountId": ""}, {"accountId": ""}], "query": "invoice is:unread", "pageSize": 25, "includeSnippet": true, "includeSearchContext": true }' ``` The response has one group per account. Account errors stay in their group, so successful results remain available. See [Search multiple accounts](/docs/rest-api/search-messages) for the request and response schemas. ## Get the complete message [#get-the-complete-message] Use an ID from the list response to fetch the message body and attachment metadata: ```bash curl "$FLUXMAIL_API_URL/accounts//messages/" \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` Use [Get a thread](/docs/rest-api/get-thread) instead when you need the complete conversation. Treat attachment IDs as opaque strings. Keep the ID exactly as returned and pass it to the download operation. For example, an IMAP attachment ID can look like `part:1.2`. ## Mark the message as read [#mark-the-message-as-read] After your app processes a message, it can mark that message as read: ```bash curl "$FLUXMAIL_API_URL/accounts//messages/actions" \ -X POST \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" \ -H "Content-Type: application/json" \ --data '{ "messageIds": [""], "action": "markRead" }' ``` The same endpoint can archive, star, move, label, trash, or permanently delete messages. See [Modify messages](/docs/rest-api/modify-messages) before using those actions. The response now reports each message in `succeededIds`, `failed`, or `uncertainIds`. Send at most 100 distinct IDs. If an ID is uncertain, inspect that message before retrying. ## Send safely [#send-safely] Pass an `Idempotency-Key` header with every send or forward request. Reuse the same key for retries of the same request. Fluxmail returns a delivery `operationId` and a status of `queued`, `sending`, `succeeded`, `failed`, or `uncertain`. Fetch `/accounts//delivery-operations/` to check the outcome. An uncertain status means the provider may have delivered the message, so Fluxmail will not send it again under that key. You can inspect a draft with `GET /accounts//drafts/`. The `/accounts//send/preview` operation resolves the sender, reply recipients, subject, and attachment metadata without sending. See the [REST API reference](/docs/rest-api) for request fields. When sending plain-text email, keep each prose paragraph on one continuous line in `body.text`, with a blank line between paragraphs. Fluxmail preserves line breaks in the sent message. The same applies to a forward's `comment`. ## Continue building [#continue-building] * [Create a draft](/docs/rest-api/create-draft) or [send and reply](/docs/rest-api/send-message). * [Download an attachment](/docs/rest-api/download-attachment). * Browse the complete [REST API reference](/docs/rest-api), or load the OpenAPI 3.1 document from `/api/v1/openapi.json`. --- # Configuration URL: https://fluxmail.ai/docs/configuration Fluxmail has two configuration domains. Deployment configuration controls how the process starts. Instance settings control OAuth applications and the license used by a running instance. ## Deployment configuration [#deployment-configuration] Deployment settings are resolved in this order: 1. Built-in defaults 2. `/config.toml` 3. Process environment variables Changes to deployment settings require a restart. Run `fluxmail config init` to create a starter file with owner-only permissions. Run `fluxmail config show` to see effective values, their sources, and the paths Fluxmail is using. `FLUXMAIL_DATA_DIR` stays outside `config.toml` because it tells Fluxmail where to find the file. It defaults to `~/.fluxmail`, or `/data` in the Docker image. A typical file looks like this: ```toml [storage] database_path = "/var/lib/fluxmail/fluxmail.db" [server] port = 8977 public_url = "https://mail.example.com" trust_proxy = false max_attachment_mb = 10 [oauth.local] host = "127.0.0.1" port = 8976 ``` Fluxmail rejects unknown TOML keys, invalid types, and values outside their allowed ranges. It does not change `process.env` while resolving settings. ## Instance settings [#instance-settings] Custom Google and Microsoft OAuth applications and the license key are stored as encrypted records in SQLite. Changes made with `fluxmail oauth configure`, `fluxmail oauth reset`, or `fluxmail license activate` take effect immediately. You do not need to restart the server. Use `fluxmail oauth status` to see client IDs, tenant IDs, configuration state, and source categories. Status output never includes client secrets, ciphertext, secret-file paths, or environment values. Environment variables can override a complete provider group. When a provider comes from the environment, authenticated commands and APIs cannot replace or reset it until you remove the overrides and restart Fluxmail. * Google requires both `GOOGLE_CLIENT_ID` and `GOOGLE_CLIENT_SECRET`. * Microsoft requires `MICROSOFT_CLIENT_ID` when any Microsoft override is present. `MICROSOFT_TENANT_ID` defaults to `common`. Public clients can omit `MICROSOFT_CLIENT_SECRET`. ## Secret storage [#secret-storage] Fluxmail encrypts instance settings and provider credentials with AES-256-GCM before writing them to SQLite. Encrypted values use a versioned storage envelope so future releases can migrate the format safely. The encryption key is resolved from one source: 1. `FLUXMAIL_ENCRYPTION_KEY` 2. `FLUXMAIL_ENCRYPTION_KEY_FILE` 3. `/encryption.key` Fluxmail generates `/encryption.key` with owner-only permissions when no external key is configured. Back up this file with the database. A database backup is not usable without the matching key. For managed deployments, use `*_FILE` variables instead of putting secrets directly in the process environment. Fluxmail supports files for `FLUXMAIL_ENCRYPTION_KEY`, `GOOGLE_CLIENT_SECRET`, `MICROSOFT_CLIENT_SECRET`, and `FLUXMAIL_LICENSE_KEY`. Paths must be absolute. Fluxmail reads UTF-8, removes one final newline, rejects empty files, and leaves externally managed file permissions unchanged. ## Import an env file [#import-an-env-file] Fluxmail does not read `config.env`, `.env.local`, or `.env` files. Import settings from an existing file before starting Fluxmail: ```bash fluxmail config migrate --from /absolute/path/to/old.env --dry-run fluxmail config migrate --from /absolute/path/to/old.env ``` If the source file sets `FLUXMAIL_DATA_DIR`, that directory is the migration target. Otherwise, the command uses `FLUXMAIL_DATA_DIR` from the process environment or the default data directory. The command validates imported deployment values and checks the database format before writing anything. If the target database already contains encrypted values, you must provide its existing encryption key. Fluxmail will not generate a replacement key for that database. The command writes deployment settings to `config.toml`, stores OAuth applications and the license in encrypted SQLite records, and preserves the source file. If the encrypted settings step fails, Fluxmail removes only the new `config.toml` and `encryption.key` files created by that import. Run `fluxmail config show` and `fluxmail oauth status` after the import. Remove the old `config.env` after you verify the result. Docker Compose and process-manager env files still work because those tools populate the process environment before Fluxmail starts. ## Outbound proxy [#outbound-proxy] If Gmail or Google sign-in requests need an HTTP proxy, set `HTTPS_PROXY` in the Fluxmail process environment before starting the server. Fluxmail also accepts `https_proxy`, `HTTP_PROXY`, and `http_proxy`. When several are set, it uses the first of `HTTPS_PROXY`, `https_proxy`, `HTTP_PROXY`, and `http_proxy`. Use an `http://` or `https://` proxy URL. Fluxmail keeps proxy connections open on supported Node.js versions. A Gmail search can reuse a tunnel while reading messages. With an `https://` proxy, Fluxmail includes the proxy hostname in the TLS handshake so the proxy can present the right certificate. To send some requests directly, list hosts in `NO_PROXY` (or `no_proxy`), separated by commas. Each entry can be: * `*`, which skips the proxy for every host * A hostname, such as `gmail.googleapis.com` * A domain suffix, such as `.googleapis.com` or `*.googleapis.com` * An origin, such as `https://gmail.googleapis.com` These variables apply to Gmail API and Google sign-in requests. They do not change Outlook or IMAP connections. Restart Fluxmail after changing them. ## Local logs [#local-logs] Fluxmail writes bounded local logs for failures and low-volume service events. Successful MCP, REST, and CLI operations are not logged. See [Local logs](/docs/logging) for the file location, the 20 MiB disk limit, viewing commands, and privacy notes. ## Setting reference [#setting-reference] | Setting | Primary storage | Environment override | Default | Applies | Purpose | | ------------------------------- | -------------------------- | ----------------------------------------------------------- | ----------------------------------------- | ----------------------- | ------------------------------------------------------------------------------------------ | | `deployment.data_dir` | External | `FLUXMAIL_DATA_DIR` | `~/.fluxmail (/data in Docker)` | Restart | Directory for the SQLite database, deployment configuration, and generated encryption key. | | `storage.database_path` | `storage.database_path` | `FLUXMAIL_DB_PATH` | `/fluxmail.db` | Restart | Override the SQLite database path. | | `deployment.encryption_key` | External | `FLUXMAIL_ENCRYPTION_KEY`
`FLUXMAIL_ENCRYPTION_KEY_FILE` | `generated automatically` | Restart | A 64-character hexadecimal key used to encrypt credentials and instance secrets. | | `server.port` | `server.port` | `FLUXMAIL_PORT` | `8977` | Restart | HTTP server port. | | `server.public_url` | `server.public_url` | `FLUXMAIL_PUBLIC_URL` | `http://localhost:` | Restart | Public base URL used for HTTP APIs and hosted OAuth callbacks. | | `server.trust_proxy` | `server.trust_proxy` | `FLUXMAIL_TRUST_PROXY` | `false` | Restart | Trust forwarded protocol and client address headers from a reverse proxy. | | `oauth.local.port` | `oauth.local.port` | `FLUXMAIL_OAUTH_PORT` | `8976` | Restart | Port for the local OAuth callback listener. | | `oauth.local.host` | `oauth.local.host` | `FLUXMAIL_OAUTH_HOST` | `127.0.0.1` | Restart | Bind address for the local OAuth callback listener. | | `server.max_attachment_mb` | `server.max_attachment_mb` | `FLUXMAIL_MAX_ATTACHMENT_MB` | `10` | Restart | Largest decoded attachment returned through MCP or REST, from 1 through 25 MB. | | `logging.level` | `logging.level` | `FLUXMAIL_LOG_LEVEL` | `info` | Restart | Minimum severity retained by the bounded local logger. | | `logging.destination` | `logging.destination` | `FLUXMAIL_LOG_DESTINATION` | `both` | Restart | Write local logs to both the rotating file and console, or choose file or console. | | `oauth.google.client_id` | Encrypted SQLite | `GOOGLE_CLIENT_ID` | `Fluxmail Desktop OAuth app` | Immediate; env: restart | Override the built-in Google OAuth client ID. | | `oauth.google.client_secret` | Encrypted SQLite | `GOOGLE_CLIENT_SECRET`
`GOOGLE_CLIENT_SECRET_FILE` | `Fluxmail Desktop OAuth app` | Immediate; env: restart | Override the built-in Google OAuth client secret. Required with GOOGLE\_CLIENT\_ID. | | `oauth.microsoft.client_id` | Encrypted SQLite | `MICROSOFT_CLIENT_ID` | `required for Outlook` | Immediate; env: restart | Microsoft Entra application client ID. | | `oauth.microsoft.client_secret` | Encrypted SQLite | `MICROSOFT_CLIENT_SECRET`
`MICROSOFT_CLIENT_SECRET_FILE` | `required for hosted Outlook connections` | Immediate; env: restart | Microsoft Entra application client secret. | | `oauth.microsoft.tenant_id` | Encrypted SQLite | `MICROSOFT_TENANT_ID` | `common` | Immediate; env: restart | Microsoft Entra tenant ID or verified domain. | | `license.key` | Encrypted SQLite | `FLUXMAIL_LICENSE_KEY`
`FLUXMAIL_LICENSE_KEY_FILE` | `none` | Immediate; env: restart | Paid-plan license key, normally stored with fluxmail license activate. | | `telemetry.enabled` | Data directory marker | `FLUXMAIL_TELEMETRY` | `1` | Before startup | Set to 0 to turn off anonymous CLI, MCP, and REST usage telemetry. | | `telemetry.do_not_track` | Data directory marker | `DO_NOT_TRACK` | `unset` | Before startup | Set to 1 to turn off anonymous usage telemetry. | HTTP MCP requests require an API key. REST requests accept an active member session or API key. See [Permissions](/docs/permissions) and [Authentication and instances](/docs/authentication-and-instances). ## Telemetry [#telemetry] Fluxmail sends anonymous operation events to its PostHog project by default. Events record the CLI command, MCP tool, or REST operation, plus the outcome, duration, selected feature modes, a random installation ID, and basic runtime information. For MCP attachment downloads, telemetry records whether the tool returned a resource link or inline content. It records the same choice if the download fails, without sending the attachment name or content. Delivery status, send preview, draft retrieval, body continuation, and bulk actions use the same event format. Fluxmail does not send delivery IDs, message IDs, recipients, or message content in these events. When the MCP server starts, telemetry records the plan and how many mailboxes and members the installation has. The plan is sent as Personal, Pro, Team, Business, or Enterprise, and any other plan name is sent as `other`. It does not send the license key or any address. After Fluxmail connects or removes a mailbox, telemetry records its provider and the installation's mailbox totals. OAuth connection events also record whether the callback used your public URL or the local port, and whether Google used Fluxmail's built-in application or one you registered. Local connections record whether the redirect reached Fluxmail directly, you pasted the callback URL, or the command timed out. The pasted URL is never sent. Connection events report whether they replaced credentials for an existing mailbox. Fluxmail never sends command arguments, email or mailbox data, identifiers, search text, file paths, credentials, configuration values, request payloads, provider responses, stack traces, or error text. PostHog person profiles and GeoIP lookup are disabled. For batch search, telemetry records the surface operation and marks the outcome as an error when any account group fails. It does not include account IDs, queries, page tokens, or group errors. Turn telemetry off for the installation: ```bash fluxmail telemetry disable ``` You can also set `FLUXMAIL_TELEMETRY=0` or `DO_NOT_TRACK=1`. Any disabling source takes priority over an enabling source. Use `fluxmail telemetry status` to check the effective state. --- # Connect IMAP/SMTP URL: https://fluxmail.ai/docs/connect-an-imap-mailbox Fluxmail can connect to email providers that offer IMAP for reading mail and SMTP for sending it. ## 1. Find your provider settings [#1-find-your-provider-settings] Before you start, find the IMAP and SMTP settings from your email provider. Some providers require an app password instead of your usual email password. Fluxmail defaults to IMAP over TLS on port 993 and SMTP with STARTTLS on port 587. It uses the mailbox address as the username for both connections. You can override each of these settings when you connect the mailbox. If the SMTP account has aliases, an administrator can register those existing addresses in Fluxmail. The selected address is used in both the From header and SMTP envelope. Your SMTP server must allow it. See [Send from another address](/docs/send-as-addresses). ## 2. Connect the mailbox [#2-connect-the-mailbox] Choose the setup that matches how you run Fluxmail. For a fresh local instance, create the first administrator and log in: ```bash fluxmail setup --name "Your name" --email you@example.com ``` ### Local terminal [#local-terminal] Run: ```bash fluxmail accounts add imap \ --email you@example.com \ --imap-host imap.example.com \ --smtp-host smtp.example.com ``` Fluxmail prompts for the password without showing it on screen. If your provider uses different settings, pass the matching options: ```bash fluxmail accounts add imap \ --email you@example.com \ --display-name 'Your Name' \ --imap-host imap.example.com \ --imap-port 143 \ --imap-security starttls \ --imap-user your-username \ --smtp-host smtp.example.com \ --smtp-port 465 \ --smtp-security tls \ --smtp-user your-username ``` Both security options accept `tls` or `starttls`. Fluxmail checks both connections before saving the mailbox. Mailbox passwords are encrypted at rest with AES-256-GCM in Fluxmail's local SQLite database. ### Connect through REST [#connect-through-rest] An administrative client can test settings without saving them at `POST /api/v1/admin/imap/tests`, then connect the mailbox at `POST /api/v1/admin/connections`. The API key needs `admin.accounts`. ```bash curl "$FLUXMAIL_PUBLIC_URL/api/v1/admin/connections" \ -X POST \ -H "Authorization: Bearer $FLUXMAIL_ADMIN_API_KEY" \ -H "Content-Type: application/json" \ --data '{ "provider": "imap", "ownerMemberId": "you@example.com", "email": "you@example.com", "imap": { "host": "imap.example.com", "port": 993, "security": "tls", "user": "you@example.com", "password": "app-password" }, "smtp": { "host": "smtp.example.com", "port": 587, "security": "starttls", "user": "you@example.com", "password": "app-password" }, "saveSent": true }' ``` Fluxmail tests IMAP and SMTP within 30 seconds before it saves the mailbox. The response does not echo either password. Reauthorization keeps the existing `saveSent` value and folder overrides when those fields are omitted. Mailbox owners can update folder mappings with `PATCH /api/v1/accounts/:accountId/imap/folders`. Administrators can use `PATCH /api/v1/admin/accounts/:accountId/imap/folders` for any mailbox. A string sets a folder path. `null` removes an override and restores automatic detection. Fluxmail validates every requested path before saving any of them. ### Docker or another non-interactive environment [#docker-or-another-non-interactive-environment] An interactive terminal is not always available in Docker, CI, or a script. Put the password in an environment variable and pass its name to Fluxmail: ```bash IMAP_PASSWORD='your-app-password' \ fluxmail accounts add imap \ --email you@example.com \ --imap-host imap.example.com \ --smtp-host smtp.example.com \ --imap-password-env IMAP_PASSWORD ``` The password value stays out of the command line. Fluxmail uses the IMAP password for SMTP too. If the SMTP password is different, set another environment variable and pass it with `--smtp-password-env`. For Docker, make the variable available inside the container: ```bash export IMAP_PASSWORD='your-app-password' docker compose exec -e IMAP_PASSWORD fluxmail \ fluxmail accounts add imap \ --email you@example.com \ --imap-host imap.example.com \ --smtp-host smtp.example.com \ --imap-password-env IMAP_PASSWORD ``` ## If a special folder is missing or incorrect [#if-a-special-folder-is-missing-or-incorrect] Fluxmail looks for Sent, Drafts, Trash, Archive, and Spam folders using the server's special-use flags first, then common folder names such as `Sent Items` and `Junk Mail`. It prints a warning when a folder is missing or ambiguous, but still connects the mailbox. Fluxmail does not create a missing folder or guess when several folders match. An action that needs an unresolved folder returns an error. This prevents an archive or trash command from moving mail to the wrong place. Set the right folder path with the account ID from `fluxmail accounts list`: ```bash fluxmail accounts configure --sent-folder 'Sent Items' fluxmail accounts configure --trash-folder 'Deleted Messages' ``` You can configure `--sent-folder`, `--drafts-folder`, `--trash-folder`, `--archive-folder`, and `--spam-folder`. Pass `auto` to remove an override and let Fluxmail detect that folder again: ```bash fluxmail accounts configure --trash-folder auto ``` ## Optional: avoid duplicate Sent messages [#optional-avoid-duplicate-sent-messages] Fluxmail normally saves an SMTP submission in the resolved Sent folder. Some mail services already save SMTP submissions themselves. If yours does, add `--no-save-sent` when you connect the mailbox so each message appears only once: ```bash fluxmail accounts add imap \ --email you@example.com \ --imap-host imap.example.com \ --smtp-host smtp.example.com \ --no-save-sent ``` ## How Fluxmail works with IMAP [#how-fluxmail-works-with-imap] Fluxmail uses IMAP to read and organize the mailbox, and SMTP to send messages. The available behavior depends partly on the mail server: * Each message lives in a folder. Fluxmail can move messages between folders, but IMAP mailboxes do not support label actions. * Fluxmail builds threads from the standard `References`, `In-Reply-To`, and `Message-ID` headers. * Searches run through the IMAP server, so results depend on what that server can index. * List and search results omit previews by default. Pass `includeSnippet=true` to fetch a short preview from the preferred text part without downloading attachments or complete messages. The `snippets: false` capability means IMAP has no preview available without a body read. It does not disable requested previews. * Pass `includeSearchContext=true` with a literal text query to fetch an excerpt around the match. Fluxmail scans at most 256 KiB from the preferred text part. If you also request a snippet, both values come from one partial, non-marking body read. Through MCP or REST, Fluxmail can read and search mail, work with attachments and drafts, send or schedule messages, reply, forward, and organize messages into folders. Continue with [Connect an MCP client](/docs/connect-an-mcp-client), [Build with REST](/docs/build-with-rest), or [Use the CLI](/docs/use-the-cli). --- # Connect an MCP client URL: https://fluxmail.ai/docs/connect-an-mcp-client Complete the [Quickstart](/docs/quickstart) before configuring an MCP client. ## Choose one transport [#choose-one-transport] Configure either stdio or Streamable HTTP. You do not need both. | Transport | Use it when | Authentication | | --------------- | ------------------------------------------------------------------- | ----------------------------- | | stdio | Fluxmail and the MCP client run on the same computer | Selected local member session | | Streamable HTTP | The client connects by URL, including Docker and remote deployments | Fluxmail API key | For most local setups, choose stdio. Choose Streamable HTTP when Fluxmail runs in Docker, on another machine, or when the client requires a URL. Both transports provide the same MCP tools. The examples use the default `full` permission profile. See [Permissions](/docs/permissions) if the client should have less access. Every `send_email` and `forward_email` call now needs an `idempotencyKey`. Keep the key and reuse it if a call times out. The result includes an `operationId`; call `get_delivery_operation` to check whether delivery succeeded, failed, or is uncertain. Inspect an uncertain message before attempting a new send. Use `preview_send` to check recipients and attachments without sending. For plain-text email, ask your agent to keep each prose paragraph on one continuous line in `bodyText`, with a blank line between paragraphs. Fluxmail preserves line breaks, so wrapping a paragraph at a fixed width will show as short lines in the recipient's mail app. Lists and signatures can still use intentional line breaks. An uncertain or failed send is marked as an MCP tool error, but its structured result still contains the operation ID and status. Bulk changes with failed or uncertain messages behave the same way, so inspect their per-message result before retrying. Input errors from Fluxmail explain which field needs attention. Search syntax errors also include `data.diagnostics`. Provider error text is replaced with a safe message. Mail tools return typed `structuredContent` and readable text. `get_email` and `get_thread` accept `bodyFormat` to select text, HTML, both, or no body. Large bodies include truncation metadata; use `get_email_body` to read the remaining text. Thread messages are paged. `download_attachment` returns a protected resource link by default. Set `inline` only when the attachment bytes must be embedded in the tool response. ## Option 1: Connect over stdio [#option-1-connect-over-stdio] Every stdio client launches `fluxmail stdio`. Fluxmail uses the member logged in to the selected local instance. You do not need to run `fluxmail serve`. ### Claude Code [#claude-code] ```bash claude mcp add fluxmail -- fluxmail stdio ``` ### Claude Desktop [#claude-desktop] Add this server to `claude_desktop_config.json` under Settings > Developer > Edit Config: ```json { "mcpServers": { "fluxmail": { "command": "fluxmail", "args": ["stdio"] } } } ``` ### ChatGPT / Codex app [#chatgpt--codex-app] Open Settings > Plugins > MCPs > Add server, then enter: * Name: `Fluxmail` * Type: `STDIO` * Command to launch: `fluxmail` * Arguments: `stdio` Save the server and restart the app. ### Codex CLI [#codex-cli] ```bash codex mcp add fluxmail -- fluxmail stdio ``` You can also add the server to `~/.codex/config.toml`: ```toml [mcp_servers.fluxmail] command = "fluxmail" args = ["stdio"] ``` ### Cursor [#cursor] Add the server to `~/.cursor/mcp.json`, or to `.cursor/mcp.json` in a project: ```json { "mcpServers": { "fluxmail": { "command": "fluxmail", "args": ["stdio"] } } } ``` ### Hermes [#hermes] Add the server to `~/.hermes/config.yaml`, then run `/reload-mcp`. You can also use the dashboard opened by `hermes dashboard`. ```yaml mcp_servers: fluxmail: command: 'fluxmail' args: ['stdio'] ``` ### Gemini CLI [#gemini-cli] Add the server to `~/.gemini/settings.json`: ```json { "mcpServers": { "fluxmail": { "command": "fluxmail", "args": ["stdio"] } } } ``` ### Other stdio clients [#other-stdio-clients] Register `fluxmail` as the command with `stdio` as its argument. If a desktop client cannot find `fluxmail`, run `which fluxmail` in your terminal and use the returned absolute path as the command. If you configured stdio, continue to [Test the connection](#test-the-connection). Do not configure Streamable HTTP as well. ## Option 2: Connect over Streamable HTTP [#option-2-connect-over-streamable-http] Use this option instead of stdio when the MCP client connects to Fluxmail by URL. Start the HTTP server and create an API key for the client: ```bash fluxmail apikey create --name local-agent fluxmail serve ``` Fluxmail displays the `fmk_...` key once. The local MCP URL is `http://localhost:8977/mcp`. A remote deployment uses its public HTTPS URL followed by `/mcp`. If Fluxmail runs in Docker, create the key inside the container. The server is already started by Docker Compose: ```bash docker compose exec fluxmail \ fluxmail apikey create --name desktop ``` ### Claude Code [#claude-code-1] ```bash claude mcp add --transport http fluxmail http://localhost:8977/mcp \ --header "Authorization: Bearer fmk_..." ``` ### Claude Desktop [#claude-desktop-1] Claude Desktop's built-in remote connectors accept OAuth or no authentication, so they cannot send a Fluxmail API key. Use the local [`mcp-remote`](https://github.com/geelen/mcp-remote) bridge. Add this server to `claude_desktop_config.json` under Settings > Developer > Edit Config: ```json { "mcpServers": { "fluxmail": { "command": "npx", "args": [ "-y", "mcp-remote@latest", "http://localhost:8977/mcp", "--allow-http", "--transport", "http-only", "--header", "Authorization:${FLUXMAIL_AUTH_HEADER}" ], "env": { "FLUXMAIL_AUTH_HEADER": "Bearer fmk_..." } } } } ``` Replace `fmk_...` with the API key, then restart Claude Desktop. The bridge requires Node.js and npm on the same computer as Claude Desktop. ### ChatGPT / Codex app [#chatgpt--codex-app-1] Open Settings > Plugins > MCPs > Add server, then enter: * Name: `Fluxmail` * Type: `Streamable HTTP` * URL: `http://localhost:8977/mcp` * Header name: `Authorization` * Header value: `Bearer fmk_...` Save the server and restart the app. ### Codex CLI [#codex-cli-1] Add the server to `~/.codex/config.toml`: ```toml [mcp_servers.fluxmail] url = "http://localhost:8977/mcp" http_headers = { Authorization = "Bearer fmk_..." } ``` ### Cursor [#cursor-1] Add the server to `~/.cursor/mcp.json`, or to `.cursor/mcp.json` in a project: ```json { "mcpServers": { "fluxmail": { "url": "http://localhost:8977/mcp", "headers": { "Authorization": "Bearer fmk_..." } } } } ``` ### Hermes [#hermes-1] Add the server to `~/.hermes/config.yaml`, then run `/reload-mcp`: ```yaml mcp_servers: fluxmail: url: 'http://localhost:8977/mcp' headers: Authorization: 'Bearer fmk_...' ``` ### Gemini CLI [#gemini-cli-1] Add the server to `~/.gemini/settings.json`: ```json { "mcpServers": { "fluxmail": { "httpUrl": "http://localhost:8977/mcp", "headers": { "Authorization": "Bearer fmk_..." } } } } ``` ### ChatGPT.com developer mode [#chatgptcom-developer-mode] The ChatGPT / Codex app entry above configures Codex inside the ChatGPT app. Developer-mode apps used from regular ChatGPT chats have separate settings. ChatGPT cannot connect directly to `localhost`. For a local Docker server, use OpenAI's [Secure MCP Tunnel](https://help.openai.com/en/articles/12584461-developer-mode-and-full-mcp-connectors-in-chatgpt-beta#h_8e76ef4c26). You can also deploy Fluxmail at a public HTTPS URL. ChatGPT connectors currently support OAuth or no authentication, so they cannot send Fluxmail's API key. Fluxmail does not offer an unauthenticated MCP mode. ChatGPT developer-mode apps are not compatible until Fluxmail supports MCP OAuth. ### Other HTTP clients [#other-http-clients] Point the client to `http://localhost:8977/mcp`, or to the deployed `/mcp` URL. Send `Authorization: Bearer fmk_...` with each request. Clients that cannot set an authorization header are not compatible with the HTTP MCP endpoint. ## Test the connection [#test-the-connection] Ask the connected agent: > What are the latest 5 emails in my inbox? If the agent returns the messages, the connection is working. See [MCP tools](/docs/tools) for the operations it can call. ## Limit access [#limit-access] For stdio, add `--profile read-only`, `--profile read-write`, or repeated `--allow` options to the server command. For HTTP, the API key stores the permission profile and mailbox scope. You can change them without updating the client configuration. See [Permissions](/docs/permissions) for profiles and capabilities. --- # Connect Gmail / Google Workspace URL: https://fluxmail.ai/docs/connect-gmail-to-mcp Fluxmail includes a Google Desktop OAuth client, so you can connect Gmail locally without creating Google Cloud credentials. The local flow uses PKCE, and your OAuth tokens stay with the Fluxmail server you run. This setup works with personal Gmail and Google Workspace mailboxes. Fluxmail's built-in app requests Google's `gmail.modify` permission. You can read, draft, send, and organize mail, including moving messages to Trash. Gmail does not allow immediate permanent deletion with this permission. Fluxmail also reads Gmail's Send mail as settings with the same permission. Verified aliases can be used for drafts, replies, forwards, immediate sends, and scheduled messages. See [Send from another address](/docs/send-as-addresses) for sender selection rules. ## Connect Gmail [#connect-gmail] Choose the setup that matches how you run Fluxmail. For a fresh local instance, create the first administrator and log in: ```bash fluxmail setup --name "Your name" --email you@example.com ``` ### Local stdio [#local-stdio] Start the browser consent flow: ```bash fluxmail accounts add gmail ``` ### Docker or a remote server [#docker-or-a-remote-server] If Docker runs on the same computer as your browser, leave `FLUXMAIL_PUBLIC_URL` unset. Docker Compose publishes the local callback at `http://127.0.0.1:8976/oauth/callback`. For a remote deployment, expose Fluxmail through a public HTTPS address. You must also [use your own Google OAuth app](#use-your-own-google-oauth-app), because Google requires each hosted callback address to be registered. Add the public address to `.env`: ```dotenv FLUXMAIL_PUBLIC_URL=https://mail.example.com ``` The value must match the public HTTPS address whose callback URI you registered in Google Cloud. Start or recreate the container, then run the same mailbox command inside it: ```bash docker compose up -d docker compose exec fluxmail \ fluxmail setup --name "Your name" --email you@example.com docker compose exec fluxmail \ fluxmail accounts add gmail ``` On local Docker, the command prints a Google consent URL and waits for the callback on `127.0.0.1:8976`. On a remote deployment with `FLUXMAIL_PUBLIC_URL` set, it prints a one-time connection link instead. Open the link in your browser, choose the Google account, and approve access. Hosted links expire after 10 minutes and do not require an admin API key. Fluxmail uses the hosted flow whenever `FLUXMAIL_PUBLIC_URL` is set. The hosted flow cannot use the built-in Google client, which only accepts local callbacks, so it needs your own Web application. Without a public URL, `fluxmail accounts add gmail` uses the local callback at `http://127.0.0.1:8976/oauth/callback`. For troubleshooting, pass `--hosted` or `--local` to choose a flow explicitly. ### Browser on a different computer [#browser-on-a-different-computer] The local callback reaches Fluxmail only when your browser runs on the same computer as the CLI. If you run `fluxmail accounts add gmail` over SSH or on a headless server, open the consent URL in any browser and approve access. The browser then tries to load `http://127.0.0.1:8976/oauth/callback` and shows a connection error. Copy the full URL from its address bar and paste it into the terminal where the command is waiting. Pasting works when you run the command in an interactive terminal, so do not pass `-T` to `docker compose exec`. Fluxmail checks that the URL belongs to the current sign-in attempt and then connects the mailbox. You can also forward the callback port before you run the command, so the redirect reaches the CLI directly: ```bash ssh -L 8976:127.0.0.1:8976 you@server ``` The command stops waiting after 10 minutes. Run it again to get a new consent URL. ## Use your own Google OAuth app [#use-your-own-google-oauth-app] Use a custom Google client if you prefer to manage the OAuth consent screen yourself. A remote server with `FLUXMAIL_PUBLIC_URL` needs a Web client because Google's Desktop clients only support callbacks on the computer running the CLI. Fluxmail requests the full `https://mail.google.com/` scope when you configure a custom client. This preserves the permanent-delete action. Your Google OAuth app must be approved for that restricted scope before you make it available to other users. ### Create a Google Cloud project [#create-a-google-cloud-project] 1. Open [Google Cloud Console](https://console.cloud.google.com) and create or select a project. 2. Go to **APIs & Services → Library** and enable the **Gmail API**. 3. Open the Google Auth Platform setup and configure the OAuth consent screen. 4. Choose an **External** audience unless the app is restricted to people in your Google Workspace organization. 5. If the app is in Testing, add every Google account that will connect to Fluxmail as a test user. [Google allows up to 100 test users](https://support.google.com/cloud/answer/15549945) while an app has a Testing publishing status. Users see an unverified-app warning during authorization. ### Create OAuth credentials for a local connection [#create-oauth-credentials-for-a-local-connection] Go to **Google Auth Platform → Clients → Create client**, then choose **Desktop app**. Download the OAuth client JSON after Google creates it. Desktop apps cannot keep this credential confidential, but Google's token endpoint still requires the generated client secret. Save both values in encrypted instance settings. Fluxmail prompts for the client secret without displaying it: ```bash fluxmail oauth configure google \ --client-id .apps.googleusercontent.com ``` Fluxmail uses PKCE when it exchanges the local authorization code. ### Create OAuth credentials for a hosted connection [#create-oauth-credentials-for-a-hosted-connection] Go to **Google Auth Platform → Clients → Create client**, then choose **Web application**. Add `/auth/google/callback` as an authorized redirect URI. For example, a server available at `https://mail.example.com` uses: ```text https://mail.example.com/auth/google/callback ``` Copy the client ID and client secret, then configure the running instance: ```bash fluxmail oauth configure google \ --client-id .apps.googleusercontent.com ``` The change takes effect immediately. For Docker, prefix the command with `docker compose exec fluxmail`. In a managed deployment, you can instead set `GOOGLE_CLIENT_ID` with `GOOGLE_CLIENT_SECRET_FILE`; both values must be present, and changing them requires a restart. ### Create a hosted link through the API [#create-a-hosted-link-through-the-api] A product backend can create a hosted connection link without running the CLI. The API key needs `admin.accounts`, and its owner must still be an administrator: ```bash curl -X POST "$FLUXMAIL_PUBLIC_URL/api/v1/admin/connections" \ -H "Authorization: Bearer $FLUXMAIL_ADMIN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"provider":"gmail","ownerMemberId":"you@example.com"}' ``` The response contains `data.connectionUrl` and `data.expiresAt`. Send the URL to the user, but keep the admin API key on your backend. To reconnect an existing mailbox, send `reauthorizeAccountId` instead of `ownerMemberId`. The endpoint also accepts `provider: "outlook"`. ## Avoid seven-day token expiration with a custom app [#avoid-seven-day-token-expiration-with-a-custom-app] For an External app with a Testing publishing status, [Google expires the authorization after seven days](https://developers.google.com/identity/protocols/oauth2#expiration). Move the app to **In production** in Google Auth Platform if you want a longer-lived connection. Personal-use apps with fewer than 100 users do not have to complete Google verification, but Google may continue to show an unverified-app warning. Verification requirements differ if you make the app available more broadly. ## Reconnect Gmail later [#reconnect-gmail-later] If Google revokes or expires the token, list the accounts to find the account ID: ```bash fluxmail accounts list ``` Reconnect a local mailbox: ```bash fluxmail accounts add gmail --reauthorize ``` For Docker or HTTP, run the command inside the container: ```bash docker compose exec fluxmail \ fluxmail accounts add gmail --reauthorize ``` Open the printed link and choose the Google account that matches the mailbox you are reconnecting. Reauthorization updates the stored token for the same mailbox. It does not add another mailbox or change the mailbox owner. ## Connect through a proxy [#connect-through-a-proxy] If your server reaches Google through an HTTP proxy, set `HTTPS_PROXY` before starting Fluxmail. Gmail API and Google sign-in requests will use it. See [Outbound proxy](/docs/configuration#outbound-proxy) for `NO_PROXY` rules and variable precedence. ## How Gmail labels work [#how-gmail-labels-work] Fluxmail returns Gmail user labels in both folder and label listings. The folder listing lets clients navigate a label as a mailbox view. The label listing describes tags that can be added to or removed from messages, including the label colors configured in Gmail. Adding a label by name creates it when it does not exist. Removing a missing label has no effect. Use the dedicated read, star, archive, trash, and move actions for Gmail system labels. Continue with [Connect an MCP client](/docs/connect-an-mcp-client), [Build with REST](/docs/build-with-rest), or [Use the CLI](/docs/use-the-cli). --- # Connect Outlook / Exchange URL: https://fluxmail.ai/docs/connect-outlook-to-mcp Fluxmail connects to Microsoft 365 and Outlook.com through Microsoft Graph. You create the Microsoft Entra app registration, and Fluxmail stores its OAuth tokens on the server you run. This integration supports Exchange Online mailboxes in Microsoft 365 and personal Outlook.com accounts, including Hotmail addresses. For an on-premises Exchange server without Microsoft Graph access, use [IMAP and SMTP](/docs/connect-an-imap-mailbox). Mailbox aliases can be registered in Fluxmail and selected when sending. The alias must already belong to the mailbox in Microsoft 365 or Outlook.com. Fluxmail does not create aliases or grant delegated mailbox access. See [Send from another address](/docs/send-as-addresses). ## 1. Register the application [#1-register-the-application] 1. Open the [Microsoft Entra admin center](https://entra.microsoft.com/). 2. Go to **Identity > Applications > App registrations**, then select **New registration**. 3. Enter a name for the app. 4. Choose the supported account types. Select an option that includes personal Microsoft accounts if you need Outlook.com or Hotmail. 5. Register the application, then copy its **Application (client) ID**. The default `MICROSOFT_TENANT_ID=common` accepts work, school, and personal accounts when the app registration supports them. For a single-tenant app, set `MICROSOFT_TENANT_ID` to its Directory (tenant) ID or verified tenant domain. ## 2. Add Microsoft Graph permissions [#2-add-microsoft-graph-permissions] Open **API permissions** for the app registration and add these delegated Microsoft Graph permissions: * `User.Read` * `Mail.ReadWrite` * `Mail.Send` * `MailboxSettings.Read` Fluxmail also requests standard OpenID Connect and offline access scopes during sign-in so it can identify the mailbox and refresh access tokens. An Entra administrator may need to grant consent when organizational policy blocks user consent. ## 3. Choose a callback [#3-choose-a-callback] Add the redirect URI for each way you plan to run Fluxmail. One app registration can contain both local and hosted callbacks. | Setup | Platform | Redirect URI | | --------------------------- | ------------------------------- | ---------------------------------------------------- | | Local stdio or local Docker | Mobile and desktop applications | `http://localhost:8976/oauth/microsoft/callback` | | Remote server | Web | `/auth/microsoft/callback` | For the local callback, open **Authentication**, add the Mobile and desktop applications platform with the custom redirect URI, and enable **Allow public client flows**. For a remote server, add the Web platform and its public HTTPS callback. For example, a server at `https://mail.example.com` uses: ```text https://mail.example.com/auth/microsoft/callback ``` Create a client secret under **Certificates & secrets** for hosted connections. Copy the secret value when Entra displays it. Fluxmail does not need a client secret for the local callback. ## 4. Connect the mailbox [#4-connect-the-mailbox] For a fresh local instance, create the first administrator and log in: ```bash fluxmail setup --name "Your name" --email you@example.com ``` ### Local stdio [#local-stdio] Configure a public OAuth client, then start the browser consent flow: ```bash fluxmail oauth configure outlook \ --client-id \ --public-client fluxmail accounts add outlook ``` If the app is restricted to one tenant, include it when configuring the client: ```bash fluxmail oauth configure outlook \ --client-id \ --tenant-id \ --public-client ``` Fluxmail listens on `http://localhost:8976`, prints a Microsoft authorization URL, and waits for the redirect. Choose the mailbox you want to connect and approve access. If your browser runs on a different computer, such as when you use the CLI over SSH, the redirect to `localhost` fails to load after you approve access. Copy the full URL from the browser's address bar and paste it into the waiting terminal. Pasting needs an interactive terminal. You can also forward the port first with `ssh -L 8976:127.0.0.1:8976 you@server`. The command stops waiting after 10 minutes. ### Local Docker [#local-docker] Add the client ID to `.env` and leave `FLUXMAIL_PUBLIC_URL` unset: ```dotenv MICROSOFT_CLIENT_ID= # MICROSOFT_TENANT_ID=common ``` Start Fluxmail and run the mailbox command inside the container: ```bash docker compose up -d docker compose exec fluxmail \ fluxmail setup --name "Your name" --email you@example.com docker compose exec fluxmail \ fluxmail accounts add outlook ``` Docker Compose publishes the callback listener to `localhost:8976` on the host, so the browser can return to the waiting command. ### Remote server [#remote-server] Set the public server URL in the Docker environment, then configure the OAuth application through the running instance: ```dotenv FLUXMAIL_PUBLIC_URL=https://mail.example.com ``` ```bash docker compose up -d docker compose exec fluxmail \ fluxmail oauth configure outlook \ --client-id \ --tenant-id common ``` Fluxmail prompts for the client secret and stores the complete application encrypted in SQLite. The change takes effect immediately. Managed deployments can use `MICROSOFT_CLIENT_ID`, `MICROSOFT_TENANT_ID`, and `MICROSOFT_CLIENT_SECRET_FILE` instead. Start the mailbox command: ```bash docker compose exec fluxmail \ fluxmail accounts add outlook ``` Open the printed connection link in your browser, continue to Microsoft, and approve access. The link expires after 10 minutes and works once. ## Create hosted connection links through the API [#create-hosted-connection-links-through-the-api] A product backend can create a hosted link without running the CLI. The API key needs `admin.accounts`, and its owner must still be an administrator: ```bash curl -X POST "$FLUXMAIL_PUBLIC_URL/api/v1/admin/connections" \ -H "Authorization: Bearer $FLUXMAIL_ADMIN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"provider":"outlook","ownerMemberId":"you@example.com"}' ``` The response contains `data.connectionUrl` and `data.expiresAt`. Send the URL to the user, but keep the admin API key on your backend. To reconnect an existing mailbox, send `reauthorizeAccountId` instead of `ownerMemberId`. The endpoint also accepts `provider: "gmail"`. ## Reconnect Outlook later [#reconnect-outlook-later] List accounts to find the account ID: ```bash fluxmail accounts list ``` Reconnect the mailbox with the same flow used during setup: ```bash fluxmail accounts add outlook --reauthorize ``` For Docker, prefix the command with `docker compose exec fluxmail`. Choose the Microsoft account that matches the mailbox you are reconnecting. Reauthorization updates the stored tokens without changing the mailbox owner or access rules. Accounts connected before category support can keep reading and sending mail without reconnecting. Listing Outlook categories requires `MailboxSettings.Read`. If Fluxmail reports that this permission is missing, reauthorize the account after adding it to the Entra app registration. ## How Outlook categories work [#how-outlook-categories-work] Fluxmail exposes Outlook mail folders as folders and Outlook master categories as labels. Message label lists contain category names. Adding or removing a label updates the message's categories without replacing its other categories. If a category name is not in the master list, Outlook adds the name to the message without assigning a color. It does not appear in label listings. Continue with [Connect an MCP client](/docs/connect-an-mcp-client), [Build with REST](/docs/build-with-rest), or [Use the CLI](/docs/use-the-cli). --- # Deploy with Docker URL: https://fluxmail.ai/docs/deploy-with-docker The [`ghcr.io/churichard/fluxmail`](https://github.com/churichard/fluxmail/pkgs/container/fluxmail) image supports amd64 and arm64. Use Docker when MCP or REST clients connect over a network, or when several clients share one Fluxmail instance. ## Download the server files [#download-the-server-files] ```bash mkdir fluxmail && cd fluxmail curl -fsSLO https://raw.githubusercontent.com/churichard/fluxmail/main/docker-compose.yml curl -fsSL https://raw.githubusercontent.com/churichard/fluxmail/main/.env.example -o .env ``` Review `.env` before starting the service. ## Choose the public URL [#choose-the-public-url] If Docker and your browser run on the same computer, leave `FLUXMAIL_PUBLIC_URL` unset. Fluxmail will use its local OAuth listener on port 8976. For a remote deployment, expose Fluxmail through a public HTTPS address and set that address in `.env`: ```dotenv FLUXMAIL_PUBLIC_URL=https://mail.example.com ``` Your reverse proxy should forward traffic to port 8977. Fluxmail requires authentication for MCP, REST, and CLI requests. ## Start Fluxmail [#start-fluxmail] ```bash docker compose up -d docker compose exec fluxmail \ fluxmail setup --name "Your name" --email you@example.com docker compose exec fluxmail fluxmail status ``` ## Connect a mailbox [#connect-a-mailbox] ### Gmail or Google Workspace [#gmail-or-google-workspace] A local Docker setup can use Fluxmail's built-in Google Desktop client. A remote server needs a Google Web client with the server's callback URL. Follow [Connect Gmail / Google Workspace](/docs/connect-gmail-to-mcp) before running: ```bash docker compose exec fluxmail \ fluxmail accounts add gmail ``` The command prints a Google consent URL. On a remote server, it prints a one-time connection link that expires after 10 minutes. ### Microsoft 365 or Outlook.com [#microsoft-365-or-outlookcom] Complete the hosted setup in [Connect Outlook / Exchange](/docs/connect-outlook-to-mcp). Keep the public URL in `.env` because it is deployment configuration: ```dotenv FLUXMAIL_PUBLIC_URL=https://mail.example.com ``` Restart Fluxmail after changing `.env`, configure the OAuth application, then connect the mailbox: ```bash docker compose up -d docker compose exec fluxmail \ fluxmail oauth configure outlook \ --client-id docker compose exec fluxmail \ fluxmail accounts add outlook ``` The configure command prompts for the client secret and stores it encrypted in SQLite. In orchestrated deployments, mount the secret and set `MICROSOFT_CLIENT_SECRET_FILE` to its absolute path instead. Open the one-time link printed by the command. The link expires after 10 minutes. ### IMAP and SMTP [#imap-and-smtp] Pass the mailbox password through an environment variable so it does not appear in the command line: ```bash export IMAP_PASSWORD='your-app-password' docker compose exec -e IMAP_PASSWORD fluxmail \ fluxmail accounts add imap \ --email you@example.com \ --imap-host imap.example.com \ --smtp-host smtp.example.com \ --imap-password-env IMAP_PASSWORD ``` See [Connect IMAP/SMTP](/docs/connect-an-imap-mailbox) for provider settings and folder mapping. ## Create an HTTP API key [#create-an-http-api-key] MCP over HTTP and REST clients need an API key. Fluxmail displays the key once: ```bash docker compose exec fluxmail \ fluxmail apikey create --name desktop ``` The key can reach mailboxes available to its member. Use `--account ` to limit it to selected mailboxes, and see [Permissions](/docs/permissions) to choose a narrower permission profile. Continue with [Connect an MCP client](/docs/connect-an-mcp-client) or [Build with REST](/docs/build-with-rest). --- # Email search URL: https://fluxmail.ai/docs/email-search Fluxmail has one portable search syntax for Gmail, Outlook, and IMAP mailboxes. You can use it with `fluxmail emails search`, `fluxmail emails search-batch`, the `search_emails` and `search_emails_batch` MCP tools, or the REST search operations. ```text from:ann@example.com in:archive is:unread after:2026-07-01 quarterly report ``` Search terms use implicit AND. Fluxmail does not interpret `AND`, `OR`, or parentheses as boolean expressions. ## Filters [#filters] | Syntax | Meaning | | ------------------------------------- | ---------------------------------- | | `from:value` | Sender | | `to:value` | Recipient | | `subject:value` | Subject | | `in:role` | Portable folder role | | `is:read` or `is:unread` | Read state | | `is:starred` or `is:unstarred` | Starred state | | `has:attachment` or `-has:attachment` | Non-inline attachment state | | `after:YYYY-MM-DD` | Received on or after this UTC date | | `before:YYYY-MM-DD` | Received before this UTC date | Portable folder roles are `inbox`, `sent`, `drafts`, `archive`, `spam`, `trash`, and `all`. Custom folders are account specific. Use the structured `folder` filter after looking up the folder with `list_folders` or the REST folders endpoint. Dates use the message's received or provider internal time. `after` is inclusive and `before` is exclusive. Both values must be calendar dates, and `after` must be earlier than `before`. ## Quotes and literal text [#quotes-and-literal-text] Double quotes group spaces inside a value: ```text subject:"quarterly forecast" from:"Ann Example " ``` Inside quotes, escape `"` as `\"` and `\` as `\\`. Free text is always literal. A search for `"from:ann@example.com"` looks for that text instead of activating a sender filter. URLs, times, unrelated values containing a colon, `AND`, `OR`, and parentheses also remain text. Fluxmail may return a warning when a term looks like a mistyped operator. For example, `form:ann@example.com` remains literal text and produces a suggestion for `from:`. Quote the term when you intended it as text and do not want the warning. ## Provider-native search [#provider-native-search] Use `rawProviderQuery` when you need Gmail search syntax or Outlook KQL. Native queries are not portable and must target one compatible account. They are not part of the typed search string. Structured `text` is literal and cannot be combined with `rawProviderQuery`. Other structured filters combine with a native query using AND. IMAP supports Gmail native syntax only when the server advertises `X-GM-EXT-1`. Account capabilities report whether native syntax and portable folder roles are available, unavailable, or still unknown. Fluxmail rejects filters and native queries that the selected account reports as unavailable. Capabilities marked `unknown` are passed to the provider so it can discover support when the request runs. ## Attachments [#attachments] Fluxmail treats a message as having an attachment when its hydrated metadata contains at least one part whose disposition is not `inline`. This definition is the same across providers. Gmail's `has:attachment` operator has different behavior, so Fluxmail does not use it for portable attachment searches. Gmail may need to inspect several provider pages before it fills a result page, especially when searching for messages without attachments. ## Pagination [#pagination] Pass `nextPageToken` back with the same account, query, page size, snippet setting, and search context setting. Search page tokens expire after one hour. They are signed to prevent changes, but their contents are not encrypted. Replacing the Fluxmail instance encryption key also invalidates existing tokens. Every search page includes `exhausted`. A value of `true` means Fluxmail searched the full requested scope. When you omit the folder, that scope is all mail except Spam and Trash. An IMAP server's `\All` mailbox can define its own scope. Some filters require local checks after Fluxmail receives provider candidates. A response can include: ```json { "meta": { "nextPageToken": "...", "exhausted": false, "incomplete": true, "incompleteReason": "scan_limit", "inspectedCandidates": 1000 } } ``` An empty page confirms that there are no matches only when `exhausted` is `true`. Continue with `nextPageToken` when `incompleteReason` is `scan_limit` or `time_limit`. A provider can also return `provider_limit` when it cannot search beyond its own result cap. Search work has a 10-second soft budget and a 15-second deadline. Fluxmail returns a continuation at a safe boundary when it can. If the provider stalls before Fluxmail has a continuation point, the request fails with `provider_unavailable` and `reason: "search_timeout"`. ## Message previews [#message-previews] Set `includeSnippet` to `true` to request previews or `false` to suppress them. If you omit it, Gmail and Outlook return their native previews while IMAP avoids extra body downloads. For IMAP, Fluxmail downloads up to 16 KiB from the preferred text part and returns at most 300 characters. It prefers plain text and converts HTML when needed. A preview failure leaves the message metadata available and adds a warning to the page. The `capabilities.snippets` field tells you whether a provider includes previews without fetching message bodies. A value of `false` does not prevent you from requesting a preview with `includeSnippet`. ## Search context [#search-context] Set `includeSearchContext` to `true` to include a body excerpt around the search text. This option requires literal text from the typed query or the structured `text` field. Fluxmail rejects filter-only and provider-native searches that request context. Search context is separate from `includeSnippet`. A message can contain both. Fluxmail prefers the complete search phrase, then uses the earliest matching term when the phrase does not appear in the body. Matching is case insensitive and treats punctuation as literal text. Each message returns one of these values: | Status | Meaning | | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | | `matched` | `excerpt` contains the matching line, cropped to 300 Unicode characters when needed. | | `no_literal_match` | Fluxmail inspected the complete selected body but did not find the literal text. The provider may have matched headers, stemming, or other indexed content. | | `scan_limit` | Fluxmail reached the 256 KiB decoded body scan limit before finding a literal match. | | `unavailable` | Fluxmail could not read a suitable body or the optional body request failed. | Fluxmail reads at most 256 KiB of decoded body content for each result. It prefers plain text and converts HTML to readable text when no plain-text body exists. Attachments and attached messages are excluded. Gmail and Outlook may transfer the complete body because their APIs do not support the same bounded partial read as IMAP. Search context is off by default because it can add one body request per accepted result. On IMAP, Fluxmail uses a partial, non-marking body read. When an IMAP request asks for both a snippet and search context, Fluxmail derives both from the same download. An optional enrichment failure leaves the message metadata available, returns `unavailable`, and adds a warning to the page. ## Search several accounts [#search-several-accounts] Use `search_emails_batch`, `POST /api/v1/messages/search`, or `fluxmail emails search-batch` to run the same portable search against several accounts. A batch accepts 1 through 20 distinct accounts and searches up to three at a time. Each account has its own page and continuation token. The response keeps account groups in request order. One account can fail without discarding successful groups. The aggregate `exhausted` value is `true` only when every group is exhausted. To continue, send only the unfinished accounts with their tokens. Batch search accepts portable folder roles and rejects provider-native queries. --- # Local logs URL: https://fluxmail.ai/docs/logging Fluxmail keeps a local record of command, MCP, REST, mailbox connection, scheduled send, and license failures. It also records a small number of service events, such as server startup. Successful requests and tool calls are not logged. Logs stay on the machine where Fluxmail runs. Fluxmail does not upload them or include their text in anonymous telemetry. ## Read recent logs [#read-recent-logs] Show the latest 100 entries: ```bash fluxmail logs ``` Choose a different limit or show only errors: ```bash fluxmail logs --tail 250 fluxmail logs --level error ``` Use `--json` to print the stored JSON record for each entry: ```bash fluxmail logs --level warn --json ``` For Docker, run the same command inside the container: ```bash docker compose exec fluxmail fluxmail logs --tail 100 ``` ## Files and disk limits [#files-and-disk-limits] The active file is `/logs/fluxmail.jsonl`. Fluxmail rotates it at 5 MiB and keeps three older files. The entire directory is limited to 20 MiB. Fluxmail batches writes, limits repeated errors, and caps sustained log output at 1 MiB per hour after a 64 KiB burst. When it drops repeated or excessive records, it writes a `logging.records_suppressed` entry after capacity becomes available. If the file cannot be written, email operations continue and Fluxmail reports the problem on the console at most once per hour. The supplied Docker Compose file also limits container console logs to three 5 MiB files. ## Configure logging [#configure-logging] `FLUXMAIL_LOG_LEVEL` accepts `info`, `warn`, `error`, or `off`. The default is `info`. `FLUXMAIL_LOG_DESTINATION` accepts `both`, `file`, or `console`. The default is `both`. One shot CLI commands still show errors in the terminal without printing a duplicate log line. For example, keep errors in the rotating file without writing structured events to the console: ```toml [logging] level = "error" destination = "file" ``` Environment variables take precedence over `config.toml`. Restart Fluxmail after changing either setting. ## Private information [#private-information] Fluxmail does not log request bodies, response bodies, email content, headers, command arguments, credentials, configuration values, or raw provider responses. It also redacts common token and secret formats from error strings. Error messages and stack traces can still contain email addresses, local file paths, or details returned by a provider. Review log entries before sharing them with anyone. --- # Overview URL: https://fluxmail.ai/docs Fluxmail is self-hosted email infrastructure for agents and apps. It connects to Gmail, Microsoft 365, Outlook.com, and IMAP/SMTP mailboxes, then provides one service for working with them. ## Features [#features] * 📬 Connect Gmail, Google Workspace, Microsoft 365, Outlook.com, and IMAP/SMTP mailboxes to one instance. * 🤖 Give agents MCP tools to list, search, read, draft, reply, forward, send, schedule, and organize email. * 🔌 Use the same mailbox operations from the versioned REST API and CLI. * 🧵 Fetch complete messages and threads, work across several mailboxes, and download attachments. * 🗂️ Mark mail as read, star or archive it, move it between folders, send it to Trash, and manage Gmail labels or Outlook categories. * 🔐 Limit each client to selected mailboxes and actions with permission profiles or custom policies. * 👥 Add members and choose which mailboxes each can access on Business and Enterprise plans. * 🏠 Run Fluxmail locally or in Docker while keeping its database and encrypted provider credentials on your infrastructure. ## Choose an interface [#choose-an-interface] | Interface | Use it for | | --------- | -------------------------------------------------------------------------------------------- | | MCP | Give AI agents tools to read, search, draft, send, and organize email. | | REST API | Add email to apps, internal tools, and backend workflows through a versioned JSON API. | | CLI | Install and run Fluxmail, connect mailboxes, manage members and access, and create API keys. | MCP and REST use the same mailbox operations, permissions, and provider integrations. The CLI configures and runs that service. You do not need a separate Gmail, Microsoft Graph, or IMAP integration for each client. ## How it works [#how-it-works] You run Fluxmail on your computer or on a server you control. Agents connect over MCP, apps use the REST API, and the CLI manages either a local or remote named instance. The CLI signs in as a Fluxmail member. Local MCP clients use that member session over stdio, while remote MCP clients use a scoped API key over Streamable HTTP. ```text Local agents -> authenticated MCP stdio session -> Fluxmail -> Gmail API Remote agents -> scoped MCP HTTP API key ---------> -> Microsoft Graph Apps and jobs -> REST API ------------------------> -> IMAP and SMTP CLI operators -> authenticated control plane ----> ``` Fluxmail stores its SQLite database and encrypted provider credentials on the machine where it runs. It does not copy email content to a service operated by Fluxmail. An MCP client may send content returned by Fluxmail to its model provider, depending on how that client works. ## Supported mailboxes [#supported-mailboxes] | Provider | Connection method | Notes | | ----------------------------- | ------------------------------------- | -------------------------------------------------------------------------------------------------------- | | Gmail and Google Workspace | Gmail API with OAuth | Fluxmail includes an OAuth app for local connections. Hosted connections need your own Google Cloud app. | | Microsoft 365 and Outlook.com | Microsoft Graph with OAuth | You create and control the Microsoft Entra app registration. | | Other email providers | IMAP for reading and SMTP for sending | The provider must allow IMAP and SMTP access. Some providers require an app password. | These guides use **mailbox** for a connected email address. The CLI and API call the same resource an **account**, so commands such as `fluxmail accounts list` and fields such as `accountId` keep that name. You can connect several mailboxes to one Fluxmail instance. Members and mailbox access rules decide which mailboxes each person can reach. Permission profiles separately control whether a client can only read mail, manage drafts and folders, or send and permanently delete messages. ## Choose where to run it [#choose-where-to-run-it] | Setup | Best for | Available interfaces | | ----------------- | ------------------------------------------------------- | ------------------------------------------------ | | Local process | One person using an agent on the same computer | MCP over stdio, plus the CLI | | Local HTTP server | Local apps, scripts, or MCP clients that connect by URL | REST API, MCP over Streamable HTTP, plus the CLI | | Docker server | Remote access, shared instances, or several clients | REST API, MCP over Streamable HTTP, plus the CLI | The [Quickstart](/docs/quickstart) installs Fluxmail and connects the first mailbox. See [Deploy with Docker](/docs/deploy-with-docker) for a remote or shared server. [Authentication and instances](/docs/authentication-and-instances) explains member sessions, remote CLI profiles, and API keys. For provider-specific steps, see [Connect Gmail / Google Workspace](/docs/connect-gmail-to-mcp), [Connect Outlook / Exchange](/docs/connect-outlook-to-mcp), or [Connect IMAP/SMTP](/docs/connect-an-imap-mailbox). ## Read next [#read-next] * [Connect an MCP client](/docs/connect-an-mcp-client) covers stdio and Streamable HTTP setup for supported clients. * [MCP tools](/docs/tools) lists the email operations available to agents. * [Build with REST](/docs/build-with-rest) walks through common app and backend requests. * [Use the CLI](/docs/use-the-cli) covers common administrative workflows. * [CLI reference](/docs/cli) lists every command and option. * [Permissions](/docs/permissions) explains profiles, custom policies, and mailbox scope. * [Configuration](/docs/configuration) covers server settings, storage paths, and telemetry. * [Teams and plans](/docs/teams-and-plans) covers members, shared mailboxes, and plan limits. * [Authentication and instances](/docs/authentication-and-instances) covers login, enrollment, sessions, and remote CLI profiles. * [Architecture](/docs/architecture) explains data storage and the server's internal structure. --- # Permissions URL: https://fluxmail.ai/docs/permissions Fluxmail can limit the email actions available to each MCP or REST connection. Give a research client read-only access, or let an inbox organizer manage messages without granting send or permanent-delete access. Permissions control which MCP tools Fluxmail exposes and which REST routes or message actions a key can call. Mailbox scope is separate from permissions. The member and optional mailbox allowlist decide which mailboxes a connection can reach. The permission profile decides what it can do with those mailboxes. Fluxmail applies both checks to every connection. ## Choose a permission profile [#choose-a-permission-profile] | Profile | What it allows | Capabilities | | ------------ | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | | `read-only` | Read and search mail, inspect folders, labels, and scheduled sends, and download attachments. | `mail.read` | | `read-write` | Read mail, manage drafts, organize messages, and move messages to or from Trash. | `mail.read`, `mail.drafts`, `mail.organize`, `mail.trash` | | `full` | Use every Fluxmail email capability, including sending mail and permanently deleting messages. | `mail.read`, `mail.drafts`, `mail.organize`, `mail.trash`, `mail.delete`, `mail.send` | Fluxmail uses `full` when you do not choose a profile. Set a narrower profile for clients that do not need every email action. ## Limit a local stdio connection [#limit-a-local-stdio-connection] Pass a profile when your MCP client launches Fluxmail: ```bash fluxmail stdio --profile read-only ``` For a client config file, put the profile in the argument list: ```json { "mcpServers": { "fluxmail": { "command": "fluxmail", "args": [ "stdio", "--profile", "read-only" ] } } } ``` ## Limit an HTTP connection [#limit-an-http-connection] HTTP permissions belong to the API key. Each key also belongs to a member. Create a separate key for each MCP or REST client so you can change or revoke one connection without affecting the others. ```bash fluxmail apikey create \ --name research-agent \ --profile read-only fluxmail apikey create \ --name inbox-agent \ --profile read-write ``` The key is shown once. `fluxmail apikey list` shows each key ID and permission profile without revealing the secret. Change an existing key by its ID: ```bash fluxmail apikey permissions --profile read-only ``` Existing keys and keys created without permission options use `full`. HTTP MCP requests always require an API key. REST accepts either a member session or an API key, except for its public login, enrollment, reset redemption, discovery, and health routes. ## Administrative capabilities [#administrative-capabilities] Administrative access is separate from mail access: | Capability | What it allows | | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | | `admin.accounts` | Connect and reauthorize mailboxes, test IMAP and SMTP settings, update IMAP folder mappings, and configure Outlook or IMAP sender addresses. | | `admin.members` | Invite, suspend, activate, promote, demote, and remove members. It also permits session revocation. | | `admin.api_keys` | Create, update, list, and revoke API keys. | | `admin.license` | Read, activate, and deactivate the instance license. | | `admin.audit` | Read security audit events. | Add administrative capabilities to a named mail profile with repeated `--admin` options: ```bash fluxmail apikey create \ --name account-operator \ --profile read-only \ --admin admin.accounts ``` When changing an existing key, `--admin` keeps its current named mail profile and replaces its administrative capabilities. A custom policy has no separate administrative list, so pass every allowed capability with `--allow` instead. For a custom policy, put both mail and administrative capabilities in repeated `--allow` options. Fluxmail rejects administrative capabilities for non-admin members. It also checks the owner's current role and mailbox grants on every request. Treat `admin.api_keys` as sensitive authority. Administrator sessions remain the recovery path if an administrative key is revoked or narrowed. ## Build a custom policy [#build-a-custom-policy] Use repeated `--allow` options when the named profiles are too broad. List the available capabilities first: ```bash fluxmail apikey capabilities ``` | Capability | Actions | | --------------- | ------------------------------------------------------------------------------------------------------------------------------- | | `mail.read` | List, search, and read mail; inspect status, folders, labels, and sender addresses; list scheduled sends; download attachments. | | `mail.drafts` | Create, update, and delete drafts; cancel scheduled sends. | | `mail.organize` | Mark read or unread, star, archive, move, and manage labels or Outlook categories. | | `mail.trash` | Move messages to or from Trash. | | `mail.delete` | Permanently delete messages. | | `mail.send` | Send or schedule messages. | The generic `move` action cannot target Trash or Archive by folder ID, role, or display name. It also cannot move messages out of Trash. Use `trash` to move messages into Trash, `untrash` to restore them, and `archive` to move non-Trash messages into Archive. These restrictions keep Trash access behind the `mail.trash` capability. Create a custom HTTP key like this: ```bash fluxmail apikey create \ --name drafting-agent \ --allow mail.read \ --allow mail.drafts ``` The same options work with stdio: ```bash fluxmail stdio \ --allow mail.read \ --allow mail.organize ``` Some workflows need more than one capability. Reply drafts need `mail.drafts` and `mail.read`; replies need `mail.send` and `mail.read`; forwarding also needs `mail.send` and `mail.read`. Draft lookup needs `mail.drafts`. Send preview and delivery status need `mail.send`; previewing an existing draft also needs `mail.drafts`, and previewing a reply needs `mail.read`. Body continuation and attachment resources need `mail.read`. The same mailbox access rules apply to these operations. --- # Quickstart URL: https://fluxmail.ai/docs/quickstart Fluxmail runs on your computer or on a server you control. This guide gets the service ready for MCP, REST, and CLI clients. ## 1. Install Fluxmail [#1-install-fluxmail] Choose a local installation for personal use and local development. Use Docker when clients will connect over a network or several people share the instance. ### Local installation [#local-installation] The local installation requires Node.js 20.20.x, or Node.js 22.22 or newer. ```bash npm install -g fluxmail ``` Check that your shell can find the command: ```bash which fluxmail ``` Some desktop apps start with a limited `PATH`. If an app cannot find `fluxmail`, use the absolute path printed by `which fluxmail` in that app's configuration. To run Fluxmail without a global installation, replace `fluxmail` in local commands with `npx -y fluxmail@latest`. Create the first administrator and log in. Fluxmail asks for a password without displaying it: ```bash fluxmail setup --name "Your name" --email you@example.com ``` ### Docker installation [#docker-installation] Create a directory for Fluxmail and download the server files: ```bash mkdir fluxmail && cd fluxmail curl -fsSLO https://raw.githubusercontent.com/churichard/fluxmail/main/docker-compose.yml curl -fsSL https://raw.githubusercontent.com/churichard/fluxmail/main/.env.example -o .env docker compose up -d docker compose exec fluxmail \ fluxmail setup --name "Your name" --email you@example.com ``` Commands in the rest of this guide use the local `fluxmail` form. With Docker, run mailbox and status commands through `docker compose exec fluxmail`. For example: ```bash docker compose exec fluxmail fluxmail status ``` Read [Deploy with Docker](/docs/deploy-with-docker) before exposing Fluxmail outside your computer. Remote OAuth connections need a public HTTPS URL and provider settings. The login created by `fluxmail setup` lasts for up to 90 days. See [Authentication and instances](/docs/authentication-and-instances) for login, enrollment, sessions, and remote CLI profiles. ## 2. Connect a mailbox [#2-connect-a-mailbox] Choose your email provider. ### Gmail or Google Workspace [#gmail-or-google-workspace] Start the browser consent flow: ```bash fluxmail accounts add gmail ``` Local connections use Fluxmail's built-in Google Desktop OAuth client. A remote server needs a Google Web client. See [Connect Gmail / Google Workspace](/docs/connect-gmail-to-mcp) for remote setup, custom OAuth credentials, and reconnection help. ### Microsoft 365 or Outlook.com [#microsoft-365-or-outlookcom] Microsoft mail requires an Entra app registration. Complete the local or hosted app setup in [Connect Outlook / Exchange](/docs/connect-outlook-to-mcp). For a local installation, configure a public client and connect the mailbox: ```bash fluxmail oauth configure outlook \ --client-id \ --public-client fluxmail accounts add outlook ``` For Docker, put the client ID in `.env` instead. The Outlook guide lists the client secret and public URL required for a remote server. Recreate the container, then connect the mailbox: ```dotenv MICROSOFT_CLIENT_ID= ``` ```bash docker compose up -d docker compose exec fluxmail \ fluxmail accounts add outlook ``` ### IMAP and SMTP [#imap-and-smtp] Use the server names supplied by your email provider. Fluxmail asks for the mailbox password without displaying it: ```bash fluxmail accounts add imap \ --email you@example.com \ --imap-host imap.example.com \ --smtp-host smtp.example.com ``` See [Connect IMAP/SMTP](/docs/connect-an-imap-mailbox) for app passwords, custom ports and usernames, folder mapping, and Sent-copy behavior. ## 3. Check the setup [#3-check-the-setup] ```bash fluxmail status fluxmail accounts list ``` The connected mailbox should appear as ready. If Fluxmail reports that the mailbox needs attention, follow the provider guide linked above. ## Choose an interface [#choose-an-interface] Fluxmail is now ready. Continue with the interface your client uses: | Interface | Next guide | | --------- | ---------------------------------------------------- | | MCP | [Connect an MCP client](/docs/connect-an-mcp-client) | | REST API | [Build with REST](/docs/build-with-rest) | | CLI | [Use the CLI](/docs/use-the-cli) | MCP and REST expose email operations. The CLI connects mailboxes, manages access, creates API keys, and runs the service. --- # Send from another address URL: https://fluxmail.ai/docs/send-as-addresses Fluxmail can send from another address that belongs to the connected mailbox. The provider must already know and allow the address. Fluxmail does not create or verify aliases. ## Provider setup [#provider-setup] Gmail aliases come from Gmail's Send mail as settings. Fluxmail lists the primary address and verified aliases, including each identity's display name and Reply-To address. Add or verify an alias in Gmail before using it through Fluxmail. Outlook and IMAP aliases are configured in Fluxmail after an administrator creates them with the mail provider. Add an existing alias with: ```bash fluxmail accounts send-as add sales@example.com --name "Sales" ``` Remove a configured alias with: ```bash fluxmail accounts send-as remove sales@example.com ``` These commands change Fluxmail's allowed sender list. They do not change the mailbox or provider account. Microsoft 365, Outlook.com, and SMTP servers can still reject an address that the provider has not assigned to the mailbox. List the addresses available for an account: ```bash fluxmail accounts send-as list ``` You can also use the `list_send_as` MCP tool or `GET /api/v1/accounts/{accountId}/send-as`. Listing requires `mail.read`. Replacing the configured Outlook or IMAP list through REST requires `admin.accounts`: ```http PUT /api/v1/accounts/acct_123/send-as Content-Type: application/json { "identities": [ { "email": "sales@example.com", "name": "Sales" } ] } ``` The `PUT` request replaces the full configured alias list for that account. Gmail aliases remain managed by Gmail. ## Choose a sender [#choose-a-sender] Pass `from` through MCP or REST. In the CLI, use `--from` with send, draft, or forward commands: ```bash fluxmail emails send \ --from sales@example.com \ --to customer@example.com \ --subject "Order update" \ --body "Your order has shipped." ``` The sender address must match an available identity. Matching ignores letter case, but it does not remove dots or plus tags. Fluxmail rejects unknown and unverified addresses before delivery. New messages and forwards use the connected account address when `from` is omitted. Replies look for an owned address in the original To field, then Cc. The first match becomes the sender. If no address matches, Fluxmail uses the connected account address. A reply to a message sent from one of your own aliases reuses that alias. Reply-all removes every known identity for the account from the recipient list. An address that appears only in Bcc does not affect automatic sender selection. ## Drafts and scheduled messages [#drafts-and-scheduled-messages] A draft keeps its sender when you update it without `from`. To change the sender, update the draft first. Sending a draft by ID does not accept `from` or other message fields. Scheduled messages store the sender in the provider draft. Fluxmail checks an alternate sender again before delivery. If an administrator removes the alias before the send time, the schedule fails instead of switching to the primary address. --- # Teams & plans URL: https://fluxmail.ai/docs/teams-and-plans ## Members and mailbox access [#members-and-mailbox-access] Every Fluxmail instance has at least one **member**. A personal instance uses one member to identify its owner. Business and Enterprise instances can add more people and decide which mailboxes each person can reach. ```bash # A fresh instance starts with one logged-in administrator fluxmail setup --name "Ada Lovelace" --email ada@example.com # Administrators invite more people fluxmail members add --name "Grace Hopper" --email grace@example.com fluxmail members list # Members connect mailboxes they own fluxmail accounts add gmail # Reassign an existing mailbox fluxmail accounts assign --owner grace@example.com # Choose who else can reach it fluxmail accounts access --owner-only fluxmail accounts access --shared fluxmail accounts access --share-with ada@example.com ``` `fluxmail members add` prints an enrollment code once. Send it to the new member through a private channel. They add the instance and set their password with `fluxmail login --instance --server --enroll`. `--owner-only` makes a mailbox private to its owner. `--shared` makes it available to every active member, including members added later. Repeat `--share-with` to give selected members access. The administrator role permits member, license, key, and mailbox metadata management. It does not grant access to another member's private mail. Stdio uses the member logged in to the selected local instance. You can limit a connection to selected mailboxes that member can already reach: ```bash # Local connection for the logged-in member, limited to one mailbox fluxmail stdio --account # HTTP connection for the logged-in member, limited to one mailbox and read-only actions fluxmail apikey create \ --name "ada laptop" \ --account \ --profile read-only ``` Update an HTTP key's mailbox allowlist without replacing the key: ```bash fluxmail apikey accounts --account fluxmail apikey accounts --all-accounts ``` Member and mailbox scope control which mailboxes a connection can reach. Its [permission profile](/docs/permissions) separately controls which email actions the client can take. Use one key per client so you can change its scope, change its permissions, or revoke it without interrupting other connections. ## Plans and licensing [#plans-and-licensing] Self-hosting is free on the **Personal** plan: 3 connected mailboxes and 1 member. Pro raises the mailbox limit for one person. Each member included in your Business plan raises the mailbox limit by 20. The limit applies to the instance, so one person can connect every allotted mailbox. You choose which members can access each mailbox. Contact us about Enterprise if you need more than 50 members. See [pricing](/pricing) for current limits. You can buy Pro or Business from the pricing page. Stripe returns you to Fluxmail after payment and shows your license key. Copy it then, and keep it private. Use **Manage subscription** on the pricing page or license screen to update your card, view invoices, change plans or your member limit, or cancel. Stripe asks for the email used at checkout and sends a one-time passcode before opening billing details. Stripe billing emails also include the same portal link. Unlock a paid plan with your license key: ```bash fluxmail license activate fluxmail license status ``` Fluxmail prompts for the key without displaying it. For automation, use `fluxmail license activate --key-file /absolute/path/to/license`, or pass `-` to read from stdin. An administrative REST client can read the same status from `GET /api/v1/admin/license`, activate a key with `POST /api/v1/admin/license/activate`, and deactivate it with `DELETE /api/v1/admin/license`. An API key needs `admin.license`; an administrator's member session can call the routes directly. The status response never includes the configured license key. REST cannot replace or remove a key supplied through `FLUXMAIL_LICENSE_KEY`. One license activates one instance, and enforcement keeps working offline. If you schedule a cancellation, the paid plan works until the end of the billing period. After the subscription ends or a payment fails, the instance drops back to Personal limits. Deactivating, downgrading, or lapsing never deletes mailboxes or data. Lowering the member limit takes effect at the end of the billing period. If the instance then has more mailboxes or members than the new limits allow, Fluxmail keeps working for 7 days and warns administrators in the CLI, `fluxmail license status`, and MCP tool results. You can't add mailboxes or members during that time. Remove the extras or increase your member limit before the date in the warning. After that, email tools stop working until usage fits the plan. The CLI keeps working so you can remove mailboxes or members. ## Software license [#software-license] Fluxmail is source available under the [Elastic License 2.0](https://github.com/churichard/fluxmail/blob/main/LICENSE.md). You may use, modify, create derivative works, and redistribute it subject to that license. A fork does not need a paid Fluxmail subscription merely because it is a fork. Without a valid paid key, Fluxmail uses the Personal plan with 3 mailboxes and 1 member. Official Pro, Business, and Enterprise entitlements require a valid Fluxmail license key. ELv2 does not allow you to change or circumvent license key functionality or remove functionality protected by a key. It also does not allow you to provide Fluxmail to third parties as a hosted or managed service that exposes a substantial set of its features. The software license does not grant rights to Fluxmail names or logos beyond applicable law. Their use is subject to the [Fluxmail Terms of Service](https://fluxmail.ai/terms). --- # Troubleshooting URL: https://fluxmail.ai/docs/troubleshooting Start by checking the service and connected mailboxes: ```bash fluxmail status fluxmail accounts list ``` Show recent warnings and errors with: ```bash fluxmail logs --level warn ``` For Docker, prefix each command with `docker compose exec fluxmail`. ## The fluxmail command is not found [#the-fluxmail-command-is-not-found] Check whether your shell can find the command: ```bash which fluxmail ``` If that prints nothing, install Fluxmail globally or run it through `npx`: ```bash npm install -g fluxmail npx -y fluxmail@latest status ``` Some apps use a limited `PATH`. Run `which fluxmail` in your terminal and use the returned absolute path in the app's configuration. ## The browser cannot finish connecting a mailbox [#the-browser-cannot-finish-connecting-a-mailbox] Local OAuth connections listen for the browser redirect on port 8976 of the computer running the CLI. If your browser runs on another computer, the page fails to load after you approve access. Copy the full URL from the address bar and paste it into the terminal where the command is waiting, or forward the port with `ssh -L 8976:127.0.0.1:8976 you@server`. Pasting needs an interactive terminal. If another program is using port 8976 and you run the command in one, Fluxmail asks you to paste the URL instead. When Docker Compose is using the port, run the command inside the container with `docker compose exec fluxmail fluxmail accounts add gmail` or `outlook` so the mailbox is saved there. The command stops waiting after 10 minutes. If it times out, run it again to get a new authorization URL. A remote server needs `FLUXMAIL_PUBLIC_URL` set to its public HTTPS address. Gmail also needs a Google Web client, and Outlook needs a Microsoft Entra client secret. Follow [Deploy with Docker](/docs/deploy-with-docker) and the setup guide for [Gmail](/docs/connect-gmail-to-mcp) or [Outlook](/docs/connect-outlook-to-mcp). ## A mailbox needs to be reconnected [#a-mailbox-needs-to-be-reconnected] Run `fluxmail status` to confirm which mailbox needs attention. Then follow the reconnection steps for [Gmail](/docs/connect-gmail-to-mcp), [Outlook](/docs/connect-outlook-to-mcp), or [IMAP/SMTP](/docs/connect-an-imap-mailbox). Reconnecting updates the saved credentials without changing the mailbox owner or access rules. ## MCP or REST returns 401 [#mcp-or-rest-returns-401] HTTP clients must send the API key as a bearer token: ```text Authorization: Bearer fmk_... ``` Fluxmail shows an API key only when you create it. If the key was lost or revoked, create a new one and update the client. ## MCP or REST returns 403 [#mcp-or-rest-returns-403] The API key does not have permission for the requested operation or mailbox. Check its permission profile and mailbox allowlist: ```bash fluxmail apikey list ``` See [Permissions](/docs/permissions) to change the profile or mailbox scope. ## A Docker server does not respond [#a-docker-server-does-not-respond] Check the container status and recent logs: ```bash docker compose ps docker compose logs --tail=100 fluxmail docker compose exec fluxmail fluxmail logs --level warn ``` Confirm that port 8977 is reachable and that your reverse proxy forwards requests to it. See [Deploy with Docker](/docs/deploy-with-docker) for the expected public URL and authentication settings. ## A configuration import fails [#a-configuration-import-fails] `fluxmail config migrate` preserves the source file whether the command succeeds or fails. Read the error before changing any files. A key mismatch means the configured key differs from `/encryption.key` or cannot decrypt the existing database. Restore the key that was used with the database, then retry the command. Do not replace the key just to clear the error. Provider credentials and encrypted instance settings cannot be decrypted with a different key. If `config.toml` already exists, move it aside only when the env file should replace its deployment settings. After a successful import, run `fluxmail config show` and `fluxmail oauth status` before removing the old file. ## An OAuth application cannot be changed [#an-oauth-application-cannot-be-changed] Run `fluxmail oauth status` and check the source. An application with an `environment` or `environment-file` source is controlled by deployment overrides. Remove the complete provider override group, restart Fluxmail, then run `fluxmail oauth configure` or `fluxmail oauth reset` again. --- # Use the CLI URL: https://fluxmail.ai/docs/use-the-cli The Fluxmail CLI can read, draft, send, schedule, and organize email. It also configures and runs the service. Mail commands call the same authenticated REST operations for local and remote instances, so permissions and mailbox access rules stay the same across CLI, MCP, and REST. Complete the [Quickstart](/docs/quickstart) before using the workflows below. ## Check the instance [#check-the-instance] ```bash fluxmail status fluxmail accounts list fluxmail members list ``` `fluxmail status` reports provider availability, connected mailboxes, and mailboxes that need to be reauthorized. ## Choose a mailbox [#choose-a-mailbox] Mail commands use the only accessible mailbox when there is exactly one. If you can access several mailboxes, pass the global account option with an account ID or email address: ```bash fluxmail --mail-account you@example.com emails list --folder inbox fluxmail -a labels list ``` Fluxmail returns an error when it cannot choose one mailbox safely. ## Read and search email [#read-and-search-email] List inbox messages, search across mail, or fetch a complete message or thread: ```bash fluxmail emails list --folder inbox --read false --page-size 20 fluxmail emails search "from:ann@example.com is:unread quarterly report" --include-search-context true fluxmail emails search-batch "subject:invoice is:unread" --account --account fluxmail emails get fluxmail threads get fluxmail emails list --all --max-results 1000 ``` The search string uses Fluxmail's [portable search syntax](/docs/email-search). Add `--include-snippet true` to request IMAP previews, or pass `false` to suppress previews. Add `--include-search-context true` to include an excerpt around literal search text. List responses include `meta.nextPageToken` when another page is available. Pass it back with `--page-token` and the same query, page size, snippet setting, and search context setting. Check `meta.exhausted` before treating an empty page as a confirmed negative result. Use `--all` on `emails list` or `emails search` to follow every page. It stops after 1,000 messages by default. Set `--max-results` to another limit up to 10,000. Set the global `--timeout ` option when a slow mailbox needs more than the default 30 seconds per request. `emails search-batch` accepts 1 through 20 repeated `--account` options. It prints every account group and exits nonzero if any group fails. Use `--input ` to send an exact batch request with per-account continuation tokens. Folders are navigable mailbox locations. Labels are Gmail user labels or Outlook categories: ```bash fluxmail folders list fluxmail labels list ``` Gmail user labels appear in both listings because Gmail uses them as mailbox views and message tags. IMAP mailboxes support folders but not labels. ## Draft, send, and forward [#draft-send-and-forward] Build a message with flags: ```bash fluxmail drafts create \ --to ann@example.com \ --subject "Quarterly report" \ --body-file report.txt \ --attach report.pdf fluxmail drafts get fluxmail emails send \ --to ann@example.com \ --subject "Quarterly report" \ --body "The report is attached." \ --attach report.pdf \ --idempotency-key quarterly-report-2026-09 ``` Use `--html` or `--html-file` for an HTML body. Repeat `--to`, `--cc`, `--bcc`, and `--attach` as needed. If standard input is redirected and no body option is present, Fluxmail uses standard input as the plain-text body. For plain-text email, keep each prose paragraph on one continuous line in `--body`, a body file, or standard input. Use a blank line between paragraphs. Fluxmail preserves line breaks, including those in lists and signatures. Reply, send an existing draft, schedule delivery, or forward a message: ```bash fluxmail emails preview --reply-to --reply-all --body "Thanks, everyone." fluxmail emails send --reply-to --reply-all --body "Thanks, everyone." --idempotency-key reply-2026-09 fluxmail emails send --draft --idempotency-key draft-2026-09 fluxmail emails send --to ann@example.com --body "Later" --send-at 2026-10-01T12:00:00Z --idempotency-key later-2026-09 fluxmail emails forward --to lee@example.com --no-attachments --idempotency-key forward-2026-09 fluxmail emails delivery-status ``` Every send and forward needs an idempotency key that you choose. Save the key with the request and reuse it if the command times out or you need to check the result. The response contains an `operationId`. Use `emails delivery-status` to inspect it. If the status is `uncertain`, inspect the recipient mailbox or sent folder before sending again. Reusing the key never starts a second delivery. ## Organize messages [#organize-messages] Apply one action to one or more message IDs: ```bash fluxmail emails modify mark-read fluxmail emails modify archive fluxmail emails modify move --folder Projects fluxmail emails modify add-labels --label Customer ``` The available actions are `mark-read`, `mark-unread`, `star`, `unstar`, `archive`, `trash`, `untrash`, `delete`, `move`, `add-labels`, and `remove-labels`. Label actions work with Gmail labels and Outlook categories. A modify request accepts up to 100 distinct message IDs. Its result lists `succeededIds`, `failed` entries with safe error codes, and `uncertainIds`. Check uncertain messages before retrying. Other IDs continue processing when one fails. List or cancel scheduled sends: ```bash fluxmail scheduled list fluxmail scheduled cancel ``` ## Download attachments [#download-attachments] Choose the destination path explicitly: ```bash fluxmail attachments download --output ./report.pdf ``` Fluxmail will not replace an existing file unless you pass `--force`. Attachment IDs are opaque, so pass them exactly as returned. The command prints JSON metadata after it writes the attachment. ## Send exact REST JSON [#send-exact-rest-json] Draft, send, forward, and modify commands accept an exact REST request body from a file or standard input: ```bash fluxmail emails send --input request.json --idempotency-key request-2026-09 fluxmail emails modify --input - < request.json ``` `--input` cannot be combined with flags that build the same request body. Send and forward commands still accept `--idempotency-key` with JSON input. ## Script output and exit codes [#script-output-and-exit-codes] The default output is a JSON envelope with `data`, plus `meta` and `warnings` when present. Mail, account list, and root status commands return their API data in `data`. Other management commands wrap their displayed lines in `data`; interactive setup and connection flows still print prompts directly. Use the root `--format table` option for a compact display or `--format ndjson` for one record per line. Errors in JSON and NDJSON mode go to stderr as JSON. The exit code is `0` for success, `2` for invalid input, `3` for partial or uncertain results, `4` for access errors, `5` for provider or network errors, and `1` for internal or uncategorized errors. Scripts should inspect the response as well as the exit code. ## Run the HTTP server [#run-the-http-server] ```bash fluxmail serve ``` The server listens on port 8977 by default. It provides MCP at `/mcp` and REST at `/api/v1`. For a local MCP client that uses stdio, the client launches this command instead: ```bash fluxmail stdio ``` See [Connect an MCP client](/docs/connect-an-mcp-client) for client configuration and transport options. ## Manage mailboxes and members [#manage-mailboxes-and-members] Connect another mailbox or list the existing mailboxes: ```bash fluxmail accounts add gmail fluxmail accounts list ``` Administrators can invite members and share mailboxes with them: ```bash fluxmail members add --name "Another person" --email person@example.com fluxmail accounts access --share-with person@example.com ``` See [Teams and plans](/docs/teams-and-plans) for mailbox sharing and plan limits. ## Manage API keys [#manage-api-keys] Create a key for an HTTP MCP or REST client: ```bash fluxmail apikey create --name local-client ``` Fluxmail shows the key once. You can list, change, or revoke keys without exposing their stored secrets: ```bash fluxmail apikey list fluxmail apikey permissions --profile read-only fluxmail apikey revoke ``` See [Permissions](/docs/permissions) for profiles, custom capabilities, and mailbox restrictions. ## Use the CLI with Docker [#use-the-cli-with-docker] Prefix commands with `docker compose exec fluxmail`: ```bash docker compose exec fluxmail fluxmail status docker compose exec fluxmail fluxmail accounts list ``` See [Deploy with Docker](/docs/deploy-with-docker) for remote server setup. ## Command reference [#command-reference] Run `fluxmail --help` or add `--help` to a command for terminal help: ```bash fluxmail accounts add --help fluxmail emails send --help ``` The [CLI reference](/docs/cli) lists every command and option. ## Update Fluxmail [#update-fluxmail] Fluxmail checks npm for a newer stable release at most once every 24 hours when you run an interactive CLI command. The check runs in the background. If it finds a newer release, a later command prints an update notice to stderr. Registry and cache errors do not affect the command. Update a global installation: ```bash npm install -g fluxmail@latest ``` `npx -y fluxmail@latest` already downloads the current stable release. If you use an exact version with `npx`, change the version in the command when you are ready to update. For Docker, pull the current image and recreate the service: ```bash docker compose pull fluxmail docker compose up -d ``` Fluxmail does not show update notices for MCP stdio, redirected output, CI, npm scripts, or `npx` runs. Skip the check for one command with the global option: ```bash fluxmail --no-update-notifier status ``` Set `NO_UPDATE_NOTIFIER=1` in your shell or container environment to turn off update checks. This variable controls only CLI update checks and is not part of Fluxmail configuration. --- # Activate a license URL: https://fluxmail.ai/docs/rest-api/activate-administrative-license `POST /api/v1/admin/license/activate` Validate and activate a Fluxmail license key. Requires admin.license. ## Authentication [#authentication] Pass an administrator member session or an API key as a bearer token. An API key must include the administrative capability named in the endpoint description. Remote administrative requests require HTTPS. Requests from the local computer can use HTTP. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/admin/license/activate' \ -X POST \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" \ -H "Content-Type: application/json" \ --data '{ "licenseKey": "string" }' ``` ### Request body [#request-body] Content type: `application/json`
JSON schema ```json { "type": "object", "properties": { "licenseKey": { "type": "string", "maxLength": 200 } }, "required": [ "licenseKey" ], "additionalProperties": false } ```
## Responses [#responses] | Status | Description | Content type | | ------ | ------------------------------- | ------------------ | | `200` | Validated activation | `application/json` | | `202` | Saved for retry after an outage | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Administrative access denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `413` | Request body too large | `application/json` | | `415` | Unsupported media type | `application/json` | | `500` | Internal error | `application/json` | | `502` | License could not be verified | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "object", "additionalProperties": { "nullable": true } } }, "required": [ "data" ], "additionalProperties": false } ```
### 202 response [#202-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "object", "additionalProperties": { "nullable": true } } }, "required": [ "data" ], "additionalProperties": false } ```
--- # Cancel a scheduled send URL: https://fluxmail.ai/docs/rest-api/cancel-scheduled-send `DELETE /api/v1/accounts/{accountId}/scheduled-sends/{scheduleId}` Cancel a pending scheduled send and keep its provider draft. ## Authentication [#authentication] Pass a Fluxmail member session or API key as a bearer token. API keys apply their mailbox scope and permissions to the request. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/accounts/acct_123/scheduled-sends/schedule_123' \ -X DELETE \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ------------ | -------- | -------- | -------- | ------------------ | | `accountId` | path | Yes | `string` | Minimum length: 1. | | `scheduleId` | path | Yes | `string` | Minimum length: 1. | ## Responses [#responses] | Status | Description | Content type | | ------ | ------------------------- | ------------------ | | `200` | Scheduled send canceled | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission or plan denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `422` | Unsupported capability | `application/json` | | `429` | Provider rate limit | `application/json` | | `500` | Internal error | `application/json` | | `503` | Provider unavailable | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "object", "properties": { "scheduleId": { "type": "string" }, "draftId": { "type": "string" }, "draftKept": { "type": "boolean", "enum": [ true ] } }, "required": [ "scheduleId", "draftId", "draftKept" ], "additionalProperties": false }, "warnings": { "type": "array", "items": { "type": "string" } } }, "required": [ "data" ], "additionalProperties": false } ```
--- # Change the current member password URL: https://fluxmail.ai/docs/rest-api/change-password `PUT /api/v1/me/password` Reference for PUT /api/v1/me/password. ## Authentication [#authentication] Pass a Fluxmail member session as a bearer token. API keys cannot use this endpoint. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/me/password' \ -X PUT \ -H "Authorization: Bearer $FLUXMAIL_SESSION" \ -H "Content-Type: application/json" \ --data '{ "currentPassword": "string", "newPassword": "string" }' ``` ### Request body [#request-body] Content type: `application/json`
JSON schema ```json { "type": "object", "properties": { "currentPassword": { "type": "string" }, "newPassword": { "type": "string" } }, "required": [ "currentPassword", "newPassword" ], "additionalProperties": false } ```
## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------- | ------------------ | | `200` | Success | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission denied | `application/json` | | `404` | Not found | `application/json` | | `409` | Conflict | `application/json` | | `413` | Request body too large | `application/json` | | `429` | Too many attempts | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "nullable": true } } } ```
--- # Connect or reauthorize a mailbox account URL: https://fluxmail.ai/docs/rest-api/connect-own-account `POST /api/v1/accounts/connections` Reference for POST /api/v1/accounts/connections. ## Authentication [#authentication] Pass a Fluxmail member session as a bearer token. API keys cannot use this endpoint. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/accounts/connections' \ -X POST \ -H "Authorization: Bearer $FLUXMAIL_SESSION" \ -H "Content-Type: application/json" \ --data '{ "provider": "gmail" }' ``` ### Request body [#request-body] Content type: `application/json`
JSON schema ```json { "type": "object", "properties": { "provider": { "type": "string", "enum": [ "gmail", "outlook", "imap" ] }, "reauthorizeAccountId": { "type": "string" }, "email": { "type": "string", "format": "email" }, "displayName": { "type": "string" }, "imap": { "type": "object", "properties": { "host": { "type": "string", "minLength": 1, "maxLength": 255 }, "port": { "type": "integer", "minimum": 1, "maximum": 65535 }, "security": { "type": "string", "enum": [ "tls", "starttls" ] }, "user": { "type": "string", "minLength": 1, "maxLength": 320 }, "password": { "type": "string", "minLength": 1, "maxLength": 4096 } }, "required": [ "host", "port", "security", "user", "password" ], "additionalProperties": false }, "smtp": { "type": "object", "properties": { "host": { "type": "string", "minLength": 1, "maxLength": 255 }, "port": { "type": "integer", "minimum": 1, "maximum": 65535 }, "security": { "type": "string", "enum": [ "tls", "starttls" ] }, "user": { "type": "string", "minLength": 1, "maxLength": 320 }, "password": { "type": "string", "minLength": 1, "maxLength": 4096 } }, "required": [ "host", "port", "security", "user", "password" ], "additionalProperties": false }, "saveSent": { "type": "boolean" }, "folderOverrides": { "type": "object", "properties": { "sent": { "type": "string", "minLength": 1, "maxLength": 1024 }, "drafts": { "type": "string", "minLength": 1, "maxLength": 1024 }, "trash": { "type": "string", "minLength": 1, "maxLength": 1024 }, "archive": { "type": "string", "minLength": 1, "maxLength": 1024 }, "spam": { "type": "string", "minLength": 1, "maxLength": 1024 } }, "additionalProperties": false } }, "required": [ "provider" ], "additionalProperties": false } ```
## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------- | ------------------ | | `200` | Success | `application/json` | | `201` | Success | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission denied | `application/json` | | `404` | Not found | `application/json` | | `409` | Conflict | `application/json` | | `413` | Request body too large | `application/json` | | `422` | Unsupported capability | `application/json` | | `429` | Too many attempts | `application/json` | | `503` | Provider unavailable | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "nullable": true } } } ```
### 201 response [#201-response]
JSON schema ```json { "type": "object", "properties": { "data": { "nullable": true } } } ```
--- # Create an API key URL: https://fluxmail.ai/docs/rest-api/create-administrative-api-key `POST /api/v1/admin/api-keys` Create an API key and return its plaintext secret once. Requires admin.api\_keys. ## Authentication [#authentication] Pass an administrator member session or an API key as a bearer token. An API key must include the administrative capability named in the endpoint description. Remote administrative requests require HTTPS. Requests from the local computer can use HTTP. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/admin/api-keys' \ -X POST \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" \ -H "Content-Type: application/json" \ --data '{ "name": "reporting", "member": "you@example.com", "permissionProfile": "read-only" }' ``` ### Request body [#request-body] Content type: `application/json`
JSON schema ```json { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 200 }, "member": { "type": "string", "minLength": 1, "maxLength": 200 }, "accounts": { "type": "array", "nullable": true, "items": { "type": "string", "minLength": 1, "maxLength": 200 }, "maxItems": 100 }, "permissionProfile": { "type": "string", "enum": [ "read-only", "read-write", "full" ] }, "supplementalCapabilities": { "type": "array", "items": { "type": "string", "enum": [ "admin.accounts", "admin.members", "admin.api_keys", "admin.license", "admin.audit" ] }, "maxItems": 5 }, "customCapabilities": { "type": "array", "items": { "type": "string", "enum": [ "mail.read", "mail.drafts", "mail.organize", "mail.trash", "mail.delete", "mail.send", "admin.accounts", "admin.members", "admin.api_keys", "admin.license", "admin.audit" ] }, "minItems": 1, "maxItems": 11 } }, "required": [ "name", "member" ], "additionalProperties": false, "example": { "name": "reporting", "member": "you@example.com", "permissionProfile": "read-only" } } ```
## Responses [#responses] | Status | Description | Content type | | ------ | ---------------------------------------------- | ------------------ | | `201` | Created API key with one-time plaintext secret | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Administrative access denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `413` | Request body too large | `application/json` | | `415` | Unsupported media type | `application/json` | | `500` | Internal error | `application/json` | | `502` | License could not be verified | `application/json` | ### 201 response [#201-response]
JSON schema ```json { "type": "object", "properties": { "data": { "allOf": [ { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "createdAt": { "type": "string" }, "lastUsedAt": { "type": "string", "nullable": true }, "memberId": { "type": "string" }, "permissionProfile": { "type": "string", "enum": [ "read-only", "read-write", "full", "custom" ] }, "capabilities": { "type": "array", "items": { "type": "string", "enum": [ "mail.read", "mail.drafts", "mail.organize", "mail.trash", "mail.delete", "mail.send", "admin.accounts", "admin.members", "admin.api_keys", "admin.license", "admin.audit" ] } }, "supplementalCapabilities": { "type": "array", "items": { "type": "string", "enum": [ "admin.accounts", "admin.members", "admin.api_keys", "admin.license", "admin.audit" ] } }, "accountIds": { "type": "array", "nullable": true, "items": { "type": "string" } } }, "required": [ "id", "name", "createdAt", "lastUsedAt", "memberId", "permissionProfile", "capabilities", "supplementalCapabilities", "accountIds" ], "additionalProperties": false }, { "type": "object", "properties": { "key": { "type": "string" } }, "required": [ "key" ], "additionalProperties": false } ] } }, "required": [ "data" ], "additionalProperties": false } ```
--- # Create or reauthorize a connection URL: https://fluxmail.ai/docs/rest-api/create-administrative-connection `POST /api/v1/admin/connections` Create or reauthorize a Gmail, Outlook, or IMAP connection. Requires admin.accounts. ## Authentication [#authentication] Pass an administrator member session or an API key as a bearer token. An API key must include the administrative capability named in the endpoint description. Remote administrative requests require HTTPS. Requests from the local computer can use HTTP. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/admin/connections' \ -X POST \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" \ -H "Content-Type: application/json" \ --data '{ "provider": "gmail", "ownerMemberId": "you@example.com" }' ``` ### Request body [#request-body] Content type: `application/json`
JSON schema ```json { "oneOf": [ { "type": "object", "properties": { "provider": { "type": "string", "enum": [ "gmail" ] }, "ownerMemberId": { "type": "string", "minLength": 1, "maxLength": 200 }, "reauthorizeAccountId": { "type": "string", "minLength": 1, "maxLength": 200 }, "sharedWithAll": { "type": "boolean" }, "grantedMemberIds": { "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 200 }, "maxItems": 100 } }, "required": [ "provider" ], "additionalProperties": false }, { "type": "object", "properties": { "provider": { "type": "string", "enum": [ "outlook" ] }, "ownerMemberId": { "type": "string", "minLength": 1, "maxLength": 200 }, "reauthorizeAccountId": { "type": "string", "minLength": 1, "maxLength": 200 }, "sharedWithAll": { "type": "boolean" }, "grantedMemberIds": { "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 200 }, "maxItems": 100 } }, "required": [ "provider" ], "additionalProperties": false }, { "type": "object", "properties": { "provider": { "type": "string", "enum": [ "imap" ] }, "ownerMemberId": { "type": "string", "minLength": 1, "maxLength": 200 }, "reauthorizeAccountId": { "type": "string", "minLength": 1, "maxLength": 200 }, "sharedWithAll": { "type": "boolean" }, "grantedMemberIds": { "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 200 }, "maxItems": 100 }, "email": { "type": "string", "maxLength": 320, "format": "email" }, "displayName": { "type": "string", "minLength": 1, "maxLength": 200 }, "imap": { "type": "object", "properties": { "host": { "type": "string", "minLength": 1, "maxLength": 255 }, "port": { "type": "integer", "minimum": 1, "maximum": 65535 }, "security": { "type": "string", "enum": [ "tls", "starttls" ] }, "user": { "type": "string", "minLength": 1, "maxLength": 320 }, "password": { "type": "string", "minLength": 1, "maxLength": 4096 } }, "required": [ "host", "port", "security", "user", "password" ], "additionalProperties": false }, "smtp": { "type": "object", "properties": { "host": { "type": "string", "minLength": 1, "maxLength": 255 }, "port": { "type": "integer", "minimum": 1, "maximum": 65535 }, "security": { "type": "string", "enum": [ "tls", "starttls" ] }, "user": { "type": "string", "minLength": 1, "maxLength": 320 }, "password": { "type": "string", "minLength": 1, "maxLength": 4096 } }, "required": [ "host", "port", "security", "user", "password" ], "additionalProperties": false }, "saveSent": { "type": "boolean" }, "folderOverrides": { "type": "object", "properties": { "sent": { "type": "string", "minLength": 1, "maxLength": 1024 }, "drafts": { "type": "string", "minLength": 1, "maxLength": 1024 }, "trash": { "type": "string", "minLength": 1, "maxLength": 1024 }, "archive": { "type": "string", "minLength": 1, "maxLength": 1024 }, "spam": { "type": "string", "minLength": 1, "maxLength": 1024 } }, "additionalProperties": false } }, "required": [ "provider", "email", "imap", "smtp" ], "additionalProperties": false } ], "example": { "provider": "gmail", "ownerMemberId": "you@example.com" } } ```
## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------------- | ------------------ | | `201` | Connection prepared or saved | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Administrative access denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `413` | Request body too large | `application/json` | | `415` | Unsupported media type | `application/json` | | `500` | Internal error | `application/json` | | `502` | License could not be verified | `application/json` | ### 201 response [#201-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "object", "additionalProperties": { "nullable": true } } }, "required": [ "data" ], "additionalProperties": false } ```
--- # Create a draft URL: https://fluxmail.ai/docs/rest-api/create-draft `POST /api/v1/accounts/{accountId}/drafts` Create a new draft or a reply draft in an email account. ## Authentication [#authentication] Pass a Fluxmail member session or API key as a bearer token. API keys apply their mailbox scope and permissions to the request. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/accounts/acct_123/drafts' \ -X POST \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" \ -H "Content-Type: application/json" \ --data '{ "body": {} }' ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ----------- | -------- | -------- | -------- | ------------------ | | `accountId` | path | Yes | `string` | Minimum length: 1. | ### Request body [#request-body] Content type: `application/json`
JSON schema ```json { "type": "object", "properties": { "from": { "type": "string", "format": "email" }, "to": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "cc": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "bcc": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "subject": { "type": "string" }, "body": { "type": "object", "properties": { "text": { "type": "string", "description": "Plain-text body. Line breaks appear in the sent email. Keep each prose paragraph on one continuous line and separate paragraphs with blank lines." }, "html": { "type": "string" } }, "additionalProperties": false }, "replyToMessageId": { "type": "string", "minLength": 1, "example": "msg_123" }, "replyAll": { "type": "boolean", "description": "Requires replyToMessageId when true." }, "attachments": { "type": "array", "items": { "type": "object", "properties": { "filename": { "type": "string", "minLength": 1 }, "mimeType": { "type": "string", "minLength": 1 }, "content": { "type": "string", "format": "byte", "pattern": "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$", "description": "Base64-encoded content" }, "contentId": { "type": "string", "minLength": 1 }, "disposition": { "type": "string", "enum": [ "inline", "attachment" ] } }, "required": [ "filename", "mimeType", "content" ], "additionalProperties": false } } }, "required": [ "body" ], "additionalProperties": false } ```
## Responses [#responses] | Status | Description | Content type | | ------ | ------------------------- | ------------------ | | `201` | Draft created | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission or plan denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `422` | Unsupported capability | `application/json` | | `429` | Provider rate limit | `application/json` | | `500` | Internal error | `application/json` | | `503` | Provider unavailable | `application/json` | ### 201 response [#201-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "object", "properties": { "id": { "type": "string" }, "threadId": { "type": "string" }, "accountId": { "type": "string" }, "draftId": { "type": "string" }, "folder": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "role": { "type": "string", "enum": [ "inbox", "sent", "drafts", "trash", "spam", "archive", "starred", "all" ] }, "roleSource": { "type": "string", "enum": [ "user", "extension", "name" ] }, "unreadCount": { "type": "integer", "minimum": 0 } }, "required": [ "id", "name" ], "additionalProperties": false }, "labels": { "type": "array", "items": { "type": "string" } }, "from": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false }, "to": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "cc": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "bcc": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "replyTo": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "subject": { "type": "string" }, "date": { "type": "string" }, "snippet": { "type": "string" }, "searchContext": { "anyOf": [ { "type": "object", "properties": { "status": { "type": "string", "enum": [ "matched" ] }, "excerpt": { "type": "string" } }, "required": [ "status", "excerpt" ], "additionalProperties": false }, { "type": "object", "properties": { "status": { "type": "string", "enum": [ "no_literal_match", "scan_limit", "unavailable" ] } }, "required": [ "status" ], "additionalProperties": false } ], "description": "Optional body excerpt status for a requested portable text search." }, "body": { "type": "object", "properties": { "text": { "type": "string" }, "html": { "type": "string" } }, "additionalProperties": false }, "attachments": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "filename": { "type": "string" }, "mimeType": { "type": "string" }, "sizeBytes": { "type": "integer", "minimum": 0 }, "contentId": { "type": "string" }, "disposition": { "type": "string", "enum": [ "inline", "attachment" ] } }, "required": [ "id", "filename", "mimeType", "sizeBytes" ], "additionalProperties": false } }, "flags": { "type": "object", "properties": { "read": { "type": "boolean" }, "starred": { "type": "boolean" }, "draft": { "type": "boolean" } }, "required": [ "read", "starred", "draft" ], "additionalProperties": false }, "headers": { "type": "object", "additionalProperties": { "type": "string" } } }, "required": [ "id", "threadId", "accountId", "to", "subject", "date", "flags" ], "additionalProperties": false }, "warnings": { "type": "array", "items": { "type": "string" } } }, "required": [ "data" ], "additionalProperties": false } ```
--- # Issue a member password reset URL: https://fluxmail.ai/docs/rest-api/create-member-password-reset `POST /api/v1/admin/members/{memberId}/password-reset` Reference for POST /api/v1/admin/members/\{memberId}/password-reset. ## Authentication [#authentication] Pass an administrator member session or an API key as a bearer token. An API key must include the administrative capability named in the endpoint description. Remote administrative requests require HTTPS. Requests from the local computer can use HTTP. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/admin/members/memberId_123/password-reset' \ -X POST \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ---------- | -------- | -------- | -------- | ------------------ | | `memberId` | path | Yes | `string` | Minimum length: 1. | ## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------- | ------------------ | | `200` | Success | `application/json` | | `201` | Success | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission denied | `application/json` | | `404` | Not found | `application/json` | | `409` | Conflict | `application/json` | | `413` | Request body too large | `application/json` | | `429` | Too many attempts | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "nullable": true } } } ```
### 201 response [#201-response]
JSON schema ```json { "type": "object", "properties": { "data": { "nullable": true } } } ```
--- # Create and invite a member URL: https://fluxmail.ai/docs/rest-api/create-member `POST /api/v1/admin/members` Reference for POST /api/v1/admin/members. ## Authentication [#authentication] Pass an administrator member session or an API key as a bearer token. An API key must include the administrative capability named in the endpoint description. Remote administrative requests require HTTPS. Requests from the local computer can use HTTP. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/admin/members' \ -X POST \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" \ -H "Content-Type: application/json" \ --data '{ "name": "string", "email": "person@example.com", "role": "admin" }' ``` ### Request body [#request-body] Content type: `application/json`
JSON schema ```json { "type": "object", "properties": { "name": { "type": "string", "minLength": 1 }, "email": { "type": "string", "format": "email" }, "role": { "type": "string", "enum": [ "admin", "member" ] } }, "required": [ "name", "email", "role" ], "additionalProperties": false } ```
## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------- | ------------------ | | `200` | Success | `application/json` | | `201` | Success | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission denied | `application/json` | | `404` | Not found | `application/json` | | `409` | Conflict | `application/json` | | `413` | Request body too large | `application/json` | | `429` | Too many attempts | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "nullable": true } } } ```
### 201 response [#201-response]
JSON schema ```json { "type": "object", "properties": { "data": { "nullable": true } } } ```
--- # Create an API key for the current member URL: https://fluxmail.ai/docs/rest-api/create-own-api-key `POST /api/v1/me/api-keys` Reference for POST /api/v1/me/api-keys. ## Authentication [#authentication] Pass a Fluxmail member session as a bearer token. API keys cannot use this endpoint. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/me/api-keys' \ -X POST \ -H "Authorization: Bearer $FLUXMAIL_SESSION" \ -H "Content-Type: application/json" \ --data '{ "name": "string" }' ``` ### Request body [#request-body] Content type: `application/json`
JSON schema ```json { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 200 }, "permissionProfile": { "type": "string", "enum": [ "read-only", "read-write", "full" ] }, "capabilities": { "type": "array", "items": { "type": "string", "enum": [ "mail.read", "mail.drafts", "mail.organize", "mail.trash", "mail.delete", "mail.send", "admin.accounts", "admin.members", "admin.api_keys", "admin.license", "admin.audit" ] }, "minItems": 1, "maxItems": 11 }, "supplementalCapabilities": { "type": "array", "items": { "type": "string", "enum": [ "admin.accounts", "admin.members", "admin.api_keys", "admin.license", "admin.audit" ] }, "maxItems": 5 }, "accountIds": { "type": "array", "nullable": true, "items": { "type": "string" } } }, "required": [ "name" ], "additionalProperties": false } ```
## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------- | ------------------ | | `200` | Success | `application/json` | | `201` | Success | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission denied | `application/json` | | `404` | Not found | `application/json` | | `409` | Conflict | `application/json` | | `413` | Request body too large | `application/json` | | `429` | Too many attempts | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "nullable": true } } } ```
### 201 response [#201-response]
JSON schema ```json { "type": "object", "properties": { "data": { "nullable": true } } } ```
--- # Deactivate a license URL: https://fluxmail.ai/docs/rest-api/deactivate-administrative-license `DELETE /api/v1/admin/license` Release the stored license and return this instance to Personal limits. Requires admin.license. ## Authentication [#authentication] Pass an administrator member session or an API key as a bearer token. An API key must include the administrative capability named in the endpoint description. Remote administrative requests require HTTPS. Requests from the local computer can use HTTP. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/admin/license' \ -X DELETE \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` This endpoint has no parameters or request body. ## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------------- | ------------------ | | `200` | License deactivated | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Administrative access denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `413` | Request body too large | `application/json` | | `415` | Unsupported media type | `application/json` | | `500` | Internal error | `application/json` | | `502` | License could not be verified | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "object", "additionalProperties": { "nullable": true } } }, "required": [ "data" ], "additionalProperties": false } ```
--- # Remove a mailbox account URL: https://fluxmail.ai/docs/rest-api/delete-admin-account `DELETE /api/v1/admin/accounts/{accountId}` Reference for DELETE /api/v1/admin/accounts/\{accountId}. ## Authentication [#authentication] Pass an administrator member session or an API key as a bearer token. An API key must include the administrative capability named in the endpoint description. Remote administrative requests require HTTPS. Requests from the local computer can use HTTP. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/admin/accounts/acct_123' \ -X DELETE \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ----------- | -------- | -------- | -------- | ------------------ | | `accountId` | path | Yes | `string` | Minimum length: 1. | ## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------- | ------------------ | | `200` | Success | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission denied | `application/json` | | `404` | Not found | `application/json` | | `409` | Conflict | `application/json` | | `413` | Request body too large | `application/json` | | `429` | Too many attempts | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "nullable": true } } } ```
--- # Reset an OAuth application URL: https://fluxmail.ai/docs/rest-api/delete-administrative-oauth-app `DELETE /api/v1/admin/oauth-apps/{provider}` Remove a stored OAuth application. Requires admin.accounts. ## Authentication [#authentication] Pass an administrator member session or an API key as a bearer token. An API key must include the administrative capability named in the endpoint description. Remote administrative requests require HTTPS. Requests from the local computer can use HTTP. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/admin/oauth-apps/google' \ -X DELETE \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ---------- | -------- | -------- | --------------------- | ------- | | `provider` | path | Yes | `google` or `outlook` | None | ## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------------- | ------------------ | | `200` | OAuth applications | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Administrative access denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `413` | Request body too large | `application/json` | | `415` | Unsupported media type | `application/json` | | `500` | Internal error | `application/json` | | `502` | License could not be verified | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "object", "properties": { "google": { "type": "object", "properties": { "clientId": { "type": "string" }, "clientSecretConfigured": { "type": "boolean" }, "source": { "type": "string", "enum": [ "built-in", "stored", "environment", "environment-file" ] }, "mutable": { "type": "boolean" } }, "required": [ "clientId", "clientSecretConfigured", "source", "mutable" ] }, "outlook": { "type": "object", "properties": { "clientId": { "type": "string", "nullable": true }, "tenantId": { "type": "string", "nullable": true }, "clientSecretConfigured": { "type": "boolean" }, "source": { "type": "string", "nullable": true, "enum": [ "stored", "environment", "environment-file" ] }, "mutable": { "type": "boolean" } }, "required": [ "clientId", "tenantId", "clientSecretConfigured", "source", "mutable" ] } }, "required": [ "google", "outlook" ] } }, "required": [ "data" ], "additionalProperties": false } ```
--- # Delete a draft URL: https://fluxmail.ai/docs/rest-api/delete-draft `DELETE /api/v1/accounts/{accountId}/drafts/{draftId}` Delete an existing draft from an email account. ## Authentication [#authentication] Pass a Fluxmail member session or API key as a bearer token. API keys apply their mailbox scope and permissions to the request. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/accounts/acct_123/drafts/draft_123' \ -X DELETE \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ----------- | -------- | -------- | -------- | ------------------ | | `accountId` | path | Yes | `string` | Minimum length: 1. | | `draftId` | path | Yes | `string` | Minimum length: 1. | ## Responses [#responses] | Status | Description | Content type | | ------ | ------------------------- | ------------------ | | `200` | Draft deleted | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission or plan denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `422` | Unsupported capability | `application/json` | | `429` | Provider rate limit | `application/json` | | `500` | Internal error | `application/json` | | `503` | Provider unavailable | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "object", "properties": { "deleted": { "type": "string" } }, "required": [ "deleted" ], "additionalProperties": false }, "warnings": { "type": "array", "items": { "type": "string" } } }, "required": [ "data" ], "additionalProperties": false } ```
--- # Remove a member URL: https://fluxmail.ai/docs/rest-api/delete-member `DELETE /api/v1/admin/members/{memberId}` Reference for DELETE /api/v1/admin/members/\{memberId}. ## Authentication [#authentication] Pass an administrator member session or an API key as a bearer token. An API key must include the administrative capability named in the endpoint description. Remote administrative requests require HTTPS. Requests from the local computer can use HTTP. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/admin/members/memberId_123' \ -X DELETE \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ---------- | -------- | -------- | -------- | ------------------ | | `memberId` | path | Yes | `string` | Minimum length: 1. | ## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------- | ------------------ | | `200` | Success | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission denied | `application/json` | | `404` | Not found | `application/json` | | `409` | Conflict | `application/json` | | `413` | Request body too large | `application/json` | | `429` | Too many attempts | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "nullable": true } } } ```
--- # Download an attachment URL: https://fluxmail.ai/docs/rest-api/download-attachment `GET /api/v1/accounts/{accountId}/messages/{messageId}/attachments/{attachmentId}` Download one attachment as raw bytes. ## Authentication [#authentication] Pass a Fluxmail member session or API key as a bearer token. API keys apply their mailbox scope and permissions to the request. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/accounts/acct_123/messages/msg_123/attachments/part%3A1.2' \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | -------------- | -------- | -------- | -------- | -------------------------------------------------------------------- | | `accountId` | path | Yes | `string` | Minimum length: 1. | | `messageId` | path | Yes | `string` | Minimum length: 1. | | `attachmentId` | path | Yes | `string` | Opaque attachment ID returned by message metadata Minimum length: 1. | ## Responses [#responses] | Status | Description | Content type | | ------ | ------------------------- | -------------------------- | | `200` | Attachment bytes | `application/octet-stream` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission or plan denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `422` | Unsupported capability | `application/json` | | `429` | Provider rate limit | `application/json` | | `500` | Internal error | `application/json` | | `503` | Provider unavailable | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "string", "format": "binary" } ```
--- # Enroll a member URL: https://fluxmail.ai/docs/rest-api/enroll-member `POST /api/v1/auth/enroll` Reference for POST /api/v1/auth/enroll. ## Authentication [#authentication] This endpoint does not require authentication. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/auth/enroll' \ -X POST \ -H "Content-Type: application/json" \ --data '{ "token": "string", "password": "string", "deviceName": "string" }' ``` ### Request body [#request-body] Content type: `application/json`
JSON schema ```json { "type": "object", "properties": { "token": { "type": "string", "minLength": 1 }, "password": { "type": "string" }, "deviceName": { "type": "string", "minLength": 1, "maxLength": 200 } }, "required": [ "token", "password", "deviceName" ], "additionalProperties": false } ```
## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------- | ------------------ | | `200` | Success | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission denied | `application/json` | | `404` | Not found | `application/json` | | `409` | Conflict | `application/json` | | `413` | Request body too large | `application/json` | | `429` | Too many attempts | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "nullable": true } } } ```
--- # Forward a message URL: https://fluxmail.ai/docs/rest-api/forward-message `POST /api/v1/accounts/{accountId}/messages/{messageId}/forward` Forward a message to one or more recipients. ## Authentication [#authentication] Pass a Fluxmail member session or API key as a bearer token. API keys apply their mailbox scope and permissions to the request. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/accounts/acct_123/messages/msg_123/forward' \ -X POST \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ --data '{ "to": [ { "email": "person@example.com" } ] }' ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ----------------- | -------- | -------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | | `accountId` | path | Yes | `string` | Minimum length: 1. | | `messageId` | path | Yes | `string` | Minimum length: 1. | | `Idempotency-Key` | header | Yes | `string` | A unique key for one intended delivery. Reuse it when retrying the same request. Minimum length: 1. Maximum length: 255. Pattern: `^[\x21-\x7e]+$`. | ### Request body [#request-body] Content type: `application/json`
JSON schema ```json { "type": "object", "properties": { "from": { "type": "string", "format": "email" }, "to": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false }, "minItems": 1 }, "cc": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "comment": { "type": "string", "description": "Comment above the forwarded message. Keep prose paragraphs on one continuous line and separate paragraphs with blank lines." }, "includeAttachments": { "type": "boolean", "default": true, "description": "Include attachments from the original message. Defaults to true." } }, "required": [ "to" ], "additionalProperties": false } ```
## Safe retries [#safe-retries] Fluxmail scopes each delivery key to the authenticated credential. Delivery operations and their keys have no automatic expiry. * Repeating a request with the same key and request data returns the stored delivery operation. It does not send again. * Reusing the key with different request data returns `409 idempotency_conflict`. * An `uncertain` operation may have been delivered. Fluxmail does not retry it automatically. Save the key with the request and reuse it if the response is lost. Look up the operation status before taking further action. For an `uncertain` result, check the Sent folder or recipient before creating a new delivery request. REST keys created before the delivery-operation upgrade keep their original 24 hour lifetime. A retry with one of those keys may return the legacy response shape and `Idempotency-Replayed: true`. ## Responses [#responses] | Status | Description | Content type | | ------ | -------------------------- | ------------------ | | `200` | Forward delivery operation | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission or plan denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `422` | Unsupported capability | `application/json` | | `429` | Provider rate limit | `application/json` | | `500` | Internal error | `application/json` | | `503` | Provider unavailable | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "object", "properties": { "operationId": { "type": "string" }, "accountId": { "type": "string" }, "kind": { "type": "string", "enum": [ "send", "forward", "scheduled" ] }, "status": { "type": "string", "enum": [ "queued", "sending", "succeeded", "failed", "uncertain" ] }, "result": { "type": "object", "properties": { "id": { "type": "string" }, "threadId": { "type": "string" }, "warnings": { "type": "array", "items": { "type": "string" } } }, "required": [ "id", "threadId" ], "additionalProperties": false }, "error": { "type": "object", "properties": { "code": { "type": "string" } }, "required": [ "code" ], "additionalProperties": false }, "scheduleId": { "type": "string" } }, "required": [ "operationId", "accountId", "kind", "status" ], "additionalProperties": false }, "warnings": { "type": "array", "items": { "type": "string" } } }, "required": [ "data" ], "additionalProperties": false } ```
--- # Get license status URL: https://fluxmail.ai/docs/rest-api/get-administrative-license `GET /api/v1/admin/license` Get license status and usage without returning the configured license key. Requires admin.license. ## Authentication [#authentication] Pass an administrator member session or an API key as a bearer token. An API key must include the administrative capability named in the endpoint description. Remote administrative requests require HTTPS. Requests from the local computer can use HTTP. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/admin/license' \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` This endpoint has no parameters or request body. ## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------------------------- | ------------------ | | `200` | License status without the configured key | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Administrative access denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `413` | Request body too large | `application/json` | | `415` | Unsupported media type | `application/json` | | `500` | Internal error | `application/json` | | `502` | License could not be verified | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "object", "additionalProperties": { "nullable": true } } }, "required": [ "data" ], "additionalProperties": false } ```
--- # Get OAuth application status URL: https://fluxmail.ai/docs/rest-api/get-administrative-oauth-apps `GET /api/v1/admin/oauth-apps` Get safe OAuth application metadata without returning client secrets. Requires admin.accounts. ## Authentication [#authentication] Pass an administrator member session or an API key as a bearer token. An API key must include the administrative capability named in the endpoint description. Remote administrative requests require HTTPS. Requests from the local computer can use HTTP. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/admin/oauth-apps' \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` This endpoint has no parameters or request body. ## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------------- | ------------------ | | `200` | OAuth applications | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Administrative access denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `413` | Request body too large | `application/json` | | `415` | Unsupported media type | `application/json` | | `500` | Internal error | `application/json` | | `502` | License could not be verified | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "object", "properties": { "google": { "type": "object", "properties": { "clientId": { "type": "string" }, "clientSecretConfigured": { "type": "boolean" }, "source": { "type": "string", "enum": [ "built-in", "stored", "environment", "environment-file" ] }, "mutable": { "type": "boolean" } }, "required": [ "clientId", "clientSecretConfigured", "source", "mutable" ] }, "outlook": { "type": "object", "properties": { "clientId": { "type": "string", "nullable": true }, "tenantId": { "type": "string", "nullable": true }, "clientSecretConfigured": { "type": "boolean" }, "source": { "type": "string", "nullable": true, "enum": [ "stored", "environment", "environment-file" ] }, "mutable": { "type": "boolean" } }, "required": [ "clientId", "tenantId", "clientSecretConfigured", "source", "mutable" ] } }, "required": [ "google", "outlook" ] } }, "required": [ "data" ], "additionalProperties": false } ```
--- # Get API information URL: https://fluxmail.ai/docs/rest-api/get-api-info `GET /api/v1` Return the Fluxmail version and the URL of the OpenAPI document. ## Authentication [#authentication] This endpoint does not require authentication. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1' ``` This endpoint has no parameters or request body. ## Responses [#responses] | Status | Description | Content type | | ------ | ------------------ | ------------------ | | `200` | REST API discovery | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "object", "properties": { "name": { "type": "string", "enum": [ "fluxmail" ] }, "version": { "type": "string" }, "openapi": { "type": "string" } }, "required": [ "name", "version", "openapi" ], "additionalProperties": false }, "warnings": { "type": "array", "items": { "type": "string" } } }, "required": [ "data" ], "additionalProperties": false } ```
--- # Get the authenticated member URL: https://fluxmail.ai/docs/rest-api/get-current-member `GET /api/v1/me` Reference for GET /api/v1/me. ## Authentication [#authentication] Pass a Fluxmail member session or API key as a bearer token. API keys apply their mailbox scope and permissions to the request. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/me' \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` This endpoint has no parameters or request body. ## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------- | ------------------ | | `200` | Success | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission denied | `application/json` | | `404` | Not found | `application/json` | | `409` | Conflict | `application/json` | | `413` | Request body too large | `application/json` | | `429` | Too many attempts | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "nullable": true } } } ```
--- # Get a delivery outcome URL: https://fluxmail.ai/docs/rest-api/get-delivery-operation `GET /api/v1/accounts/{accountId}/delivery-operations/{operationId}` Reference for GET /api/v1/accounts/\{accountId}/delivery-operations/\{operationId}. ## Authentication [#authentication] Pass a Fluxmail member session or API key as a bearer token. API keys apply their mailbox scope and permissions to the request. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/accounts/acct_123/delivery-operations/operationId_123' \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ------------- | -------- | -------- | -------- | ------------------ | | `accountId` | path | Yes | `string` | Minimum length: 1. | | `operationId` | path | Yes | `string` | Minimum length: 1. | ## Responses [#responses] | Status | Description | Content type | | ------ | ------------------------- | ------------------ | | `200` | Delivery outcome | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission or plan denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `422` | Unsupported capability | `application/json` | | `429` | Provider rate limit | `application/json` | | `500` | Internal error | `application/json` | | `503` | Provider unavailable | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "object", "properties": { "operationId": { "type": "string" }, "accountId": { "type": "string" }, "kind": { "type": "string", "enum": [ "send", "forward", "scheduled" ] }, "status": { "type": "string", "enum": [ "queued", "sending", "succeeded", "failed", "uncertain" ] }, "result": { "type": "object", "properties": { "id": { "type": "string" }, "threadId": { "type": "string" }, "warnings": { "type": "array", "items": { "type": "string" } } }, "required": [ "id", "threadId" ], "additionalProperties": false }, "error": { "type": "object", "properties": { "code": { "type": "string" } }, "required": [ "code" ], "additionalProperties": false }, "scheduleId": { "type": "string" } }, "required": [ "operationId", "accountId", "kind", "status" ], "additionalProperties": false }, "warnings": { "type": "array", "items": { "type": "string" } } }, "required": [ "data" ], "additionalProperties": false } ```
--- # Get a draft URL: https://fluxmail.ai/docs/rest-api/get-draft `GET /api/v1/accounts/{accountId}/drafts/{draftId}` Reference for GET /api/v1/accounts/\{accountId}/drafts/\{draftId}. ## Authentication [#authentication] Pass a Fluxmail member session or API key as a bearer token. API keys apply their mailbox scope and permissions to the request. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/accounts/acct_123/drafts/draft_123' \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ----------- | -------- | -------- | -------- | ------------------ | | `accountId` | path | Yes | `string` | Minimum length: 1. | | `draftId` | path | Yes | `string` | Minimum length: 1. | ## Responses [#responses] | Status | Description | Content type | | ------ | ------------------------- | ------------------ | | `200` | Draft | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission or plan denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `422` | Unsupported capability | `application/json` | | `429` | Provider rate limit | `application/json` | | `500` | Internal error | `application/json` | | `503` | Provider unavailable | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "object", "properties": { "id": { "type": "string" }, "threadId": { "type": "string" }, "accountId": { "type": "string" }, "draftId": { "type": "string" }, "folder": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "role": { "type": "string", "enum": [ "inbox", "sent", "drafts", "trash", "spam", "archive", "starred", "all" ] }, "roleSource": { "type": "string", "enum": [ "user", "extension", "name" ] }, "unreadCount": { "type": "integer", "minimum": 0 } }, "required": [ "id", "name" ], "additionalProperties": false }, "labels": { "type": "array", "items": { "type": "string" } }, "from": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false }, "to": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "cc": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "bcc": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "replyTo": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "subject": { "type": "string" }, "date": { "type": "string" }, "snippet": { "type": "string" }, "searchContext": { "anyOf": [ { "type": "object", "properties": { "status": { "type": "string", "enum": [ "matched" ] }, "excerpt": { "type": "string" } }, "required": [ "status", "excerpt" ], "additionalProperties": false }, { "type": "object", "properties": { "status": { "type": "string", "enum": [ "no_literal_match", "scan_limit", "unavailable" ] } }, "required": [ "status" ], "additionalProperties": false } ], "description": "Optional body excerpt status for a requested portable text search." }, "body": { "type": "object", "properties": { "text": { "type": "string" }, "html": { "type": "string" } }, "additionalProperties": false }, "attachments": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "filename": { "type": "string" }, "mimeType": { "type": "string" }, "sizeBytes": { "type": "integer", "minimum": 0 }, "contentId": { "type": "string" }, "disposition": { "type": "string", "enum": [ "inline", "attachment" ] } }, "required": [ "id", "filename", "mimeType", "sizeBytes" ], "additionalProperties": false } }, "flags": { "type": "object", "properties": { "read": { "type": "boolean" }, "starred": { "type": "boolean" }, "draft": { "type": "boolean" } }, "required": [ "read", "starred", "draft" ], "additionalProperties": false }, "headers": { "type": "object", "additionalProperties": { "type": "string" } } }, "required": [ "id", "threadId", "accountId", "to", "subject", "date", "flags" ], "additionalProperties": false }, "warnings": { "type": "array", "items": { "type": "string" } } }, "required": [ "data" ], "additionalProperties": false } ```
--- # Get a message URL: https://fluxmail.ai/docs/rest-api/get-message `GET /api/v1/accounts/{accountId}/messages/{messageId}` Get one message by its provider ID. ## Authentication [#authentication] Pass a Fluxmail member session or API key as a bearer token. API keys apply their mailbox scope and permissions to the request. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/accounts/acct_123/messages/msg_123' \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ----------- | -------- | -------- | -------- | ------------------ | | `accountId` | path | Yes | `string` | Minimum length: 1. | | `messageId` | path | Yes | `string` | Minimum length: 1. | ## Responses [#responses] | Status | Description | Content type | | ------ | ------------------------- | ------------------ | | `200` | Message | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission or plan denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `422` | Unsupported capability | `application/json` | | `429` | Provider rate limit | `application/json` | | `500` | Internal error | `application/json` | | `503` | Provider unavailable | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "object", "properties": { "id": { "type": "string" }, "threadId": { "type": "string" }, "accountId": { "type": "string" }, "draftId": { "type": "string" }, "folder": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "role": { "type": "string", "enum": [ "inbox", "sent", "drafts", "trash", "spam", "archive", "starred", "all" ] }, "roleSource": { "type": "string", "enum": [ "user", "extension", "name" ] }, "unreadCount": { "type": "integer", "minimum": 0 } }, "required": [ "id", "name" ], "additionalProperties": false }, "labels": { "type": "array", "items": { "type": "string" } }, "from": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false }, "to": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "cc": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "bcc": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "replyTo": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "subject": { "type": "string" }, "date": { "type": "string" }, "snippet": { "type": "string" }, "searchContext": { "anyOf": [ { "type": "object", "properties": { "status": { "type": "string", "enum": [ "matched" ] }, "excerpt": { "type": "string" } }, "required": [ "status", "excerpt" ], "additionalProperties": false }, { "type": "object", "properties": { "status": { "type": "string", "enum": [ "no_literal_match", "scan_limit", "unavailable" ] } }, "required": [ "status" ], "additionalProperties": false } ], "description": "Optional body excerpt status for a requested portable text search." }, "body": { "type": "object", "properties": { "text": { "type": "string" }, "html": { "type": "string" } }, "additionalProperties": false }, "attachments": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "filename": { "type": "string" }, "mimeType": { "type": "string" }, "sizeBytes": { "type": "integer", "minimum": 0 }, "contentId": { "type": "string" }, "disposition": { "type": "string", "enum": [ "inline", "attachment" ] } }, "required": [ "id", "filename", "mimeType", "sizeBytes" ], "additionalProperties": false } }, "flags": { "type": "object", "properties": { "read": { "type": "boolean" }, "starred": { "type": "boolean" }, "draft": { "type": "boolean" } }, "required": [ "read", "starred", "draft" ], "additionalProperties": false }, "headers": { "type": "object", "additionalProperties": { "type": "string" } } }, "required": [ "id", "threadId", "accountId", "to", "subject", "date", "flags" ], "additionalProperties": false }, "warnings": { "type": "array", "items": { "type": "string" } } }, "required": [ "data" ], "additionalProperties": false } ```
--- # Get server status URL: https://fluxmail.ai/docs/rest-api/get-status `GET /api/v1/status` Return provider and mailbox status for the accounts available to the API key. ## Authentication [#authentication] Pass a Fluxmail member session or API key as a bearer token. API keys apply their mailbox scope and permissions to the request. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/status' \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` This endpoint has no parameters or request body. ## Responses [#responses] | Status | Description | Content type | | ------ | ------------------------- | ------------------ | | `200` | Status | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission or plan denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `422` | Unsupported capability | `application/json` | | `429` | Provider rate limit | `application/json` | | `500` | Internal error | `application/json` | | `503` | Provider unavailable | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "object", "additionalProperties": { "nullable": true } }, "warnings": { "type": "array", "items": { "type": "string" } } }, "required": [ "data" ], "additionalProperties": false } ```
--- # Get a thread URL: https://fluxmail.ai/docs/rest-api/get-thread `GET /api/v1/accounts/{accountId}/threads/{threadId}` Get a complete email thread by its provider ID. ## Authentication [#authentication] Pass a Fluxmail member session or API key as a bearer token. API keys apply their mailbox scope and permissions to the request. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/accounts/acct_123/threads/thread_123' \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ----------- | -------- | -------- | -------- | ------------------ | | `accountId` | path | Yes | `string` | Minimum length: 1. | | `threadId` | path | Yes | `string` | Minimum length: 1. | ## Responses [#responses] | Status | Description | Content type | | ------ | ------------------------- | ------------------ | | `200` | Thread | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission or plan denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `422` | Unsupported capability | `application/json` | | `429` | Provider rate limit | `application/json` | | `500` | Internal error | `application/json` | | `503` | Provider unavailable | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "object", "properties": { "id": { "type": "string" }, "subject": { "type": "string" }, "messages": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "threadId": { "type": "string" }, "accountId": { "type": "string" }, "draftId": { "type": "string" }, "folder": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "role": { "type": "string", "enum": [ "inbox", "sent", "drafts", "trash", "spam", "archive", "starred", "all" ] }, "roleSource": { "type": "string", "enum": [ "user", "extension", "name" ] }, "unreadCount": { "type": "integer", "minimum": 0 } }, "required": [ "id", "name" ], "additionalProperties": false }, "labels": { "type": "array", "items": { "type": "string" } }, "from": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false }, "to": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "cc": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "bcc": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "replyTo": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "subject": { "type": "string" }, "date": { "type": "string" }, "snippet": { "type": "string" }, "searchContext": { "anyOf": [ { "type": "object", "properties": { "status": { "type": "string", "enum": [ "matched" ] }, "excerpt": { "type": "string" } }, "required": [ "status", "excerpt" ], "additionalProperties": false }, { "type": "object", "properties": { "status": { "type": "string", "enum": [ "no_literal_match", "scan_limit", "unavailable" ] } }, "required": [ "status" ], "additionalProperties": false } ], "description": "Optional body excerpt status for a requested portable text search." }, "body": { "type": "object", "properties": { "text": { "type": "string" }, "html": { "type": "string" } }, "additionalProperties": false }, "attachments": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "filename": { "type": "string" }, "mimeType": { "type": "string" }, "sizeBytes": { "type": "integer", "minimum": 0 }, "contentId": { "type": "string" }, "disposition": { "type": "string", "enum": [ "inline", "attachment" ] } }, "required": [ "id", "filename", "mimeType", "sizeBytes" ], "additionalProperties": false } }, "flags": { "type": "object", "properties": { "read": { "type": "boolean" }, "starred": { "type": "boolean" }, "draft": { "type": "boolean" } }, "required": [ "read", "starred", "draft" ], "additionalProperties": false }, "headers": { "type": "object", "additionalProperties": { "type": "string" } } }, "required": [ "id", "threadId", "accountId", "to", "subject", "date", "flags" ], "additionalProperties": false } } }, "required": [ "id", "subject", "messages" ], "additionalProperties": false }, "warnings": { "type": "array", "items": { "type": "string" } } }, "required": [ "data" ], "additionalProperties": false } ```
--- # REST API URL: https://fluxmail.ai/docs/rest-api Fluxmail exposes a REST API at `/api/v1` alongside its MCP endpoint. It uses the same connected mailboxes, permissions, and plan limits as MCP. ## Start locally [#start-locally] Complete the [quickstart](/docs/quickstart), then create an API key and start the HTTP server: ```bash fluxmail apikey create \ --name local-script fluxmail serve ``` Copy the `fmk_...` key when Fluxmail displays it. The local base URL is `http://localhost:8977/api/v1`. Pass the key as a bearer token. For example, list the accounts available to the key: ```bash export FLUXMAIL_API_KEY='fmk_...' curl http://localhost:8977/api/v1/accounts \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` Use the returned account ID in mailbox routes. If you expose the HTTP server outside your computer, protect it with HTTPS and a firewall or reverse proxy. ## Administrative access [#administrative-access] Routes under `/api/v1/admin` accept a member session or API key. A session must belong to a current administrator. An API key must belong to a current administrator and include the capability for the requested operation: | Capability | Access | | ---------------- | ------------------------------------------------------------------------------------------------------- | | `admin.accounts` | Connect or reauthorize mailboxes, update IMAP settings, and configure Outlook or IMAP sender addresses. | | `admin.api_keys` | List, create, update, and revoke API keys. | | `admin.members` | Manage members, invitations, roles, statuses, and sessions. | | `admin.audit` | Read security audit events. | | `admin.license` | Read license status and activate a license key. | The first member is the initial administrator. Administrators can use their CLI session directly. Create an administrative API key only when automation needs these routes: ```bash fluxmail apikey create \ --name instance-admin \ --profile full \ --admin admin.accounts \ --admin admin.api_keys \ --admin admin.members \ --admin admin.audit \ --admin admin.license ``` Remote administrative requests require HTTPS. Requests from the local computer can use HTTP. If a reverse proxy terminates TLS and connects to Fluxmail from a non-loopback address, set `FLUXMAIL_TRUST_PROXY=1`. Enable it only when the proxy overwrites forwarded headers and prevents clients from reaching Fluxmail directly. ## Endpoint reference [#endpoint-reference] | Endpoint | Description | | -------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | | [Log in with a member email and password](/docs/rest-api/login) | Log in with a member email and password | | [Enroll a member](/docs/rest-api/enroll-member) | Enroll a member | | [Redeem a password reset](/docs/rest-api/reset-password) | Redeem a password reset | | [Get the authenticated member](/docs/rest-api/get-current-member) | Get the authenticated member | | [Update the current member profile](/docs/rest-api/update-current-member) | Update the current member profile | | [Revoke the current member session](/docs/rest-api/logout) | Revoke the current member session | | [Change the current member password](/docs/rest-api/change-password) | Change the current member password | | [List current member sessions](/docs/rest-api/list-sessions) | List current member sessions | | [Revoke a member session](/docs/rest-api/revoke-session) | Revoke a member session | | [List API keys owned by the current member](/docs/rest-api/list-own-api-keys) | List API keys owned by the current member | | [Create an API key for the current member](/docs/rest-api/create-own-api-key) | Create an API key for the current member | | [Revoke an API key owned by the current member](/docs/rest-api/revoke-own-api-key) | Revoke an API key owned by the current member | | [Connect or reauthorize a mailbox account](/docs/rest-api/connect-own-account) | Connect or reauthorize a mailbox account | | [Remove a mailbox account owned by the current member](/docs/rest-api/remove-own-account) | Remove a mailbox account owned by the current member | | [Update folder settings for an owned IMAP mailbox](/docs/rest-api/update-owned-imap-folders) | Update folder settings for an owned IMAP mailbox | | [List members](/docs/rest-api/list-members) | List members | | [Create and invite a member](/docs/rest-api/create-member) | Create and invite a member | | [Update a member](/docs/rest-api/update-member) | Update a member | | [Remove a member](/docs/rest-api/delete-member) | Remove a member | | [Issue a member invitation](/docs/rest-api/invite-member) | Issue a member invitation | | [Issue a member password reset](/docs/rest-api/create-member-password-reset) | Issue a member password reset | | [List a member's sessions](/docs/rest-api/list-member-sessions) | List a member's sessions | | [Revoke a member's session](/docs/rest-api/revoke-member-session) | Revoke a member's session | | [List all mailbox account metadata](/docs/rest-api/list-admin-accounts) | List all mailbox account metadata | | [Update mailbox ownership and access](/docs/rest-api/update-account-access) | Update mailbox ownership and access | | [Remove a mailbox account](/docs/rest-api/delete-admin-account) | Remove a mailbox account | | [List security audit events](/docs/rest-api/list-audit-events) | List security audit events | | [Create or reauthorize a connection](/docs/rest-api/create-administrative-connection) | Create or reauthorize a Gmail, Outlook, or IMAP connection. Requires admin.accounts. | | [Test an IMAP connection](/docs/rest-api/test-administrative-imap-connection) | Test IMAP and SMTP settings without saving an account. Requires admin.accounts. | | [Update IMAP folders](/docs/rest-api/update-administrative-imap-folders) | Update the folder overrides for an IMAP account. Requires admin.accounts. | | [List API keys](/docs/rest-api/list-administrative-api-keys) | List API key metadata without returning plaintext secrets. Requires admin.api\_keys. | | [Create an API key](/docs/rest-api/create-administrative-api-key) | Create an API key and return its plaintext secret once. Requires admin.api\_keys. | | [Update an API key](/docs/rest-api/update-administrative-api-key) | Update the permissions or mailbox scope of an API key. Requires admin.api\_keys. | | [Revoke an API key](/docs/rest-api/revoke-administrative-api-key) | Revoke an API key. Requires admin.api\_keys. | | [Get OAuth application status](/docs/rest-api/get-administrative-oauth-apps) | Get safe OAuth application metadata without returning client secrets. Requires admin.accounts. | | [Configure an OAuth application](/docs/rest-api/put-administrative-oauth-app) | Save an OAuth application in encrypted instance settings. Requires admin.accounts. | | [Reset an OAuth application](/docs/rest-api/delete-administrative-oauth-app) | Remove a stored OAuth application. Requires admin.accounts. | | [Get license status](/docs/rest-api/get-administrative-license) | Get license status and usage without returning the configured license key. Requires admin.license. | | [Deactivate a license](/docs/rest-api/deactivate-administrative-license) | Release the stored license and return this instance to Personal limits. Requires admin.license. | | [Activate a license](/docs/rest-api/activate-administrative-license) | Validate and activate a Fluxmail license key. Requires admin.license. | | [Get API information](/docs/rest-api/get-api-info) | Return the Fluxmail version and the URL of the OpenAPI document. | | [Get server status](/docs/rest-api/get-status) | Return provider and mailbox status for the accounts available to the API key. | | [List accounts](/docs/rest-api/list-accounts) | List the email accounts available to the API key. | | [List folders](/docs/rest-api/list-folders) | List folders in an email account. | | [List labels](/docs/rest-api/list-labels) | List Gmail user labels or Outlook categories in an email account. | | [List sender addresses](/docs/rest-api/list-send-as) | List sender addresses available for an email account. | | [Replace configured sender addresses](/docs/rest-api/replace-send-as) | Replace the configured Outlook or IMAP aliases for an email account. | | [List messages](/docs/rest-api/list-messages) | List and filter messages in an email account. | | [Search multiple accounts](/docs/rest-api/search-messages) | Search up to 20 email accounts with one portable query. | | [Get a message](/docs/rest-api/get-message) | Get one message by its provider ID. | | [Get a thread](/docs/rest-api/get-thread) | Get a complete email thread by its provider ID. | | [Get a draft](/docs/rest-api/get-draft) | Get a draft | | [Replace a draft](/docs/rest-api/update-draft) | Replace the full content of an existing draft. | | [Delete a draft](/docs/rest-api/delete-draft) | Delete an existing draft from an email account. | | [Create a draft](/docs/rest-api/create-draft) | Create a new draft or a reply draft in an email account. | | [Preview a send](/docs/rest-api/preview-send) | Preview a send | | [Send or schedule a message](/docs/rest-api/send-message) | Send a message now or schedule it for a specified time. | | [Get a delivery outcome](/docs/rest-api/get-delivery-operation) | Get a delivery outcome | | [List scheduled sends](/docs/rest-api/list-scheduled-sends) | List scheduled messages in an email account. | | [Cancel a scheduled send](/docs/rest-api/cancel-scheduled-send) | Cancel a pending scheduled send and keep its provider draft. | | [Forward a message](/docs/rest-api/forward-message) | Forward a message to one or more recipients. | | [Modify messages](/docs/rest-api/modify-messages) | Apply one mailbox action to a batch of messages. | | [Download an attachment](/docs/rest-api/download-attachment) | Download one attachment as raw bytes. | ## Common behavior [#common-behavior] * JSON responses put results in `data`. Paginated responses provide `meta.nextPageToken`. * Send and forward requests require an `Idempotency-Key` header. Their endpoint pages explain safe retries. * API keys use the profiles and capabilities described in [Permissions](/docs/permissions). * Errors return an `error` object with a stable `code` and `message`. ## OpenAPI schema [#openapi-schema] The OpenAPI 3.1 schema is public: ```text curl http://localhost:8977/api/v1/openapi.json \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` Use the schema or the endpoint pages for request parameters, JSON bodies, and response details. --- # Issue a member invitation URL: https://fluxmail.ai/docs/rest-api/invite-member `POST /api/v1/admin/members/{memberId}/invitation` Reference for POST /api/v1/admin/members/\{memberId}/invitation. ## Authentication [#authentication] Pass an administrator member session or an API key as a bearer token. An API key must include the administrative capability named in the endpoint description. Remote administrative requests require HTTPS. Requests from the local computer can use HTTP. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/admin/members/memberId_123/invitation' \ -X POST \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ---------- | -------- | -------- | -------- | ------------------ | | `memberId` | path | Yes | `string` | Minimum length: 1. | ## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------- | ------------------ | | `200` | Success | `application/json` | | `201` | Success | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission denied | `application/json` | | `404` | Not found | `application/json` | | `409` | Conflict | `application/json` | | `413` | Request body too large | `application/json` | | `429` | Too many attempts | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "nullable": true } } } ```
### 201 response [#201-response]
JSON schema ```json { "type": "object", "properties": { "data": { "nullable": true } } } ```
--- # List accounts URL: https://fluxmail.ai/docs/rest-api/list-accounts `GET /api/v1/accounts` List the email accounts available to the API key. ## Authentication [#authentication] Pass a Fluxmail member session or API key as a bearer token. API keys apply their mailbox scope and permissions to the request. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/accounts' \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` This endpoint has no parameters or request body. ## Responses [#responses] | Status | Description | Content type | | ------ | ------------------------- | ------------------ | | `200` | Accounts | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission or plan denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `422` | Unsupported capability | `application/json` | | `429` | Provider rate limit | `application/json` | | `500` | Internal error | `application/json` | | `503` | Provider unavailable | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "provider": { "type": "string", "enum": [ "gmail", "outlook", "imap" ] }, "email": { "type": "string" }, "displayName": { "type": "string" }, "status": { "type": "string", "enum": [ "active", "auth_error", "disabled" ] }, "capabilities": { "type": "object", "properties": { "labels": { "type": "boolean" }, "serverThreads": { "type": "boolean" }, "serverSearch": { "type": "string", "enum": [ "rich", "basic" ] }, "search": { "type": "object", "properties": { "filters": { "type": "array", "items": { "type": "string", "enum": [ "folder", "text", "from", "to", "subject", "read", "starred", "hasAttachment", "after", "before" ] } }, "folderRoles": { "type": "object", "properties": { "inbox": { "type": "string", "enum": [ "available", "unavailable", "unknown" ] }, "sent": { "type": "string", "enum": [ "available", "unavailable", "unknown" ] }, "drafts": { "type": "string", "enum": [ "available", "unavailable", "unknown" ] }, "archive": { "type": "string", "enum": [ "available", "unavailable", "unknown" ] }, "spam": { "type": "string", "enum": [ "available", "unavailable", "unknown" ] }, "trash": { "type": "string", "enum": [ "available", "unavailable", "unknown" ] }, "all": { "type": "string", "enum": [ "available", "unavailable", "unknown" ] } }, "required": [ "inbox", "sent", "drafts", "archive", "spam", "trash", "all" ], "additionalProperties": false }, "nativeQuery": { "type": "object", "nullable": true, "properties": { "syntax": { "type": "string", "enum": [ "gmail", "outlook-kql" ] }, "availability": { "type": "string", "enum": [ "available", "unavailable", "unknown" ] }, "unavailableReason": { "type": "string" } }, "required": [ "syntax", "availability" ], "additionalProperties": false } }, "required": [ "filters", "folderRoles", "nativeQuery" ], "additionalProperties": false }, "snippets": { "type": "boolean" }, "searchContext": { "type": "boolean", "description": "Supports optional match-centered body excerpts." } }, "required": [ "labels", "serverThreads", "serverSearch", "search", "snippets" ], "additionalProperties": false }, "ownerMemberId": { "type": "string" }, "sharedWithAll": { "type": "boolean" }, "grantedMemberIds": { "type": "array", "items": { "type": "string" } } }, "required": [ "id", "provider", "email", "status", "capabilities", "ownerMemberId", "sharedWithAll", "grantedMemberIds" ], "additionalProperties": false } }, "warnings": { "type": "array", "items": { "type": "string" } } }, "required": [ "data" ], "additionalProperties": false } ```
--- # List all mailbox account metadata URL: https://fluxmail.ai/docs/rest-api/list-admin-accounts `GET /api/v1/admin/accounts` Reference for GET /api/v1/admin/accounts. ## Authentication [#authentication] Pass an administrator member session or an API key as a bearer token. An API key must include the administrative capability named in the endpoint description. Remote administrative requests require HTTPS. Requests from the local computer can use HTTP. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/admin/accounts' \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` This endpoint has no parameters or request body. ## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------- | ------------------ | | `200` | Success | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission denied | `application/json` | | `404` | Not found | `application/json` | | `409` | Conflict | `application/json` | | `413` | Request body too large | `application/json` | | `429` | Too many attempts | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "nullable": true } } } ```
--- # List API keys URL: https://fluxmail.ai/docs/rest-api/list-administrative-api-keys `GET /api/v1/admin/api-keys` List API key metadata without returning plaintext secrets. Requires admin.api\_keys. ## Authentication [#authentication] Pass an administrator member session or an API key as a bearer token. An API key must include the administrative capability named in the endpoint description. Remote administrative requests require HTTPS. Requests from the local computer can use HTTP. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/admin/api-keys' \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` This endpoint has no parameters or request body. ## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------------- | ------------------ | | `200` | API keys | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Administrative access denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `413` | Request body too large | `application/json` | | `415` | Unsupported media type | `application/json` | | `500` | Internal error | `application/json` | | `502` | License could not be verified | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "createdAt": { "type": "string" }, "lastUsedAt": { "type": "string", "nullable": true }, "memberId": { "type": "string" }, "permissionProfile": { "type": "string", "enum": [ "read-only", "read-write", "full", "custom" ] }, "capabilities": { "type": "array", "items": { "type": "string", "enum": [ "mail.read", "mail.drafts", "mail.organize", "mail.trash", "mail.delete", "mail.send", "admin.accounts", "admin.members", "admin.api_keys", "admin.license", "admin.audit" ] } }, "supplementalCapabilities": { "type": "array", "items": { "type": "string", "enum": [ "admin.accounts", "admin.members", "admin.api_keys", "admin.license", "admin.audit" ] } }, "accountIds": { "type": "array", "nullable": true, "items": { "type": "string" } } }, "required": [ "id", "name", "createdAt", "lastUsedAt", "memberId", "permissionProfile", "capabilities", "supplementalCapabilities", "accountIds" ], "additionalProperties": false } } }, "required": [ "data" ] } ```
--- # List security audit events URL: https://fluxmail.ai/docs/rest-api/list-audit-events `GET /api/v1/admin/audit-events` Reference for GET /api/v1/admin/audit-events. ## Authentication [#authentication] Pass an administrator member session or an API key as a bearer token. An API key must include the administrative capability named in the endpoint description. Remote administrative requests require HTTPS. Requests from the local computer can use HTTP. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/admin/audit-events' \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ------- | -------- | -------- | -------- | ----------------- | | `limit` | query | No | `string` | Pattern: `^\d+$`. | ## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------- | ------------------ | | `200` | Success | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission denied | `application/json` | | `404` | Not found | `application/json` | | `409` | Conflict | `application/json` | | `413` | Request body too large | `application/json` | | `429` | Too many attempts | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "nullable": true } } } ```
--- # List folders URL: https://fluxmail.ai/docs/rest-api/list-folders `GET /api/v1/accounts/{accountId}/folders` List folders in an email account. ## Authentication [#authentication] Pass a Fluxmail member session or API key as a bearer token. API keys apply their mailbox scope and permissions to the request. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/accounts/acct_123/folders' \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ----------- | -------- | -------- | -------- | ------------------ | | `accountId` | path | Yes | `string` | Minimum length: 1. | ## Responses [#responses] | Status | Description | Content type | | ------ | ------------------------- | ------------------ | | `200` | Folders | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission or plan denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `422` | Unsupported capability | `application/json` | | `429` | Provider rate limit | `application/json` | | `500` | Internal error | `application/json` | | `503` | Provider unavailable | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "role": { "type": "string", "enum": [ "inbox", "sent", "drafts", "trash", "spam", "archive", "starred", "all" ] }, "roleSource": { "type": "string", "enum": [ "user", "extension", "name" ] }, "unreadCount": { "type": "integer", "minimum": 0 } }, "required": [ "id", "name" ], "additionalProperties": false } }, "warnings": { "type": "array", "items": { "type": "string" } } }, "required": [ "data" ], "additionalProperties": false } ```
--- # List labels URL: https://fluxmail.ai/docs/rest-api/list-labels `GET /api/v1/accounts/{accountId}/labels` List Gmail user labels or Outlook categories in an email account. ## Authentication [#authentication] Pass a Fluxmail member session or API key as a bearer token. API keys apply their mailbox scope and permissions to the request. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/accounts/acct_123/labels' \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ----------- | -------- | -------- | -------- | ------------------ | | `accountId` | path | Yes | `string` | Minimum length: 1. | ## Responses [#responses] | Status | Description | Content type | | ------ | ------------------------- | ------------------ | | `200` | Labels | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission or plan denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `422` | Unsupported capability | `application/json` | | `429` | Provider rate limit | `application/json` | | `500` | Internal error | `application/json` | | `503` | Provider unavailable | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "color": { "type": "object", "properties": { "background": { "type": "string" }, "text": { "type": "string" }, "preset": { "type": "string" } }, "additionalProperties": false } }, "required": [ "id", "name" ], "additionalProperties": false } }, "warnings": { "type": "array", "items": { "type": "string" } } }, "required": [ "data" ], "additionalProperties": false } ```
--- # List a member's sessions URL: https://fluxmail.ai/docs/rest-api/list-member-sessions `GET /api/v1/admin/members/{memberId}/sessions` Reference for GET /api/v1/admin/members/\{memberId}/sessions. ## Authentication [#authentication] Pass an administrator member session or an API key as a bearer token. An API key must include the administrative capability named in the endpoint description. Remote administrative requests require HTTPS. Requests from the local computer can use HTTP. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/admin/members/memberId_123/sessions' \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ---------- | -------- | -------- | -------- | ------------------ | | `memberId` | path | Yes | `string` | Minimum length: 1. | ## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------- | ------------------ | | `200` | Success | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission denied | `application/json` | | `404` | Not found | `application/json` | | `409` | Conflict | `application/json` | | `413` | Request body too large | `application/json` | | `429` | Too many attempts | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "nullable": true } } } ```
--- # List members URL: https://fluxmail.ai/docs/rest-api/list-members `GET /api/v1/admin/members` Reference for GET /api/v1/admin/members. ## Authentication [#authentication] Pass an administrator member session or an API key as a bearer token. An API key must include the administrative capability named in the endpoint description. Remote administrative requests require HTTPS. Requests from the local computer can use HTTP. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/admin/members' \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` This endpoint has no parameters or request body. ## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------- | ------------------ | | `200` | Success | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission denied | `application/json` | | `404` | Not found | `application/json` | | `409` | Conflict | `application/json` | | `413` | Request body too large | `application/json` | | `429` | Too many attempts | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "nullable": true } } } ```
--- # List messages URL: https://fluxmail.ai/docs/rest-api/list-messages `GET /api/v1/accounts/{accountId}/messages` List and filter messages in an email account. ## Authentication [#authentication] Pass a Fluxmail member session or API key as a bearer token. API keys apply their mailbox scope and permissions to the request. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/accounts/acct_123/messages' \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ---------------------- | -------- | -------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `accountId` | path | Yes | `string` | Minimum length: 1. | | `query` | query | No | `string` | Typed portable search syntax Minimum length: 1. | | `folder` | query | No | `string` | Folder role (inbox, sent, drafts, trash, spam, starred, archive, all) or a label/folder name. Use all or omit this field to search all mail except Spam and Trash. An IMAP server's \All mailbox may use different rules. Minimum length: 1. | | `text` | query | No | `string` | Literal full-text search terms | | `from` | query | No | `string` | None | | `to` | query | No | `string` | None | | `subject` | query | No | `string` | None | | `read` | query | No | `true` or `false` | None | | `starred` | query | No | `true` or `false` | None | | `hasAttachment` | query | No | `true` or `false` | None | | `after` | query | No | `string` | Format: `date`. Pattern: `^\d{4}-\d{2}-\d{2}$`. | | `before` | query | No | `string` | Format: `date`. Pattern: `^\d{4}-\d{2}-\d{2}$`. | | `rawProviderQuery` | query | No | `string` | Provider-native Gmail syntax or Outlook KQL | | `pageSize` | query | No | `string` | Pattern: `^(?:[1-9]\|[1-9][0-9]\|100)$`. | | `pageToken` | query | No | `string` | Minimum length: 1. | | `includeSnippet` | query | No | `true` or `false` | None | | `includeSearchContext` | query | No | `true` or `false` | Include a match-centered body excerpt. Requires a portable text query. | ## Responses [#responses] | Status | Description | Content type | | ------ | ------------------------- | ------------------ | | `200` | Messages | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission or plan denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `422` | Unsupported capability | `application/json` | | `429` | Provider rate limit | `application/json` | | `500` | Internal error | `application/json` | | `503` | Provider unavailable | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "threadId": { "type": "string" }, "accountId": { "type": "string" }, "draftId": { "type": "string" }, "folder": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "role": { "type": "string", "enum": [ "inbox", "sent", "drafts", "trash", "spam", "archive", "starred", "all" ] }, "roleSource": { "type": "string", "enum": [ "user", "extension", "name" ] }, "unreadCount": { "type": "integer", "minimum": 0 } }, "required": [ "id", "name" ], "additionalProperties": false }, "labels": { "type": "array", "items": { "type": "string" } }, "from": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false }, "to": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "cc": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "bcc": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "replyTo": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "subject": { "type": "string" }, "date": { "type": "string" }, "snippet": { "type": "string" }, "searchContext": { "anyOf": [ { "type": "object", "properties": { "status": { "type": "string", "enum": [ "matched" ] }, "excerpt": { "type": "string" } }, "required": [ "status", "excerpt" ], "additionalProperties": false }, { "type": "object", "properties": { "status": { "type": "string", "enum": [ "no_literal_match", "scan_limit", "unavailable" ] } }, "required": [ "status" ], "additionalProperties": false } ], "description": "Optional body excerpt status for a requested portable text search." }, "body": { "type": "object", "properties": { "text": { "type": "string" }, "html": { "type": "string" } }, "additionalProperties": false }, "attachments": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "filename": { "type": "string" }, "mimeType": { "type": "string" }, "sizeBytes": { "type": "integer", "minimum": 0 }, "contentId": { "type": "string" }, "disposition": { "type": "string", "enum": [ "inline", "attachment" ] } }, "required": [ "id", "filename", "mimeType", "sizeBytes" ], "additionalProperties": false } }, "flags": { "type": "object", "properties": { "read": { "type": "boolean" }, "starred": { "type": "boolean" }, "draft": { "type": "boolean" } }, "required": [ "read", "starred", "draft" ], "additionalProperties": false }, "headers": { "type": "object", "additionalProperties": { "type": "string" } } }, "required": [ "id", "threadId", "accountId", "to", "subject", "date", "flags" ], "additionalProperties": false } }, "meta": { "type": "object", "properties": { "nextPageToken": { "type": "string" }, "exhausted": { "type": "boolean" }, "diagnostics": { "type": "array", "items": { "type": "object", "properties": { "code": { "type": "string" }, "severity": { "type": "string", "enum": [ "error", "warning" ] }, "message": { "type": "string" }, "start": { "type": "integer", "minimum": 0 }, "end": { "type": "integer", "minimum": 0 }, "suggestion": { "type": "string" } }, "required": [ "code", "severity", "message" ], "additionalProperties": false } }, "incomplete": { "type": "boolean", "enum": [ true ] }, "incompleteReason": { "type": "string", "enum": [ "scan_limit", "provider_limit", "time_limit" ] }, "inspectedCandidates": { "type": "integer", "minimum": 0 } }, "required": [ "exhausted" ], "additionalProperties": false }, "warnings": { "type": "array", "items": { "type": "string" } } }, "required": [ "data", "meta" ], "additionalProperties": false } ```
--- # List API keys owned by the current member URL: https://fluxmail.ai/docs/rest-api/list-own-api-keys `GET /api/v1/me/api-keys` Reference for GET /api/v1/me/api-keys. ## Authentication [#authentication] Pass a Fluxmail member session as a bearer token. API keys cannot use this endpoint. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/me/api-keys' \ -H "Authorization: Bearer $FLUXMAIL_SESSION" ``` This endpoint has no parameters or request body. ## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------- | ------------------ | | `200` | Success | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission denied | `application/json` | | `404` | Not found | `application/json` | | `409` | Conflict | `application/json` | | `413` | Request body too large | `application/json` | | `429` | Too many attempts | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "nullable": true } } } ```
--- # List scheduled sends URL: https://fluxmail.ai/docs/rest-api/list-scheduled-sends `GET /api/v1/accounts/{accountId}/scheduled-sends` List scheduled messages in an email account. ## Authentication [#authentication] Pass a Fluxmail member session or API key as a bearer token. API keys apply their mailbox scope and permissions to the request. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/accounts/acct_123/scheduled-sends' \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ----------- | -------- | -------- | -------- | ------------------ | | `accountId` | path | Yes | `string` | Minimum length: 1. | ## Responses [#responses] | Status | Description | Content type | | ------ | ------------------------- | ------------------ | | `200` | Scheduled sends | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission or plan denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `422` | Unsupported capability | `application/json` | | `429` | Provider rate limit | `application/json` | | `500` | Internal error | `application/json` | | `503` | Provider unavailable | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "scheduleId": { "type": "string" }, "operationId": { "type": "string" }, "accountId": { "type": "string" }, "draftId": { "type": "string" }, "sendAt": { "type": "string" }, "status": { "type": "string", "enum": [ "pending", "sending", "sent", "failed", "uncertain", "canceled" ] }, "attempts": { "type": "integer", "minimum": 0 }, "subject": { "type": "string" }, "to": { "type": "string" }, "lastError": { "type": "string" }, "sentMessageId": { "type": "string" }, "sentThreadId": { "type": "string" } }, "required": [ "scheduleId", "accountId", "draftId", "sendAt", "status", "attempts" ], "additionalProperties": false } }, "warnings": { "type": "array", "items": { "type": "string" } } }, "required": [ "data" ], "additionalProperties": false } ```
--- # List sender addresses URL: https://fluxmail.ai/docs/rest-api/list-send-as `GET /api/v1/accounts/{accountId}/send-as` List sender addresses available for an email account. ## Authentication [#authentication] Pass a Fluxmail member session or API key as a bearer token. API keys apply their mailbox scope and permissions to the request. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/accounts/acct_123/send-as' \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ----------- | -------- | -------- | -------- | ------------------ | | `accountId` | path | Yes | `string` | Minimum length: 1. | ## Responses [#responses] | Status | Description | Content type | | ------ | ------------------------- | ------------------ | | `200` | Sender addresses | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission or plan denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `422` | Unsupported capability | `application/json` | | `429` | Provider rate limit | `application/json` | | `500` | Internal error | `application/json` | | `503` | Provider unavailable | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string" }, "replyTo": { "type": "string", "format": "email" }, "isPrimary": { "type": "boolean" }, "source": { "type": "string", "enum": [ "provider", "configured" ] } }, "required": [ "email", "isPrimary", "source" ], "additionalProperties": false } }, "warnings": { "type": "array", "items": { "type": "string" } } }, "required": [ "data" ], "additionalProperties": false } ```
--- # List current member sessions URL: https://fluxmail.ai/docs/rest-api/list-sessions `GET /api/v1/me/sessions` Reference for GET /api/v1/me/sessions. ## Authentication [#authentication] Pass a Fluxmail member session as a bearer token. API keys cannot use this endpoint. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/me/sessions' \ -H "Authorization: Bearer $FLUXMAIL_SESSION" ``` This endpoint has no parameters or request body. ## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------- | ------------------ | | `200` | Success | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission denied | `application/json` | | `404` | Not found | `application/json` | | `409` | Conflict | `application/json` | | `413` | Request body too large | `application/json` | | `429` | Too many attempts | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "nullable": true } } } ```
--- # Log in with a member email and password URL: https://fluxmail.ai/docs/rest-api/login `POST /api/v1/auth/login` Reference for POST /api/v1/auth/login. ## Authentication [#authentication] This endpoint does not require authentication. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/auth/login' \ -X POST \ -H "Content-Type: application/json" \ --data '{ "email": "person@example.com", "password": "string", "deviceName": "string" }' ``` ### Request body [#request-body] Content type: `application/json`
JSON schema ```json { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "password": { "type": "string" }, "deviceName": { "type": "string", "minLength": 1, "maxLength": 200 } }, "required": [ "email", "password", "deviceName" ], "additionalProperties": false } ```
## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------- | ------------------ | | `200` | Success | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission denied | `application/json` | | `404` | Not found | `application/json` | | `409` | Conflict | `application/json` | | `413` | Request body too large | `application/json` | | `429` | Too many attempts | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "nullable": true } } } ```
--- # Revoke the current member session URL: https://fluxmail.ai/docs/rest-api/logout `POST /api/v1/auth/logout` Reference for POST /api/v1/auth/logout. ## Authentication [#authentication] Pass a Fluxmail member session as a bearer token. API keys cannot use this endpoint. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/auth/logout' \ -X POST \ -H "Authorization: Bearer $FLUXMAIL_SESSION" ``` This endpoint has no parameters or request body. ## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------- | ------------------ | | `200` | Success | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission denied | `application/json` | | `404` | Not found | `application/json` | | `409` | Conflict | `application/json` | | `413` | Request body too large | `application/json` | | `429` | Too many attempts | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "nullable": true } } } ```
--- # Modify messages URL: https://fluxmail.ai/docs/rest-api/modify-messages `POST /api/v1/accounts/{accountId}/messages/actions` Apply one mailbox action to a batch of messages. ## Authentication [#authentication] Pass a Fluxmail member session or API key as a bearer token. API keys apply their mailbox scope and permissions to the request. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/accounts/acct_123/messages/actions' \ -X POST \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" \ -H "Content-Type: application/json" \ --data '{ "messageIds": [ "msg_123" ], "action": "markRead" }' ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ----------- | -------- | -------- | -------- | ------------------ | | `accountId` | path | Yes | `string` | Minimum length: 1. | ### Request body [#request-body] Content type: `application/json`
JSON schema ```json { "type": "object", "properties": { "messageIds": { "type": "array", "items": { "type": "string", "minLength": 1, "example": "msg_123" }, "minItems": 1 }, "action": { "type": "string", "enum": [ "markRead", "markUnread", "star", "unstar", "archive", "trash", "untrash", "delete", "move", "addLabels", "removeLabels" ] }, "folder": { "type": "string", "minLength": 1, "description": "Required when action is move. Use archive or trash instead of moving to those folders." }, "labels": { "type": "array", "items": { "type": "string", "minLength": 1 }, "maxItems": 100, "description": "Required when action is addLabels or removeLabels. Change Gmail system labels with dedicated actions." } }, "required": [ "messageIds", "action" ], "additionalProperties": false } ```
## Responses [#responses] | Status | Description | Content type | | ------ | ------------------------- | ------------------ | | `200` | Messages modified | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission or plan denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `422` | Unsupported capability | `application/json` | | `429` | Provider rate limit | `application/json` | | `500` | Internal error | `application/json` | | `503` | Provider unavailable | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "object", "properties": { "action": { "type": "string" }, "succeededIds": { "type": "array", "items": { "type": "string" } }, "failed": { "type": "array", "items": { "type": "object", "properties": { "messageId": { "type": "string" }, "code": { "type": "string" } }, "required": [ "messageId", "code" ], "additionalProperties": false } }, "uncertainIds": { "type": "array", "items": { "type": "string" } } }, "required": [ "action", "succeededIds", "failed", "uncertainIds" ], "additionalProperties": false }, "warnings": { "type": "array", "items": { "type": "string" } } }, "required": [ "data" ], "additionalProperties": false } ```
--- # Preview a send URL: https://fluxmail.ai/docs/rest-api/preview-send `POST /api/v1/accounts/{accountId}/send/preview` Reference for POST /api/v1/accounts/\{accountId}/send/preview. ## Authentication [#authentication] Pass a Fluxmail member session or API key as a bearer token. API keys apply their mailbox scope and permissions to the request. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/accounts/acct_123/send/preview' \ -X POST \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" \ -H "Content-Type: application/json" \ --data '{ "draftId": "draft_123" }' ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ----------- | -------- | -------- | -------- | ------------------ | | `accountId` | path | Yes | `string` | Minimum length: 1. | ### Request body [#request-body] Content type: `application/json`
JSON schema ```json { "anyOf": [ { "type": "object", "properties": { "draftId": { "type": "string", "minLength": 1, "example": "draft_123" }, "sendAt": { "type": "string", "format": "date-time" } }, "required": [ "draftId" ], "additionalProperties": false }, { "type": "object", "properties": { "from": { "type": "string", "format": "email" }, "to": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "cc": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "bcc": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "subject": { "type": "string" }, "body": { "type": "object", "properties": { "text": { "type": "string", "description": "Plain-text body. Line breaks appear in the sent email. Keep each prose paragraph on one continuous line and separate paragraphs with blank lines." }, "html": { "type": "string" } }, "additionalProperties": false }, "replyToMessageId": { "type": "string", "minLength": 1, "example": "msg_123" }, "replyAll": { "type": "boolean", "description": "Requires replyToMessageId when true." }, "attachments": { "type": "array", "items": { "type": "object", "properties": { "filename": { "type": "string", "minLength": 1 }, "mimeType": { "type": "string", "minLength": 1 }, "content": { "type": "string", "format": "byte", "pattern": "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$", "description": "Base64-encoded content" }, "contentId": { "type": "string", "minLength": 1 }, "disposition": { "type": "string", "enum": [ "inline", "attachment" ] } }, "required": [ "filename", "mimeType", "content" ], "additionalProperties": false } }, "sendAt": { "type": "string", "format": "date-time" } }, "required": [ "body" ], "additionalProperties": false } ] } ```
## Responses [#responses] | Status | Description | Content type | | ------ | ------------------------- | ------------------ | | `200` | Resolved send details | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission or plan denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `422` | Unsupported capability | `application/json` | | `429` | Provider rate limit | `application/json` | | `500` | Internal error | `application/json` | | `503` | Provider unavailable | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "object", "properties": { "accountId": { "type": "string" }, "from": { "type": "string" }, "to": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "cc": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "bcc": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "subject": { "type": "string" }, "attachments": { "type": "array", "items": { "type": "object", "properties": { "filename": { "type": "string" }, "mimeType": { "type": "string" }, "sizeBytes": { "type": "integer" } }, "required": [ "filename", "mimeType", "sizeBytes" ], "additionalProperties": false } }, "bodyTextChars": { "type": "integer" }, "bodyHtmlChars": { "type": "integer" } }, "required": [ "accountId", "from", "to", "cc", "bcc", "subject", "attachments", "bodyTextChars", "bodyHtmlChars" ], "additionalProperties": false }, "warnings": { "type": "array", "items": { "type": "string" } } }, "required": [ "data" ], "additionalProperties": false } ```
--- # Configure an OAuth application URL: https://fluxmail.ai/docs/rest-api/put-administrative-oauth-app `PUT /api/v1/admin/oauth-apps/{provider}` Save an OAuth application in encrypted instance settings. Requires admin.accounts. ## Authentication [#authentication] Pass an administrator member session or an API key as a bearer token. An API key must include the administrative capability named in the endpoint description. Remote administrative requests require HTTPS. Requests from the local computer can use HTTP. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/admin/oauth-apps/google' \ -X PUT \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" \ -H "Content-Type: application/json" \ --data '{ "clientId": "client-id.apps.example.com", "clientSecret": "client-secret" }' ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ---------- | -------- | -------- | --------------------- | ------- | | `provider` | path | Yes | `google` or `outlook` | None | ### Request body [#request-body] Content type: `application/json`
JSON schema ```json { "type": "object", "properties": { "clientId": { "type": "string", "minLength": 1, "maxLength": 2048, "example": "client-id.apps.example.com" }, "clientSecret": { "type": "string", "minLength": 1, "maxLength": 16384, "example": "client-secret" }, "tenantId": { "type": "string", "minLength": 1, "maxLength": 2048, "example": "common" }, "publicClient": { "type": "boolean" } }, "required": [ "clientId" ], "additionalProperties": false, "example": { "clientId": "client-id.apps.example.com", "clientSecret": "client-secret" } } ```
## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------------- | ------------------ | | `200` | OAuth applications | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Administrative access denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `413` | Request body too large | `application/json` | | `415` | Unsupported media type | `application/json` | | `500` | Internal error | `application/json` | | `502` | License could not be verified | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "object", "properties": { "google": { "type": "object", "properties": { "clientId": { "type": "string" }, "clientSecretConfigured": { "type": "boolean" }, "source": { "type": "string", "enum": [ "built-in", "stored", "environment", "environment-file" ] }, "mutable": { "type": "boolean" } }, "required": [ "clientId", "clientSecretConfigured", "source", "mutable" ] }, "outlook": { "type": "object", "properties": { "clientId": { "type": "string", "nullable": true }, "tenantId": { "type": "string", "nullable": true }, "clientSecretConfigured": { "type": "boolean" }, "source": { "type": "string", "nullable": true, "enum": [ "stored", "environment", "environment-file" ] }, "mutable": { "type": "boolean" } }, "required": [ "clientId", "tenantId", "clientSecretConfigured", "source", "mutable" ] } }, "required": [ "google", "outlook" ] } }, "required": [ "data" ], "additionalProperties": false } ```
--- # Remove a mailbox account owned by the current member URL: https://fluxmail.ai/docs/rest-api/remove-own-account `DELETE /api/v1/accounts/{accountId}/connection` Reference for DELETE /api/v1/accounts/\{accountId}/connection. ## Authentication [#authentication] Pass a Fluxmail member session as a bearer token. API keys cannot use this endpoint. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/accounts/acct_123/connection' \ -X DELETE \ -H "Authorization: Bearer $FLUXMAIL_SESSION" ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ----------- | -------- | -------- | -------- | ------------------ | | `accountId` | path | Yes | `string` | Minimum length: 1. | ## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------- | ------------------ | | `200` | Success | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission denied | `application/json` | | `404` | Not found | `application/json` | | `409` | Conflict | `application/json` | | `413` | Request body too large | `application/json` | | `429` | Too many attempts | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "nullable": true } } } ```
--- # Replace configured sender addresses URL: https://fluxmail.ai/docs/rest-api/replace-send-as `PUT /api/v1/accounts/{accountId}/send-as` Replace the configured Outlook or IMAP aliases for an email account. ## Authentication [#authentication] Pass a Fluxmail member session or API key as a bearer token. API keys apply their mailbox scope and permissions to the request. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/accounts/acct_123/send-as' \ -X PUT \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" \ -H "Content-Type: application/json" \ --data '{ "identities": [ { "email": "person@example.com" } ] }' ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ----------- | -------- | -------- | -------- | ------------------ | | `accountId` | path | Yes | `string` | Minimum length: 1. | ### Request body [#request-body] Content type: `application/json`
JSON schema ```json { "type": "object", "properties": { "identities": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string" } }, "required": [ "email" ], "additionalProperties": false } } }, "required": [ "identities" ], "additionalProperties": false } ```
## Responses [#responses] | Status | Description | Content type | | ------ | ------------------------- | ------------------ | | `200` | Sender addresses replaced | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission or plan denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `422` | Unsupported capability | `application/json` | | `429` | Provider rate limit | `application/json` | | `500` | Internal error | `application/json` | | `503` | Provider unavailable | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string" }, "replyTo": { "type": "string", "format": "email" }, "isPrimary": { "type": "boolean" }, "source": { "type": "string", "enum": [ "provider", "configured" ] } }, "required": [ "email", "isPrimary", "source" ], "additionalProperties": false } }, "warnings": { "type": "array", "items": { "type": "string" } } }, "required": [ "data" ], "additionalProperties": false } ```
--- # Redeem a password reset URL: https://fluxmail.ai/docs/rest-api/reset-password `POST /api/v1/auth/password-reset` Reference for POST /api/v1/auth/password-reset. ## Authentication [#authentication] This endpoint does not require authentication. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/auth/password-reset' \ -X POST \ -H "Content-Type: application/json" \ --data '{ "token": "string", "password": "string", "deviceName": "string" }' ``` ### Request body [#request-body] Content type: `application/json`
JSON schema ```json { "type": "object", "properties": { "token": { "type": "string", "minLength": 1 }, "password": { "type": "string" }, "deviceName": { "type": "string", "minLength": 1, "maxLength": 200 } }, "required": [ "token", "password", "deviceName" ], "additionalProperties": false } ```
## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------- | ------------------ | | `200` | Success | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission denied | `application/json` | | `404` | Not found | `application/json` | | `409` | Conflict | `application/json` | | `413` | Request body too large | `application/json` | | `429` | Too many attempts | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "nullable": true } } } ```
--- # Revoke an API key URL: https://fluxmail.ai/docs/rest-api/revoke-administrative-api-key `DELETE /api/v1/admin/api-keys/{keyId}` Revoke an API key. Requires admin.api\_keys. ## Authentication [#authentication] Pass an administrator member session or an API key as a bearer token. An API key must include the administrative capability named in the endpoint description. Remote administrative requests require HTTPS. Requests from the local computer can use HTTP. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/admin/api-keys/keyId_123' \ -X DELETE \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ------- | -------- | -------- | -------- | --------------------------------------- | | `keyId` | path | Yes | `string` | Minimum length: 1. Maximum length: 200. | ## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------------- | ------------------ | | `200` | Revoked API key | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Administrative access denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `413` | Request body too large | `application/json` | | `415` | Unsupported media type | `application/json` | | `500` | Internal error | `application/json` | | `502` | License could not be verified | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "object", "additionalProperties": { "nullable": true } } }, "required": [ "data" ], "additionalProperties": false } ```
--- # Revoke a member's session URL: https://fluxmail.ai/docs/rest-api/revoke-member-session `DELETE /api/v1/admin/members/{memberId}/sessions/{sessionId}` Reference for DELETE /api/v1/admin/members/\{memberId}/sessions/\{sessionId}. ## Authentication [#authentication] Pass an administrator member session or an API key as a bearer token. An API key must include the administrative capability named in the endpoint description. Remote administrative requests require HTTPS. Requests from the local computer can use HTTP. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/admin/members/memberId_123/sessions/sessionId_123' \ -X DELETE \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ----------- | -------- | -------- | -------- | ------------------ | | `memberId` | path | Yes | `string` | Minimum length: 1. | | `sessionId` | path | Yes | `string` | Minimum length: 1. | ## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------- | ------------------ | | `200` | Success | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission denied | `application/json` | | `404` | Not found | `application/json` | | `409` | Conflict | `application/json` | | `413` | Request body too large | `application/json` | | `429` | Too many attempts | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "nullable": true } } } ```
--- # Revoke an API key owned by the current member URL: https://fluxmail.ai/docs/rest-api/revoke-own-api-key `DELETE /api/v1/me/api-keys/{keyId}` Reference for DELETE /api/v1/me/api-keys/\{keyId}. ## Authentication [#authentication] Pass a Fluxmail member session as a bearer token. API keys cannot use this endpoint. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/me/api-keys/keyId_123' \ -X DELETE \ -H "Authorization: Bearer $FLUXMAIL_SESSION" ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ------- | -------- | -------- | -------- | ------------------ | | `keyId` | path | Yes | `string` | Minimum length: 1. | ## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------- | ------------------ | | `200` | Success | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission denied | `application/json` | | `404` | Not found | `application/json` | | `409` | Conflict | `application/json` | | `413` | Request body too large | `application/json` | | `429` | Too many attempts | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "nullable": true } } } ```
--- # Revoke a member session URL: https://fluxmail.ai/docs/rest-api/revoke-session `DELETE /api/v1/me/sessions/{sessionId}` Reference for DELETE /api/v1/me/sessions/\{sessionId}. ## Authentication [#authentication] Pass a Fluxmail member session as a bearer token. API keys cannot use this endpoint. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/me/sessions/sessionId_123' \ -X DELETE \ -H "Authorization: Bearer $FLUXMAIL_SESSION" ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ----------- | -------- | -------- | -------- | ------------------ | | `sessionId` | path | Yes | `string` | Minimum length: 1. | ## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------- | ------------------ | | `200` | Success | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission denied | `application/json` | | `404` | Not found | `application/json` | | `409` | Conflict | `application/json` | | `413` | Request body too large | `application/json` | | `429` | Too many attempts | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "nullable": true } } } ```
--- # Search multiple accounts URL: https://fluxmail.ai/docs/rest-api/search-messages `POST /api/v1/messages/search` Search up to 20 email accounts with one portable query. ## Authentication [#authentication] Pass a Fluxmail member session or API key as a bearer token. API keys apply their mailbox scope and permissions to the request. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/messages/search' \ -X POST \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" \ -H "Content-Type: application/json" \ --data '{ "accounts": [ { "accountId": "acct_123" } ], "query": "string" }' ``` ### Request body [#request-body] Content type: `application/json`
JSON schema ```json { "type": "object", "properties": { "accounts": { "type": "array", "items": { "type": "object", "properties": { "accountId": { "type": "string", "minLength": 1, "example": "acct_123" }, "pageToken": { "type": "string", "minLength": 1 } }, "required": [ "accountId" ], "additionalProperties": false }, "minItems": 1, "maxItems": 20 }, "query": { "type": "string", "minLength": 1 }, "folder": { "type": "string", "enum": [ "inbox", "sent", "drafts", "archive", "spam", "trash", "all" ] }, "text": { "type": "string" }, "from": { "type": "string" }, "to": { "type": "string" }, "subject": { "type": "string" }, "read": { "type": "boolean" }, "starred": { "type": "boolean" }, "hasAttachment": { "type": "boolean" }, "after": { "type": "string", "format": "date", "pattern": "^\\d{4}-\\d{2}-\\d{2}$" }, "before": { "type": "string", "format": "date", "pattern": "^\\d{4}-\\d{2}-\\d{2}$" }, "pageSize": { "type": "integer", "minimum": 1, "maximum": 100 }, "includeSnippet": { "type": "boolean" }, "includeSearchContext": { "type": "boolean", "description": "Include a match-centered body excerpt. Requires a portable text query." } }, "required": [ "accounts", "query" ], "additionalProperties": false } ```
## Responses [#responses] | Status | Description | Content type | | ------ | ------------------------- | ------------------ | | `200` | Grouped search results | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission or plan denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `422` | Unsupported capability | `application/json` | | `429` | Provider rate limit | `application/json` | | `500` | Internal error | `application/json` | | `503` | Provider unavailable | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "array", "items": { "anyOf": [ { "type": "object", "properties": { "accountId": { "type": "string" }, "data": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "threadId": { "type": "string" }, "accountId": { "type": "string" }, "draftId": { "type": "string" }, "folder": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "role": { "type": "string", "enum": [ "inbox", "sent", "drafts", "trash", "spam", "archive", "starred", "all" ] }, "roleSource": { "type": "string", "enum": [ "user", "extension", "name" ] }, "unreadCount": { "type": "integer", "minimum": 0 } }, "required": [ "id", "name" ], "additionalProperties": false }, "labels": { "type": "array", "items": { "type": "string" } }, "from": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false }, "to": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "cc": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "bcc": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "replyTo": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "subject": { "type": "string" }, "date": { "type": "string" }, "snippet": { "type": "string" }, "searchContext": { "anyOf": [ { "type": "object", "properties": { "status": { "type": "string", "enum": [ "matched" ] }, "excerpt": { "type": "string" } }, "required": [ "status", "excerpt" ], "additionalProperties": false }, { "type": "object", "properties": { "status": { "type": "string", "enum": [ "no_literal_match", "scan_limit", "unavailable" ] } }, "required": [ "status" ], "additionalProperties": false } ], "description": "Optional body excerpt status for a requested portable text search." }, "body": { "type": "object", "properties": { "text": { "type": "string" }, "html": { "type": "string" } }, "additionalProperties": false }, "attachments": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "filename": { "type": "string" }, "mimeType": { "type": "string" }, "sizeBytes": { "type": "integer", "minimum": 0 }, "contentId": { "type": "string" }, "disposition": { "type": "string", "enum": [ "inline", "attachment" ] } }, "required": [ "id", "filename", "mimeType", "sizeBytes" ], "additionalProperties": false } }, "flags": { "type": "object", "properties": { "read": { "type": "boolean" }, "starred": { "type": "boolean" }, "draft": { "type": "boolean" } }, "required": [ "read", "starred", "draft" ], "additionalProperties": false }, "headers": { "type": "object", "additionalProperties": { "type": "string" } } }, "required": [ "id", "threadId", "accountId", "to", "subject", "date", "flags" ], "additionalProperties": false } }, "meta": { "type": "object", "properties": { "nextPageToken": { "type": "string" }, "exhausted": { "type": "boolean" }, "diagnostics": { "type": "array", "items": { "type": "object", "properties": { "code": { "type": "string" }, "severity": { "type": "string", "enum": [ "error", "warning" ] }, "message": { "type": "string" }, "start": { "type": "integer", "minimum": 0 }, "end": { "type": "integer", "minimum": 0 }, "suggestion": { "type": "string" } }, "required": [ "code", "severity", "message" ], "additionalProperties": false } }, "incomplete": { "type": "boolean", "enum": [ true ] }, "incompleteReason": { "type": "string", "enum": [ "scan_limit", "provider_limit", "time_limit" ] }, "inspectedCandidates": { "type": "integer", "minimum": 0 } }, "required": [ "exhausted" ], "additionalProperties": false } }, "required": [ "accountId", "data", "meta" ], "additionalProperties": false }, { "type": "object", "properties": { "accountId": { "type": "string" }, "error": { "type": "object", "properties": { "code": { "type": "string" }, "message": { "type": "string" }, "data": { "type": "object", "additionalProperties": { "nullable": true } }, "exhausted": { "type": "boolean", "enum": [ false ] } }, "required": [ "code", "message", "exhausted" ], "additionalProperties": false } }, "required": [ "accountId", "error" ], "additionalProperties": false } ] } }, "meta": { "type": "object", "properties": { "exhausted": { "type": "boolean" } }, "required": [ "exhausted" ], "additionalProperties": false }, "warnings": { "type": "array", "items": { "type": "string" } } }, "required": [ "data", "meta" ], "additionalProperties": false } ```
--- # Send or schedule a message URL: https://fluxmail.ai/docs/rest-api/send-message `POST /api/v1/accounts/{accountId}/send` Send a message now or schedule it for a specified time. ## Authentication [#authentication] Pass a Fluxmail member session or API key as a bearer token. API keys apply their mailbox scope and permissions to the request. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/accounts/acct_123/send' \ -X POST \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ --data '{ "draftId": "draft_123" }' ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ----------------- | -------- | -------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | | `accountId` | path | Yes | `string` | Minimum length: 1. | | `Idempotency-Key` | header | Yes | `string` | A unique key for one intended delivery. Reuse it when retrying the same request. Minimum length: 1. Maximum length: 255. Pattern: `^[\x21-\x7e]+$`. | ### Request body [#request-body] Content type: `application/json`
JSON schema ```json { "anyOf": [ { "type": "object", "properties": { "draftId": { "type": "string", "minLength": 1, "example": "draft_123" }, "sendAt": { "type": "string", "format": "date-time" } }, "required": [ "draftId" ], "additionalProperties": false }, { "type": "object", "properties": { "from": { "type": "string", "format": "email" }, "to": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "cc": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "bcc": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "subject": { "type": "string" }, "body": { "type": "object", "properties": { "text": { "type": "string", "description": "Plain-text body. Line breaks appear in the sent email. Keep each prose paragraph on one continuous line and separate paragraphs with blank lines." }, "html": { "type": "string" } }, "additionalProperties": false }, "replyToMessageId": { "type": "string", "minLength": 1, "example": "msg_123" }, "replyAll": { "type": "boolean", "description": "Requires replyToMessageId when true." }, "attachments": { "type": "array", "items": { "type": "object", "properties": { "filename": { "type": "string", "minLength": 1 }, "mimeType": { "type": "string", "minLength": 1 }, "content": { "type": "string", "format": "byte", "pattern": "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$", "description": "Base64-encoded content" }, "contentId": { "type": "string", "minLength": 1 }, "disposition": { "type": "string", "enum": [ "inline", "attachment" ] } }, "required": [ "filename", "mimeType", "content" ], "additionalProperties": false } }, "sendAt": { "type": "string", "format": "date-time" } }, "required": [ "body" ], "additionalProperties": false } ] } ```
## Safe retries [#safe-retries] Fluxmail scopes each delivery key to the authenticated credential. Delivery operations and their keys have no automatic expiry. * Repeating a request with the same key and request data returns the stored delivery operation. It does not send again. * Reusing the key with different request data returns `409 idempotency_conflict`. * An `uncertain` operation may have been delivered. Fluxmail does not retry it automatically. Save the key with the request and reuse it if the response is lost. Look up the operation status before taking further action. For an `uncertain` result, check the Sent folder or recipient before creating a new delivery request. REST keys created before the delivery-operation upgrade keep their original 24 hour lifetime. A retry with one of those keys may return the legacy response shape and `Idempotency-Replayed: true`. ## Responses [#responses] | Status | Description | Content type | | ------ | ------------------------- | ------------------ | | `200` | Delivery operation | `application/json` | | `202` | Message scheduled | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission or plan denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `422` | Unsupported capability | `application/json` | | `429` | Provider rate limit | `application/json` | | `500` | Internal error | `application/json` | | `503` | Provider unavailable | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "object", "properties": { "operationId": { "type": "string" }, "accountId": { "type": "string" }, "kind": { "type": "string", "enum": [ "send", "forward", "scheduled" ] }, "status": { "type": "string", "enum": [ "queued", "sending", "succeeded", "failed", "uncertain" ] }, "result": { "type": "object", "properties": { "id": { "type": "string" }, "threadId": { "type": "string" }, "warnings": { "type": "array", "items": { "type": "string" } } }, "required": [ "id", "threadId" ], "additionalProperties": false }, "error": { "type": "object", "properties": { "code": { "type": "string" } }, "required": [ "code" ], "additionalProperties": false }, "scheduleId": { "type": "string" } }, "required": [ "operationId", "accountId", "kind", "status" ], "additionalProperties": false }, "warnings": { "type": "array", "items": { "type": "string" } } }, "required": [ "data" ], "additionalProperties": false } ```
### 202 response [#202-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "object", "properties": { "operationId": { "type": "string" }, "accountId": { "type": "string" }, "kind": { "type": "string", "enum": [ "send", "forward", "scheduled" ] }, "status": { "type": "string", "enum": [ "queued", "sending", "succeeded", "failed", "uncertain" ] }, "result": { "type": "object", "properties": { "id": { "type": "string" }, "threadId": { "type": "string" }, "warnings": { "type": "array", "items": { "type": "string" } } }, "required": [ "id", "threadId" ], "additionalProperties": false }, "error": { "type": "object", "properties": { "code": { "type": "string" } }, "required": [ "code" ], "additionalProperties": false }, "scheduleId": { "type": "string" } }, "required": [ "operationId", "accountId", "kind", "status" ], "additionalProperties": false }, "warnings": { "type": "array", "items": { "type": "string" } } }, "required": [ "data" ], "additionalProperties": false } ```
--- # Test an IMAP connection URL: https://fluxmail.ai/docs/rest-api/test-administrative-imap-connection `POST /api/v1/admin/imap/tests` Test IMAP and SMTP settings without saving an account. Requires admin.accounts. ## Authentication [#authentication] Pass an administrator member session or an API key as a bearer token. An API key must include the administrative capability named in the endpoint description. Remote administrative requests require HTTPS. Requests from the local computer can use HTTP. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/admin/imap/tests' \ -X POST \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" \ -H "Content-Type: application/json" \ --data '{ "email": "you@example.com", "imap": { "host": "imap.example.com", "port": 993, "security": "tls", "user": "you@example.com", "password": "app-password" }, "smtp": { "host": "smtp.example.com", "port": 465, "security": "tls", "user": "you@example.com", "password": "app-password" } }' ``` ### Request body [#request-body] Content type: `application/json`
JSON schema ```json { "type": "object", "properties": { "email": { "type": "string", "maxLength": 320, "format": "email" }, "displayName": { "type": "string", "minLength": 1, "maxLength": 200 }, "imap": { "type": "object", "properties": { "host": { "type": "string", "minLength": 1, "maxLength": 255 }, "port": { "type": "integer", "minimum": 1, "maximum": 65535 }, "security": { "type": "string", "enum": [ "tls", "starttls" ] }, "user": { "type": "string", "minLength": 1, "maxLength": 320 }, "password": { "type": "string", "minLength": 1, "maxLength": 4096 } }, "required": [ "host", "port", "security", "user", "password" ], "additionalProperties": false }, "smtp": { "type": "object", "properties": { "host": { "type": "string", "minLength": 1, "maxLength": 255 }, "port": { "type": "integer", "minimum": 1, "maximum": 65535 }, "security": { "type": "string", "enum": [ "tls", "starttls" ] }, "user": { "type": "string", "minLength": 1, "maxLength": 320 }, "password": { "type": "string", "minLength": 1, "maxLength": 4096 } }, "required": [ "host", "port", "security", "user", "password" ], "additionalProperties": false }, "saveSent": { "type": "boolean" }, "folderOverrides": { "type": "object", "properties": { "sent": { "type": "string", "minLength": 1, "maxLength": 1024 }, "drafts": { "type": "string", "minLength": 1, "maxLength": 1024 }, "trash": { "type": "string", "minLength": 1, "maxLength": 1024 }, "archive": { "type": "string", "minLength": 1, "maxLength": 1024 }, "spam": { "type": "string", "minLength": 1, "maxLength": 1024 } }, "additionalProperties": false } }, "required": [ "email", "imap", "smtp" ], "additionalProperties": false, "example": { "email": "you@example.com", "imap": { "host": "imap.example.com", "port": 993, "security": "tls", "user": "you@example.com", "password": "app-password" }, "smtp": { "host": "smtp.example.com", "port": 465, "security": "tls", "user": "you@example.com", "password": "app-password" } } } ```
## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------------- | ------------------ | | `200` | Connection test result | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Administrative access denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `413` | Request body too large | `application/json` | | `415` | Unsupported media type | `application/json` | | `500` | Internal error | `application/json` | | `502` | License could not be verified | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "object", "additionalProperties": { "nullable": true } } }, "required": [ "data" ], "additionalProperties": false } ```
--- # Update mailbox ownership and access URL: https://fluxmail.ai/docs/rest-api/update-account-access `PATCH /api/v1/admin/accounts/{accountId}` Reference for PATCH /api/v1/admin/accounts/\{accountId}. ## Authentication [#authentication] Pass an administrator member session or an API key as a bearer token. An API key must include the administrative capability named in the endpoint description. Remote administrative requests require HTTPS. Requests from the local computer can use HTTP. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/admin/accounts/acct_123' \ -X PATCH \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" \ -H "Content-Type: application/json" \ --data '{}' ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ----------- | -------- | -------- | -------- | ------------------ | | `accountId` | path | Yes | `string` | Minimum length: 1. | ### Request body [#request-body] Content type: `application/json`
JSON schema ```json { "type": "object", "properties": { "ownerMemberId": { "type": "string" }, "sharedWithAll": { "type": "boolean" }, "grantedMemberIds": { "type": "array", "items": { "type": "string" } } }, "additionalProperties": false } ```
## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------- | ------------------ | | `200` | Success | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission denied | `application/json` | | `404` | Not found | `application/json` | | `409` | Conflict | `application/json` | | `413` | Request body too large | `application/json` | | `429` | Too many attempts | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "nullable": true } } } ```
--- # Update an API key URL: https://fluxmail.ai/docs/rest-api/update-administrative-api-key `PATCH /api/v1/admin/api-keys/{keyId}` Update the permissions or mailbox scope of an API key. Requires admin.api\_keys. ## Authentication [#authentication] Pass an administrator member session or an API key as a bearer token. An API key must include the administrative capability named in the endpoint description. Remote administrative requests require HTTPS. Requests from the local computer can use HTTP. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/admin/api-keys/keyId_123' \ -X PATCH \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" \ -H "Content-Type: application/json" \ --data '{ "permissionProfile": "read-only" }' ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ------- | -------- | -------- | -------- | --------------------------------------- | | `keyId` | path | Yes | `string` | Minimum length: 1. Maximum length: 200. | ### Request body [#request-body] Content type: `application/json`
JSON schema ```json { "type": "object", "properties": { "permissionProfile": { "type": "string", "enum": [ "read-only", "read-write", "full" ] }, "supplementalCapabilities": { "type": "array", "items": { "type": "string", "enum": [ "admin.accounts", "admin.members", "admin.api_keys", "admin.license", "admin.audit" ] }, "maxItems": 5 }, "customCapabilities": { "type": "array", "items": { "type": "string", "enum": [ "mail.read", "mail.drafts", "mail.organize", "mail.trash", "mail.delete", "mail.send", "admin.accounts", "admin.members", "admin.api_keys", "admin.license", "admin.audit" ] }, "minItems": 1, "maxItems": 11 }, "accounts": { "type": "array", "nullable": true, "items": { "type": "string", "minLength": 1, "maxLength": 200 }, "maxItems": 100 } }, "additionalProperties": false, "example": { "permissionProfile": "read-only" } } ```
## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------------- | ------------------ | | `200` | Updated API key | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Administrative access denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `413` | Request body too large | `application/json` | | `415` | Unsupported media type | `application/json` | | `500` | Internal error | `application/json` | | `502` | License could not be verified | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "createdAt": { "type": "string" }, "lastUsedAt": { "type": "string", "nullable": true }, "memberId": { "type": "string" }, "permissionProfile": { "type": "string", "enum": [ "read-only", "read-write", "full", "custom" ] }, "capabilities": { "type": "array", "items": { "type": "string", "enum": [ "mail.read", "mail.drafts", "mail.organize", "mail.trash", "mail.delete", "mail.send", "admin.accounts", "admin.members", "admin.api_keys", "admin.license", "admin.audit" ] } }, "supplementalCapabilities": { "type": "array", "items": { "type": "string", "enum": [ "admin.accounts", "admin.members", "admin.api_keys", "admin.license", "admin.audit" ] } }, "accountIds": { "type": "array", "nullable": true, "items": { "type": "string" } } }, "required": [ "id", "name", "createdAt", "lastUsedAt", "memberId", "permissionProfile", "capabilities", "supplementalCapabilities", "accountIds" ], "additionalProperties": false } }, "required": [ "data" ] } ```
--- # Update IMAP folders URL: https://fluxmail.ai/docs/rest-api/update-administrative-imap-folders `PATCH /api/v1/admin/accounts/{accountId}/imap/folders` Update the folder overrides for an IMAP account. Requires admin.accounts. ## Authentication [#authentication] Pass an administrator member session or an API key as a bearer token. An API key must include the administrative capability named in the endpoint description. Remote administrative requests require HTTPS. Requests from the local computer can use HTTP. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/admin/accounts/acct_123/imap/folders' \ -X PATCH \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" \ -H "Content-Type: application/json" \ --data '{ "sent": "Sent" }' ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ----------- | -------- | -------- | -------- | --------------------------------------- | | `accountId` | path | Yes | `string` | Minimum length: 1. Maximum length: 200. | ### Request body [#request-body] Content type: `application/json`
JSON schema ```json { "type": "object", "properties": { "sent": { "type": "string", "nullable": true, "minLength": 1, "maxLength": 1024 }, "drafts": { "type": "string", "nullable": true, "minLength": 1, "maxLength": 1024 }, "trash": { "type": "string", "nullable": true, "minLength": 1, "maxLength": 1024 }, "archive": { "type": "string", "nullable": true, "minLength": 1, "maxLength": 1024 }, "spam": { "type": "string", "nullable": true, "minLength": 1, "maxLength": 1024 } }, "additionalProperties": false, "example": { "sent": "Sent" } } ```
## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------------- | ------------------ | | `200` | Updated folder overrides | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Administrative access denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `413` | Request body too large | `application/json` | | `415` | Unsupported media type | `application/json` | | `500` | Internal error | `application/json` | | `502` | License could not be verified | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "object", "additionalProperties": { "nullable": true } } }, "required": [ "data" ], "additionalProperties": false } ```
--- # Update the current member profile URL: https://fluxmail.ai/docs/rest-api/update-current-member `PATCH /api/v1/me` Reference for PATCH /api/v1/me. ## Authentication [#authentication] Pass a Fluxmail member session as a bearer token. API keys cannot use this endpoint. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/me' \ -X PATCH \ -H "Authorization: Bearer $FLUXMAIL_SESSION" \ -H "Content-Type: application/json" \ --data '{ "name": "string" }' ``` ### Request body [#request-body] Content type: `application/json`
JSON schema ```json { "type": "object", "properties": { "name": { "type": "string", "minLength": 1 } }, "required": [ "name" ], "additionalProperties": false } ```
## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------- | ------------------ | | `200` | Success | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission denied | `application/json` | | `404` | Not found | `application/json` | | `409` | Conflict | `application/json` | | `413` | Request body too large | `application/json` | | `429` | Too many attempts | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "nullable": true } } } ```
--- # Replace a draft URL: https://fluxmail.ai/docs/rest-api/update-draft `PUT /api/v1/accounts/{accountId}/drafts/{draftId}` Replace the full content of an existing draft. ## Authentication [#authentication] Pass a Fluxmail member session or API key as a bearer token. API keys apply their mailbox scope and permissions to the request. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/accounts/acct_123/drafts/draft_123' \ -X PUT \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" \ -H "Content-Type: application/json" \ --data '{ "body": {} }' ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ----------- | -------- | -------- | -------- | ------------------ | | `accountId` | path | Yes | `string` | Minimum length: 1. | | `draftId` | path | Yes | `string` | Minimum length: 1. | ### Request body [#request-body] Content type: `application/json`
JSON schema ```json { "type": "object", "properties": { "from": { "type": "string", "format": "email" }, "to": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "cc": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "bcc": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "subject": { "type": "string" }, "body": { "type": "object", "properties": { "text": { "type": "string", "description": "Plain-text body. Line breaks appear in the sent email. Keep each prose paragraph on one continuous line and separate paragraphs with blank lines." }, "html": { "type": "string" } }, "additionalProperties": false }, "replyToMessageId": { "type": "string", "minLength": 1, "example": "msg_123" }, "replyAll": { "type": "boolean", "description": "Requires replyToMessageId when true." }, "attachments": { "type": "array", "items": { "type": "object", "properties": { "filename": { "type": "string", "minLength": 1 }, "mimeType": { "type": "string", "minLength": 1 }, "content": { "type": "string", "format": "byte", "pattern": "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$", "description": "Base64-encoded content" }, "contentId": { "type": "string", "minLength": 1 }, "disposition": { "type": "string", "enum": [ "inline", "attachment" ] } }, "required": [ "filename", "mimeType", "content" ], "additionalProperties": false } } }, "required": [ "body" ], "additionalProperties": false } ```
## Responses [#responses] | Status | Description | Content type | | ------ | ------------------------- | ------------------ | | `200` | Draft replaced | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission or plan denied | `application/json` | | `404` | Resource not found | `application/json` | | `409` | Request conflict | `application/json` | | `422` | Unsupported capability | `application/json` | | `429` | Provider rate limit | `application/json` | | `500` | Internal error | `application/json` | | `503` | Provider unavailable | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "type": "object", "properties": { "id": { "type": "string" }, "threadId": { "type": "string" }, "accountId": { "type": "string" }, "draftId": { "type": "string" }, "folder": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "role": { "type": "string", "enum": [ "inbox", "sent", "drafts", "trash", "spam", "archive", "starred", "all" ] }, "roleSource": { "type": "string", "enum": [ "user", "extension", "name" ] }, "unreadCount": { "type": "integer", "minimum": 0 } }, "required": [ "id", "name" ], "additionalProperties": false }, "labels": { "type": "array", "items": { "type": "string" } }, "from": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false }, "to": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "cc": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "bcc": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "replyTo": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string", "minLength": 1 } }, "required": [ "email" ], "additionalProperties": false } }, "subject": { "type": "string" }, "date": { "type": "string" }, "snippet": { "type": "string" }, "searchContext": { "anyOf": [ { "type": "object", "properties": { "status": { "type": "string", "enum": [ "matched" ] }, "excerpt": { "type": "string" } }, "required": [ "status", "excerpt" ], "additionalProperties": false }, { "type": "object", "properties": { "status": { "type": "string", "enum": [ "no_literal_match", "scan_limit", "unavailable" ] } }, "required": [ "status" ], "additionalProperties": false } ], "description": "Optional body excerpt status for a requested portable text search." }, "body": { "type": "object", "properties": { "text": { "type": "string" }, "html": { "type": "string" } }, "additionalProperties": false }, "attachments": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "filename": { "type": "string" }, "mimeType": { "type": "string" }, "sizeBytes": { "type": "integer", "minimum": 0 }, "contentId": { "type": "string" }, "disposition": { "type": "string", "enum": [ "inline", "attachment" ] } }, "required": [ "id", "filename", "mimeType", "sizeBytes" ], "additionalProperties": false } }, "flags": { "type": "object", "properties": { "read": { "type": "boolean" }, "starred": { "type": "boolean" }, "draft": { "type": "boolean" } }, "required": [ "read", "starred", "draft" ], "additionalProperties": false }, "headers": { "type": "object", "additionalProperties": { "type": "string" } } }, "required": [ "id", "threadId", "accountId", "to", "subject", "date", "flags" ], "additionalProperties": false }, "warnings": { "type": "array", "items": { "type": "string" } } }, "required": [ "data" ], "additionalProperties": false } ```
--- # Update a member URL: https://fluxmail.ai/docs/rest-api/update-member `PATCH /api/v1/admin/members/{memberId}` Reference for PATCH /api/v1/admin/members/\{memberId}. ## Authentication [#authentication] Pass an administrator member session or an API key as a bearer token. An API key must include the administrative capability named in the endpoint description. Remote administrative requests require HTTPS. Requests from the local computer can use HTTP. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/admin/members/memberId_123' \ -X PATCH \ -H "Authorization: Bearer $FLUXMAIL_API_KEY" \ -H "Content-Type: application/json" \ --data '{}' ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ---------- | -------- | -------- | -------- | ------------------ | | `memberId` | path | Yes | `string` | Minimum length: 1. | ### Request body [#request-body] Content type: `application/json`
JSON schema ```json { "type": "object", "properties": { "name": { "type": "string", "minLength": 1 }, "email": { "type": "string", "format": "email" }, "role": { "type": "string", "enum": [ "admin", "member" ] }, "status": { "type": "string", "enum": [ "active", "suspended" ] } }, "additionalProperties": false } ```
## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------- | ------------------ | | `200` | Success | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission denied | `application/json` | | `404` | Not found | `application/json` | | `409` | Conflict | `application/json` | | `413` | Request body too large | `application/json` | | `429` | Too many attempts | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "nullable": true } } } ```
--- # Update folder settings for an owned IMAP mailbox URL: https://fluxmail.ai/docs/rest-api/update-owned-imap-folders `PATCH /api/v1/accounts/{accountId}/imap/folders` Reference for PATCH /api/v1/accounts/\{accountId}/imap/folders. ## Authentication [#authentication] Pass a Fluxmail member session as a bearer token. API keys cannot use this endpoint. ## Request [#request] ```bash curl 'http://localhost:8977/api/v1/accounts/acct_123/imap/folders' \ -X PATCH \ -H "Authorization: Bearer $FLUXMAIL_SESSION" \ -H "Content-Type: application/json" \ --data '{}' ``` ### Parameters [#parameters] | Name | Location | Required | Type | Details | | ----------- | -------- | -------- | -------- | ------------------ | | `accountId` | path | Yes | `string` | Minimum length: 1. | ### Request body [#request-body] Content type: `application/json`
JSON schema ```json { "type": "object", "properties": { "sent": { "type": "string", "nullable": true, "minLength": 1, "maxLength": 1024 }, "drafts": { "type": "string", "nullable": true, "minLength": 1, "maxLength": 1024 }, "trash": { "type": "string", "nullable": true, "minLength": 1, "maxLength": 1024 }, "archive": { "type": "string", "nullable": true, "minLength": 1, "maxLength": 1024 }, "spam": { "type": "string", "nullable": true, "minLength": 1, "maxLength": 1024 } }, "additionalProperties": false } ```
## Responses [#responses] | Status | Description | Content type | | ------ | ----------------------- | ------------------ | | `200` | Success | `application/json` | | `400` | Invalid request | `application/json` | | `401` | Authentication required | `application/json` | | `403` | Permission denied | `application/json` | | `404` | Not found | `application/json` | | `409` | Conflict | `application/json` | | `413` | Request body too large | `application/json` | | `422` | Unsupported capability | `application/json` | | `429` | Too many attempts | `application/json` | | `503` | Provider unavailable | `application/json` | ### 200 response [#200-response]
JSON schema ```json { "type": "object", "properties": { "data": { "nullable": true } } } ```
--- # Cancel scheduled email URL: https://fluxmail.ai/docs/tools/cancel-scheduled-email `cancel_scheduled_email` Cancel a pending scheduled send by scheduleId (from send\_email with sendAt, or list\_scheduled\_emails). The draft stays in the Drafts folder, so the content is not lost. ## Permissions [#permissions] Required capabilities: `mail.drafts`. ## Inputs [#inputs] | Name | Required | Type | Details | | ------------ | -------- | -------- | ------------------ | | `scheduleId` | Yes | `string` | Minimum length: 1. |
JSON input schema ```json { "type": "object", "properties": { "scheduleId": { "type": "string", "minLength": 1 } }, "required": [ "scheduleId" ], "additionalProperties": false, "$schema": "http://json-schema.org/draft-07/schema#" } ```
--- # Create draft URL: https://fluxmail.ai/docs/tools/create-draft `create_draft` Create a draft. For a reply draft, pass replyToMessageId (recipients/subject are derived; replyAll for reply-all). ## Permissions [#permissions] Required capabilities: `mail.drafts`. ## Inputs [#inputs] | Name | Required | Type | Details | | ------------------ | -------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `accountId` | No | `string` | Account to operate on. Optional when exactly one account is connected. Minimum length: 1. | | `from` | No | `string` | Connected address or an available send-as address Format: `email`. | | `to` | No | array of `string` | Recipients, each "Name [a@x.com](mailto:a@x.com)" or "[a@x.com](mailto:a@x.com)" | | `cc` | No | array of `string` | Recipients, each "Name [a@x.com](mailto:a@x.com)" or "[a@x.com](mailto:a@x.com)" | | `bcc` | No | array of `string` | Recipients, each "Name [a@x.com](mailto:a@x.com)" or "[a@x.com](mailto:a@x.com)" | | `subject` | No | `string` | Defaults to "Re: ..." when replying | | `bodyText` | No | `string` | Plain-text body. Line breaks appear in the sent email. Keep each prose paragraph on one continuous line and separate paragraphs with blank lines. | | `bodyHtml` | No | `string` | HTML body | | `replyToMessageId` | No | `string` | Message being replied to; threads correctly and computes recipients if "to" is omitted Minimum length: 1. | | `replyAll` | No | `boolean` | With replyToMessageId: reply to all original recipients | | `attachments` | No | array of `object` | None |
JSON input schema ```json { "type": "object", "properties": { "accountId": { "type": "string", "minLength": 1, "description": "Account to operate on. Optional when exactly one account is connected." }, "from": { "type": "string", "format": "email", "description": "Connected address or an available send-as address" }, "to": { "type": "array", "items": { "type": "string", "minLength": 1 }, "description": "Recipients, each \"Name \" or \"a@x.com\"" }, "cc": { "$ref": "#/properties/to", "description": "Recipients, each \"Name \" or \"a@x.com\"" }, "bcc": { "$ref": "#/properties/to", "description": "Recipients, each \"Name \" or \"a@x.com\"" }, "subject": { "type": "string", "description": "Defaults to \"Re: ...\" when replying" }, "bodyText": { "type": "string", "description": "Plain-text body. Line breaks appear in the sent email. Keep each prose paragraph on one continuous line and separate paragraphs with blank lines." }, "bodyHtml": { "type": "string", "description": "HTML body" }, "replyToMessageId": { "type": "string", "minLength": 1, "description": "Message being replied to; threads correctly and computes recipients if \"to\" is omitted" }, "replyAll": { "type": "boolean", "description": "With replyToMessageId: reply to all original recipients" }, "attachments": { "type": "array", "items": { "type": "object", "properties": { "filename": { "type": "string", "minLength": 1 }, "mimeType": { "type": "string", "minLength": 1 }, "content": { "type": "string", "description": "base64" } }, "required": [ "filename", "mimeType", "content" ], "additionalProperties": false } } }, "additionalProperties": false, "$schema": "http://json-schema.org/draft-07/schema#" } ```
--- # Delete draft URL: https://fluxmail.ai/docs/tools/delete-draft `delete_draft` Delete a draft. ## Permissions [#permissions] Required capabilities: `mail.drafts`. ## Inputs [#inputs] | Name | Required | Type | Details | | ----------- | -------- | -------- | ----------------------------------------------------------------------------------------- | | `accountId` | No | `string` | Account to operate on. Optional when exactly one account is connected. Minimum length: 1. | | `draftId` | Yes | `string` | Minimum length: 1. |
JSON input schema ```json { "type": "object", "properties": { "accountId": { "type": "string", "minLength": 1, "description": "Account to operate on. Optional when exactly one account is connected." }, "draftId": { "type": "string", "minLength": 1 } }, "required": [ "draftId" ], "additionalProperties": false, "$schema": "http://json-schema.org/draft-07/schema#" } ```
--- # Download attachment URL: https://fluxmail.ai/docs/tools/download-attachment `download_attachment` Get attachment metadata and a fetchable resource link. Set inline to embed the bytes. ## Permissions [#permissions] Required capabilities: `mail.read`. ## Inputs [#inputs] | Name | Required | Type | Details | | -------------- | -------- | --------- | -------------------------------------------------------------------- | | `accountId` | Yes | `string` | Minimum length: 1. | | `messageId` | Yes | `string` | None | | `attachmentId` | Yes | `string` | Opaque attachment ID returned by message metadata Minimum length: 1. | | `inline` | No | `boolean` | None |
JSON input schema ```json { "type": "object", "properties": { "accountId": { "type": "string", "minLength": 1 }, "messageId": { "$ref": "#/properties/accountId" }, "attachmentId": { "type": "string", "minLength": 1, "description": "Opaque attachment ID returned by message metadata" }, "inline": { "type": "boolean" } }, "required": [ "accountId", "messageId", "attachmentId" ], "additionalProperties": false, "$schema": "http://json-schema.org/draft-07/schema#" } ```
--- # Forward email URL: https://fluxmail.ai/docs/tools/forward-email `forward_email` Forward an email to new recipients: quoted original body, "Fwd:" subject, original attachments included unless includeAttachments=false. Optional comment appears above the forwarded content. ## Permissions [#permissions] Required capabilities: `mail.read` + `mail.send`. ## Inputs [#inputs] | Name | Required | Type | Details | | -------------------- | -------- | ----------------- | --------------------------------------------------------------------------------------------------------------------------- | | `idempotencyKey` | Yes | `string` | Reuse this key when retrying the same forward | | `accountId` | No | `string` | Account to operate on. Optional when exactly one account is connected. Minimum length: 1. | | `messageId` | Yes | `string` | Minimum length: 1. | | `from` | No | `string` | Connected address or an available send-as address Format: `email`. | | `to` | Yes | array of `string` | Recipients, each "Name [a@x.com](mailto:a@x.com)" or "[a@x.com](mailto:a@x.com)" | | `cc` | No | array of `string` | Recipients, each "Name [a@x.com](mailto:a@x.com)" or "[a@x.com](mailto:a@x.com)" | | `comment` | No | `string` | Comment above the forwarded message. Keep prose paragraphs on one continuous line and separate paragraphs with blank lines. | | `includeAttachments` | No | `boolean` | Default true |
JSON input schema ```json { "type": "object", "properties": { "idempotencyKey": { "type": "string", "pattern": "^[\\x21-\\x7e]{1,255}$", "description": "Reuse this key when retrying the same forward" }, "accountId": { "type": "string", "minLength": 1, "description": "Account to operate on. Optional when exactly one account is connected." }, "messageId": { "type": "string", "minLength": 1 }, "from": { "type": "string", "format": "email", "description": "Connected address or an available send-as address" }, "to": { "type": "array", "items": { "type": "string", "minLength": 1 }, "minItems": 1, "description": "Recipients, each \"Name \" or \"a@x.com\"" }, "cc": { "type": "array", "items": { "$ref": "#/properties/to/items" }, "description": "Recipients, each \"Name \" or \"a@x.com\"" }, "comment": { "type": "string", "description": "Comment above the forwarded message. Keep prose paragraphs on one continuous line and separate paragraphs with blank lines." }, "includeAttachments": { "type": "boolean", "description": "Default true" } }, "required": [ "idempotencyKey", "messageId", "to" ], "additionalProperties": false, "$schema": "http://json-schema.org/draft-07/schema#" } ```
--- # Get delivery operation URL: https://fluxmail.ai/docs/tools/get-delivery-operation `get_delivery_operation` Check whether a send or forward succeeded, failed, or has an uncertain outcome. ## Permissions [#permissions] Required capabilities: `mail.send`. ## Inputs [#inputs] | Name | Required | Type | Details | | ------------- | -------- | -------- | ------------------ | | `accountId` | Yes | `string` | Minimum length: 1. | | `operationId` | Yes | `string` | None |
JSON input schema ```json { "type": "object", "properties": { "accountId": { "type": "string", "minLength": 1 }, "operationId": { "$ref": "#/properties/accountId" } }, "required": [ "accountId", "operationId" ], "additionalProperties": false, "$schema": "http://json-schema.org/draft-07/schema#" } ```
--- # Get draft URL: https://fluxmail.ai/docs/tools/get-draft `get_draft` Read an existing draft by its draft ID. ## Permissions [#permissions] Required capabilities: `mail.drafts`. ## Inputs [#inputs] | Name | Required | Type | Details | | ----------- | -------- | -------- | ----------------------------------------------------------------------------------------- | | `accountId` | No | `string` | Account to operate on. Optional when exactly one account is connected. Minimum length: 1. | | `draftId` | Yes | `string` | Minimum length: 1. |
JSON input schema ```json { "type": "object", "properties": { "accountId": { "type": "string", "minLength": 1, "description": "Account to operate on. Optional when exactly one account is connected." }, "draftId": { "type": "string", "minLength": 1 } }, "required": [ "draftId" ], "additionalProperties": false, "$schema": "http://json-schema.org/draft-07/schema#" } ```
--- # Get email body URL: https://fluxmail.ai/docs/tools/get-email-body `get_email_body` Read a bounded portion of one email body. Use nextOffset to continue. ## Permissions [#permissions] Required capabilities: `mail.read`. ## Inputs [#inputs] | Name | Required | Type | Details | | ----------- | -------- | ---------------- | ----------------------------------------------------------------------------------------- | | `accountId` | No | `string` | Account to operate on. Optional when exactly one account is connected. Minimum length: 1. | | `messageId` | Yes | `string` | Minimum length: 1. | | `format` | Yes | `text` or `html` | None | | `offset` | No | `integer` | Minimum: 0. | | `maxChars` | No | `integer` | Minimum: 1. Maximum: 50000. |
JSON input schema ```json { "type": "object", "properties": { "accountId": { "type": "string", "minLength": 1, "description": "Account to operate on. Optional when exactly one account is connected." }, "messageId": { "type": "string", "minLength": 1 }, "format": { "type": "string", "enum": [ "text", "html" ] }, "offset": { "type": "integer", "minimum": 0 }, "maxChars": { "type": "integer", "minimum": 1, "maximum": 50000 } }, "required": [ "messageId", "format" ], "additionalProperties": false, "$schema": "http://json-schema.org/draft-07/schema#" } ```
--- # Get email URL: https://fluxmail.ai/docs/tools/get-email `get_email` Fetch one email in full: body (text and/or HTML), recipients, attachment metadata. ## Permissions [#permissions] Required capabilities: `mail.read`. ## Inputs [#inputs] | Name | Required | Type | Details | | ------------ | -------- | ------------------------------------ | ----------------------------------------------------------------------------------------- | | `accountId` | No | `string` | Account to operate on. Optional when exactly one account is connected. Minimum length: 1. | | `messageId` | Yes | `string` | Minimum length: 1. | | `bodyFormat` | No | `text` or `html` or `both` or `none` | None |
JSON input schema ```json { "type": "object", "properties": { "accountId": { "type": "string", "minLength": 1, "description": "Account to operate on. Optional when exactly one account is connected." }, "messageId": { "type": "string", "minLength": 1 }, "bodyFormat": { "type": "string", "enum": [ "text", "html", "both", "none" ] } }, "required": [ "messageId" ], "additionalProperties": false, "$schema": "http://json-schema.org/draft-07/schema#" } ```
--- # Get status URL: https://fluxmail.ai/docs/tools/get-status `get_status` Account connection and scheduled-send status. Administrators also see plan details. Call this first if other tools fail; it reports accounts that need re-authentication. ## Permissions [#permissions] Required capabilities: `mail.read`. ## Inputs [#inputs] This tool has no inputs.
JSON input schema ```json { "type": "object", "properties": {}, "$schema": "http://json-schema.org/draft-07/schema#" } ```
--- # Get thread URL: https://fluxmail.ai/docs/tools/get-thread `get_thread` Fetch a page of conversation messages with bounded body content. ## Permissions [#permissions] Required capabilities: `mail.read`. ## Inputs [#inputs] | Name | Required | Type | Details | | ------------ | -------- | ------------------------------------ | ----------------------------------------------------------------------------------------- | | `accountId` | No | `string` | Account to operate on. Optional when exactly one account is connected. Minimum length: 1. | | `threadId` | Yes | `string` | Minimum length: 1. | | `pageSize` | No | `integer` | Minimum: 1. Maximum: 25. | | `pageToken` | No | `string` | Minimum length: 1. | | `bodyFormat` | No | `text` or `html` or `both` or `none` | None |
JSON input schema ```json { "type": "object", "properties": { "accountId": { "type": "string", "minLength": 1, "description": "Account to operate on. Optional when exactly one account is connected." }, "threadId": { "type": "string", "minLength": 1 }, "pageSize": { "type": "integer", "minimum": 1, "maximum": 25 }, "pageToken": { "type": "string", "minLength": 1 }, "bodyFormat": { "type": "string", "enum": [ "text", "html", "both", "none" ] } }, "required": [ "threadId" ], "additionalProperties": false, "$schema": "http://json-schema.org/draft-07/schema#" } ```
--- # MCP tools URL: https://fluxmail.ai/docs/tools Fluxmail exposes MCP tools over Streamable HTTP and stdio. Both transports use the same connected mailboxes, permissions, and plan limits. ## Start locally [#start-locally] Complete the [Quickstart](/docs/quickstart), then create an API key and start the HTTP server: ```bash fluxmail apikey create \ --name local-mcp fluxmail serve ``` Copy the `fmk_...` key when Fluxmail displays it. The local MCP endpoint is `http://localhost:8977/mcp`. Pass the key as a bearer token when you configure your MCP client. For a local stdio connection, select a local instance where the CLI is logged in, then choose a permission profile: ```bash fluxmail stdio --profile full ``` See [Connect an MCP client](/docs/connect-an-mcp-client) for client-specific stdio and HTTP configuration. ## Tool permissions [#tool-permissions] The tools a client receives depend on its [permission profile](/docs/permissions). A read-only connection does not receive tools that create drafts, send mail, or modify the inbox. For HTTP connections, permissions belong to the API key. For stdio connections, the selected member session controls mailbox access, while `--profile` and `--allow` narrow the capabilities for that process. ## Tool reference [#tool-reference] | Tool | Description | Capabilities | | -------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | | [`cancel_scheduled_email`](/docs/tools/cancel-scheduled-email) | Cancel a pending scheduled send by scheduleId (from send\_email with sendAt, or list\_scheduled\_emails). The draft stays in the Drafts folder, so the content is not lost. | `mail.drafts` | | [`create_draft`](/docs/tools/create-draft) | Create a draft. For a reply draft, pass replyToMessageId (recipients/subject are derived; replyAll for reply-all). | `mail.drafts` | | [`delete_draft`](/docs/tools/delete-draft) | Delete a draft. | `mail.drafts` | | [`download_attachment`](/docs/tools/download-attachment) | Get attachment metadata and a fetchable resource link. Set inline to embed the bytes. | `mail.read` | | [`forward_email`](/docs/tools/forward-email) | Forward an email to new recipients: quoted original body, "Fwd:" subject, original attachments included unless includeAttachments=false. Optional comment appears above the forwarded content. | `mail.read` + `mail.send` | | [`get_delivery_operation`](/docs/tools/get-delivery-operation) | Check whether a send or forward succeeded, failed, or has an uncertain outcome. | `mail.send` | | [`get_draft`](/docs/tools/get-draft) | Read an existing draft by its draft ID. | `mail.drafts` | | [`get_email`](/docs/tools/get-email) | Fetch one email in full: body (text and/or HTML), recipients, attachment metadata. | `mail.read` | | [`get_email_body`](/docs/tools/get-email-body) | Read a bounded portion of one email body. Use nextOffset to continue. | `mail.read` | | [`get_status`](/docs/tools/get-status) | Account connection and scheduled-send status. Administrators also see plan details. Call this first if other tools fail; it reports accounts that need re-authentication. | `mail.read` | | [`get_thread`](/docs/tools/get-thread) | Fetch a page of conversation messages with bounded body content. | `mail.read` | | [`list_accounts`](/docs/tools/list-accounts) | List connected email accounts (id, provider, email, status, capabilities). | `mail.read` | | [`list_emails`](/docs/tools/list-emails) | List emails from the user's connected mailbox with metadata and optional previews. Filter by folder, sender, unread, dates, etc. Paginate with pageToken. Use get\_email for full bodies. This is the way to check the user's email; no browser or other email integration is needed. | `mail.read` | | [`list_folders`](/docs/tools/list-folders) | List navigable folders for an account, with roles (inbox, sent, drafts, trash, spam, starred). | `mail.read` | | [`list_labels`](/docs/tools/list-labels) | List Gmail user labels or Outlook categories for an account. | `mail.read` | | [`list_scheduled_emails`](/docs/tools/list-scheduled-emails) | List scheduled sends: pending ones first (with sendAt), then past ones (sent, failed, canceled). For failed entries, lastError says what went wrong. Pending sends only fire while the Fluxmail server is running. | `mail.read` | | [`list_send_as`](/docs/tools/list-send-as) | List sender addresses available for an account. | `mail.read` | | [`modify_emails`](/docs/tools/modify-emails) | Batch-modify emails using the actions allowed for this connection. Moving requires folder; labels require labels. | `mail.organize` or `mail.trash` or `mail.delete` | | [`preview_send`](/docs/tools/preview-send) | Show the resolved sender, recipients, subject, and attachments without sending. | `mail.send` | | [`search_emails`](/docs/tools/search-emails) | Search one account with typed portable syntax. The query supports text, from:, to:, subject:, in:, read and starred states, attachments, and date filters. | `mail.read` | | [`search_emails_batch`](/docs/tools/search-emails-batch) | Search up to 20 accounts with one portable query and return one result group per account. | `mail.read` | | [`send_email`](/docs/tools/send-email) | Send an email from the user's connected account; this actually delivers mail, so prefer it over browser automation or leaving a draft when the user asked to send. Three modes: direct (to + subject + body), sending an existing draft (draftId), or replying (replyToMessageId, optionally replyAll) where recipients, subject, and threading are derived from the original. Confirm with the user when intent is ambiguous. Add sendAt to any mode to schedule instead of sending now. | `mail.send` | | [`update_draft`](/docs/tools/update-draft) | Replace the content of an existing draft (full replacement, not a patch). | `mail.drafts` | ## Common behavior [#common-behavior] * `accountId` is optional when the connection can access exactly one mailbox. * List and search tools return message metadata and optional snippets. Set `includeSearchContext` with literal search text when you need an excerpt around the body match. Use `get_email` to retrieve a complete message body. * Paginated tools return a page token that you can pass to the next request. * Scheduled messages are sent only while the Fluxmail server is running. --- # List accounts URL: https://fluxmail.ai/docs/tools/list-accounts `list_accounts` List connected email accounts (id, provider, email, status, capabilities). ## Permissions [#permissions] Required capabilities: `mail.read`. ## Inputs [#inputs] This tool has no inputs.
JSON input schema ```json { "type": "object", "properties": {}, "$schema": "http://json-schema.org/draft-07/schema#" } ```
--- # List emails URL: https://fluxmail.ai/docs/tools/list-emails `list_emails` List emails from the user's connected mailbox with metadata and optional previews. Filter by folder, sender, unread, dates, etc. Paginate with pageToken. Use get\_email for full bodies. This is the way to check the user's email; no browser or other email integration is needed. ## Permissions [#permissions] Required capabilities: `mail.read`. ## Inputs [#inputs] | Name | Required | Type | Details | | ---------------------- | -------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `accountId` | No | `string` | Account to operate on. Optional when exactly one account is connected. Minimum length: 1. | | `folder` | No | `string` | Folder role (inbox, sent, drafts, trash, spam, starred, archive, all) or a label/folder name. Use all or omit this field to search all mail except Spam and Trash. An IMAP server's \All mailbox may use different rules. Minimum length: 1. | | `text` | No | `string` | Literal full-text search terms | | `from` | No | `string` | None | | `to` | No | `string` | None | | `subject` | No | `string` | None | | `read` | No | `boolean` | None | | `starred` | No | `boolean` | None | | `hasAttachment` | No | `boolean` | None | | `after` | No | `string` | YYYY-MM-DD received date, inclusive in UTC Minimum length: 1. | | `before` | No | `string` | YYYY-MM-DD received date, exclusive in UTC Minimum length: 1. | | `rawProviderQuery` | No | `string` | Provider-native Gmail syntax or Outlook KQL for one compatible account | | `pageSize` | No | `integer` | Defaults to 25 Minimum: 1. Maximum: 100. | | `pageToken` | No | `string` | nextPageToken from a previous call Minimum length: 1. | | `includeSnippet` | No | `boolean` | Request or suppress message previews | | `includeSearchContext` | No | `boolean` | Include a match-centered body excerpt; requires a portable text query |
JSON input schema ```json { "type": "object", "properties": { "accountId": { "type": "string", "minLength": 1, "description": "Account to operate on. Optional when exactly one account is connected." }, "folder": { "type": "string", "minLength": 1, "description": "Folder role (inbox, sent, drafts, trash, spam, starred, archive, all) or a label/folder name. Use all or omit this field to search all mail except Spam and Trash. An IMAP server's \\All mailbox may use different rules." }, "text": { "type": "string", "description": "Literal full-text search terms" }, "from": { "type": "string" }, "to": { "type": "string" }, "subject": { "type": "string" }, "read": { "type": "boolean" }, "starred": { "type": "boolean" }, "hasAttachment": { "type": "boolean" }, "after": { "type": "string", "minLength": 1, "description": "YYYY-MM-DD received date, inclusive in UTC" }, "before": { "type": "string", "minLength": 1, "description": "YYYY-MM-DD received date, exclusive in UTC" }, "rawProviderQuery": { "type": "string", "description": "Provider-native Gmail syntax or Outlook KQL for one compatible account" }, "pageSize": { "type": "integer", "minimum": 1, "maximum": 100, "description": "Defaults to 25" }, "pageToken": { "type": "string", "minLength": 1, "description": "nextPageToken from a previous call" }, "includeSnippet": { "type": "boolean", "description": "Request or suppress message previews" }, "includeSearchContext": { "type": "boolean", "description": "Include a match-centered body excerpt; requires a portable text query" } }, "additionalProperties": false, "$schema": "http://json-schema.org/draft-07/schema#" } ```
--- # List folders URL: https://fluxmail.ai/docs/tools/list-folders `list_folders` List navigable folders for an account, with roles (inbox, sent, drafts, trash, spam, starred). ## Permissions [#permissions] Required capabilities: `mail.read`. ## Inputs [#inputs] | Name | Required | Type | Details | | ----------- | -------- | -------- | ----------------------------------------------------------------------------------------- | | `accountId` | No | `string` | Account to operate on. Optional when exactly one account is connected. Minimum length: 1. |
JSON input schema ```json { "type": "object", "properties": { "accountId": { "type": "string", "minLength": 1, "description": "Account to operate on. Optional when exactly one account is connected." } }, "additionalProperties": false, "$schema": "http://json-schema.org/draft-07/schema#" } ```
--- # List labels URL: https://fluxmail.ai/docs/tools/list-labels `list_labels` List Gmail user labels or Outlook categories for an account. ## Permissions [#permissions] Required capabilities: `mail.read`. ## Inputs [#inputs] | Name | Required | Type | Details | | ----------- | -------- | -------- | ----------------------------------------------------------------------------------------- | | `accountId` | No | `string` | Account to operate on. Optional when exactly one account is connected. Minimum length: 1. |
JSON input schema ```json { "type": "object", "properties": { "accountId": { "type": "string", "minLength": 1, "description": "Account to operate on. Optional when exactly one account is connected." } }, "additionalProperties": false, "$schema": "http://json-schema.org/draft-07/schema#" } ```
--- # List scheduled emails URL: https://fluxmail.ai/docs/tools/list-scheduled-emails `list_scheduled_emails` List scheduled sends: pending ones first (with sendAt), then past ones (sent, failed, canceled). For failed entries, lastError says what went wrong. Pending sends only fire while the Fluxmail server is running. ## Permissions [#permissions] Required capabilities: `mail.read`. ## Inputs [#inputs] | Name | Required | Type | Details | | ----------- | -------- | -------- | ----------------------------------------------------------------------------------------- | | `accountId` | No | `string` | Account to operate on. Optional when exactly one account is connected. Minimum length: 1. |
JSON input schema ```json { "type": "object", "properties": { "accountId": { "type": "string", "minLength": 1, "description": "Account to operate on. Optional when exactly one account is connected." } }, "additionalProperties": false, "$schema": "http://json-schema.org/draft-07/schema#" } ```
--- # List send as URL: https://fluxmail.ai/docs/tools/list-send-as `list_send_as` List sender addresses available for an account. ## Permissions [#permissions] Required capabilities: `mail.read`. ## Inputs [#inputs] | Name | Required | Type | Details | | ----------- | -------- | -------- | ----------------------------------------------------------------------------------------- | | `accountId` | No | `string` | Account to operate on. Optional when exactly one account is connected. Minimum length: 1. |
JSON input schema ```json { "type": "object", "properties": { "accountId": { "type": "string", "minLength": 1, "description": "Account to operate on. Optional when exactly one account is connected." } }, "additionalProperties": false, "$schema": "http://json-schema.org/draft-07/schema#" } ```
--- # Modify emails URL: https://fluxmail.ai/docs/tools/modify-emails `modify_emails` Batch-modify emails using the actions allowed for this connection. Moving requires folder; labels require labels. ## Permissions [#permissions] Required capabilities: `mail.organize` or `mail.trash` or `mail.delete`. ## Inputs [#inputs] | Name | Required | Type | Details | | ------------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | | `accountId` | No | `string` | Account to operate on. Optional when exactly one account is connected. Minimum length: 1. | | `messageIds` | Yes | array of `string` | None | | `action` | Yes | `markRead` or `markUnread` or `star` or `unstar` or `archive` or `trash` or `untrash` or `delete` or `move` or `addLabels` or `removeLabels` | None | | `folder` | No | `string` | Target folder for action=move Minimum length: 1. | | `labels` | No | array of `string` | Labels for addLabels/removeLabels |
JSON input schema ```json { "type": "object", "properties": { "accountId": { "type": "string", "minLength": 1, "description": "Account to operate on. Optional when exactly one account is connected." }, "messageIds": { "type": "array", "items": { "type": "string", "minLength": 1 }, "minItems": 1 }, "action": { "type": "string", "enum": [ "markRead", "markUnread", "star", "unstar", "archive", "trash", "untrash", "delete", "move", "addLabels", "removeLabels" ] }, "folder": { "type": "string", "minLength": 1, "description": "Target folder for action=move" }, "labels": { "type": "array", "items": { "type": "string", "minLength": 1 }, "maxItems": 100, "description": "Labels for addLabels/removeLabels" } }, "required": [ "messageIds", "action" ], "additionalProperties": false, "$schema": "http://json-schema.org/draft-07/schema#" } ```
--- # Preview send URL: https://fluxmail.ai/docs/tools/preview-send `preview_send` Show the resolved sender, recipients, subject, and attachments without sending. ## Permissions [#permissions] Required capabilities: `mail.send`. ## Inputs [#inputs] | Name | Required | Type | Details | | ------------------ | -------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `draftId` | No | `string` | Minimum length: 1. | | `accountId` | No | `string` | Account to operate on. Optional when exactly one account is connected. Minimum length: 1. | | `from` | No | `string` | Connected address or an available send-as address Format: `email`. | | `to` | No | array of `string` | Recipients, each "Name [a@x.com](mailto:a@x.com)" or "[a@x.com](mailto:a@x.com)" | | `cc` | No | array of `string` | Recipients, each "Name [a@x.com](mailto:a@x.com)" or "[a@x.com](mailto:a@x.com)" | | `bcc` | No | array of `string` | Recipients, each "Name [a@x.com](mailto:a@x.com)" or "[a@x.com](mailto:a@x.com)" | | `subject` | No | `string` | Defaults to "Re: ..." when replying | | `bodyText` | No | `string` | Plain-text body. Line breaks appear in the sent email. Keep each prose paragraph on one continuous line and separate paragraphs with blank lines. | | `bodyHtml` | No | `string` | HTML body | | `replyToMessageId` | No | `string` | Message being replied to; threads correctly and computes recipients if "to" is omitted | | `replyAll` | No | `boolean` | With replyToMessageId: reply to all original recipients | | `attachments` | No | array of `object` | None |
JSON input schema ```json { "type": "object", "properties": { "draftId": { "type": "string", "minLength": 1 }, "accountId": { "type": "string", "minLength": 1, "description": "Account to operate on. Optional when exactly one account is connected." }, "from": { "type": "string", "format": "email", "description": "Connected address or an available send-as address" }, "to": { "type": "array", "items": { "type": "string", "minLength": 1 }, "description": "Recipients, each \"Name \" or \"a@x.com\"" }, "cc": { "$ref": "#/properties/to", "description": "Recipients, each \"Name \" or \"a@x.com\"" }, "bcc": { "$ref": "#/properties/to", "description": "Recipients, each \"Name \" or \"a@x.com\"" }, "subject": { "type": "string", "description": "Defaults to \"Re: ...\" when replying" }, "bodyText": { "type": "string", "description": "Plain-text body. Line breaks appear in the sent email. Keep each prose paragraph on one continuous line and separate paragraphs with blank lines." }, "bodyHtml": { "type": "string", "description": "HTML body" }, "replyToMessageId": { "$ref": "#/properties/draftId", "description": "Message being replied to; threads correctly and computes recipients if \"to\" is omitted" }, "replyAll": { "type": "boolean", "description": "With replyToMessageId: reply to all original recipients" }, "attachments": { "type": "array", "items": { "type": "object", "properties": { "filename": { "type": "string", "minLength": 1 }, "mimeType": { "type": "string", "minLength": 1 }, "content": { "type": "string", "description": "base64" } }, "required": [ "filename", "mimeType", "content" ], "additionalProperties": false } } }, "additionalProperties": false, "$schema": "http://json-schema.org/draft-07/schema#" } ```
--- # Search emails batch URL: https://fluxmail.ai/docs/tools/search-emails-batch `search_emails_batch` Search up to 20 accounts with one portable query and return one result group per account. ## Permissions [#permissions] Required capabilities: `mail.read`. ## Inputs [#inputs] | Name | Required | Type | Details | | ---------------------- | -------- | ------------------------------------------------------------------------ | --------------------------------------------------------------------- | | `accounts` | Yes | array of `object` | None | | `query` | Yes | `string` | Typed portable search syntax Minimum length: 1. | | `folder` | No | `inbox` or `sent` or `drafts` or `archive` or `spam` or `trash` or `all` | None | | `from` | No | `string` | None | | `to` | No | `string` | None | | `subject` | No | `string` | None | | `read` | No | `boolean` | None | | `starred` | No | `boolean` | None | | `hasAttachment` | No | `boolean` | None | | `after` | No | `string` | YYYY-MM-DD received date, inclusive in UTC Minimum length: 1. | | `before` | No | `string` | YYYY-MM-DD received date, exclusive in UTC Minimum length: 1. | | `pageSize` | No | `integer` | Defaults to 25 Minimum: 1. Maximum: 100. | | `includeSnippet` | No | `boolean` | Request or suppress message previews | | `includeSearchContext` | No | `boolean` | Include a match-centered body excerpt; requires a portable text query |
JSON input schema ```json { "type": "object", "properties": { "accounts": { "type": "array", "items": { "type": "object", "properties": { "accountId": { "type": "string", "minLength": 1 }, "pageToken": { "type": "string", "minLength": 1 } }, "required": [ "accountId" ], "additionalProperties": false }, "minItems": 1, "maxItems": 20 }, "query": { "type": "string", "minLength": 1, "description": "Typed portable search syntax" }, "folder": { "type": "string", "enum": [ "inbox", "sent", "drafts", "archive", "spam", "trash", "all" ] }, "from": { "type": "string" }, "to": { "type": "string" }, "subject": { "type": "string" }, "read": { "type": "boolean" }, "starred": { "type": "boolean" }, "hasAttachment": { "type": "boolean" }, "after": { "type": "string", "minLength": 1, "description": "YYYY-MM-DD received date, inclusive in UTC" }, "before": { "type": "string", "minLength": 1, "description": "YYYY-MM-DD received date, exclusive in UTC" }, "pageSize": { "type": "integer", "minimum": 1, "maximum": 100, "description": "Defaults to 25" }, "includeSnippet": { "type": "boolean", "description": "Request or suppress message previews" }, "includeSearchContext": { "type": "boolean", "description": "Include a match-centered body excerpt; requires a portable text query" } }, "required": [ "accounts", "query" ], "additionalProperties": false, "$schema": "http://json-schema.org/draft-07/schema#" } ```
--- # Search emails URL: https://fluxmail.ai/docs/tools/search-emails `search_emails` Search one account with typed portable syntax. The query supports text, from:, to:, subject:, in:, read and starred states, attachments, and date filters. ## Permissions [#permissions] Required capabilities: `mail.read`. ## Inputs [#inputs] | Name | Required | Type | Details | | ---------------------- | -------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `accountId` | No | `string` | Account to operate on. Optional when exactly one account is connected. Minimum length: 1. | | `query` | Yes | `string` | Typed portable search syntax Minimum length: 1. | | `folder` | No | `string` | Folder role (inbox, sent, drafts, trash, spam, starred, archive, all) or a label/folder name. Use all or omit this field to search all mail except Spam and Trash. An IMAP server's \All mailbox may use different rules. Minimum length: 1. | | `from` | No | `string` | None | | `to` | No | `string` | None | | `subject` | No | `string` | None | | `read` | No | `boolean` | None | | `starred` | No | `boolean` | None | | `hasAttachment` | No | `boolean` | None | | `after` | No | `string` | YYYY-MM-DD received date, inclusive in UTC Minimum length: 1. | | `before` | No | `string` | YYYY-MM-DD received date, exclusive in UTC Minimum length: 1. | | `rawProviderQuery` | No | `string` | Provider-native Gmail syntax or Outlook KQL for one compatible account | | `pageSize` | No | `integer` | Defaults to 25 Minimum: 1. Maximum: 100. | | `pageToken` | No | `string` | nextPageToken from a previous call Minimum length: 1. | | `includeSnippet` | No | `boolean` | Request or suppress message previews | | `includeSearchContext` | No | `boolean` | Include a match-centered body excerpt; requires a portable text query |
JSON input schema ```json { "type": "object", "properties": { "accountId": { "type": "string", "minLength": 1, "description": "Account to operate on. Optional when exactly one account is connected." }, "query": { "type": "string", "minLength": 1, "description": "Typed portable search syntax" }, "folder": { "type": "string", "minLength": 1, "description": "Folder role (inbox, sent, drafts, trash, spam, starred, archive, all) or a label/folder name. Use all or omit this field to search all mail except Spam and Trash. An IMAP server's \\All mailbox may use different rules." }, "from": { "type": "string" }, "to": { "type": "string" }, "subject": { "type": "string" }, "read": { "type": "boolean" }, "starred": { "type": "boolean" }, "hasAttachment": { "type": "boolean" }, "after": { "type": "string", "minLength": 1, "description": "YYYY-MM-DD received date, inclusive in UTC" }, "before": { "type": "string", "minLength": 1, "description": "YYYY-MM-DD received date, exclusive in UTC" }, "rawProviderQuery": { "type": "string", "description": "Provider-native Gmail syntax or Outlook KQL for one compatible account" }, "pageSize": { "type": "integer", "minimum": 1, "maximum": 100, "description": "Defaults to 25" }, "pageToken": { "type": "string", "minLength": 1, "description": "nextPageToken from a previous call" }, "includeSnippet": { "type": "boolean", "description": "Request or suppress message previews" }, "includeSearchContext": { "type": "boolean", "description": "Include a match-centered body excerpt; requires a portable text query" } }, "required": [ "query" ], "additionalProperties": false, "$schema": "http://json-schema.org/draft-07/schema#" } ```
--- # Send email URL: https://fluxmail.ai/docs/tools/send-email `send_email` Send an email from the user's connected account; this actually delivers mail, so prefer it over browser automation or leaving a draft when the user asked to send. Three modes: direct (to + subject + body), sending an existing draft (draftId), or replying (replyToMessageId, optionally replyAll) where recipients, subject, and threading are derived from the original. Confirm with the user when intent is ambiguous. Add sendAt to any mode to schedule instead of sending now. ## Permissions [#permissions] Required capabilities: `mail.send`. ## Inputs [#inputs] | Name | Required | Type | Details | | ------------------ | -------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `idempotencyKey` | Yes | `string` | Reuse this key when retrying the same delivery | | `draftId` | No | `string` | Send this existing draft Minimum length: 1. | | `accountId` | No | `string` | Account to operate on. Optional when exactly one account is connected. Minimum length: 1. | | `from` | No | `string` | Connected address or an available send-as address Format: `email`. | | `to` | No | array of `string` | Recipients, each "Name [a@x.com](mailto:a@x.com)" or "[a@x.com](mailto:a@x.com)" | | `cc` | No | array of `string` | Recipients, each "Name [a@x.com](mailto:a@x.com)" or "[a@x.com](mailto:a@x.com)" | | `bcc` | No | array of `string` | Recipients, each "Name [a@x.com](mailto:a@x.com)" or "[a@x.com](mailto:a@x.com)" | | `subject` | No | `string` | Defaults to "Re: ..." when replying | | `bodyText` | No | `string` | Plain-text body. Line breaks appear in the sent email. Keep each prose paragraph on one continuous line and separate paragraphs with blank lines. | | `bodyHtml` | No | `string` | HTML body | | `replyToMessageId` | No | `string` | Message being replied to; threads correctly and computes recipients if "to" is omitted | | `replyAll` | No | `boolean` | With replyToMessageId: reply to all original recipients | | `attachments` | No | array of `object` | None | | `sendAt` | No | `string` | Schedule delivery instead of sending now: ISO 8601 with timezone offset or Z (e.g. 2026-07-11T09:00:00-07:00). Fluxmail saves the message as a real draft in the mailbox and sends it at this time; the server must be running then (anything missed while it was down goes out at the next startup). Returns a scheduleId for list/cancel. Format: `date-time`. |
JSON input schema ```json { "type": "object", "properties": { "idempotencyKey": { "type": "string", "pattern": "^[\\x21-\\x7e]{1,255}$", "description": "Reuse this key when retrying the same delivery" }, "draftId": { "type": "string", "minLength": 1, "description": "Send this existing draft" }, "accountId": { "type": "string", "minLength": 1, "description": "Account to operate on. Optional when exactly one account is connected." }, "from": { "type": "string", "format": "email", "description": "Connected address or an available send-as address" }, "to": { "type": "array", "items": { "type": "string", "minLength": 1 }, "description": "Recipients, each \"Name \" or \"a@x.com\"" }, "cc": { "$ref": "#/properties/to", "description": "Recipients, each \"Name \" or \"a@x.com\"" }, "bcc": { "$ref": "#/properties/to", "description": "Recipients, each \"Name \" or \"a@x.com\"" }, "subject": { "type": "string", "description": "Defaults to \"Re: ...\" when replying" }, "bodyText": { "type": "string", "description": "Plain-text body. Line breaks appear in the sent email. Keep each prose paragraph on one continuous line and separate paragraphs with blank lines." }, "bodyHtml": { "type": "string", "description": "HTML body" }, "replyToMessageId": { "$ref": "#/properties/draftId", "description": "Message being replied to; threads correctly and computes recipients if \"to\" is omitted" }, "replyAll": { "type": "boolean", "description": "With replyToMessageId: reply to all original recipients" }, "attachments": { "type": "array", "items": { "type": "object", "properties": { "filename": { "type": "string", "minLength": 1 }, "mimeType": { "type": "string", "minLength": 1 }, "content": { "type": "string", "description": "base64" } }, "required": [ "filename", "mimeType", "content" ], "additionalProperties": false } }, "sendAt": { "type": "string", "format": "date-time", "description": "Schedule delivery instead of sending now: ISO 8601 with timezone offset or Z (e.g. 2026-07-11T09:00:00-07:00). Fluxmail saves the message as a real draft in the mailbox and sends it at this time; the server must be running then (anything missed while it was down goes out at the next startup). Returns a scheduleId for list/cancel." } }, "required": [ "idempotencyKey" ], "additionalProperties": false, "$schema": "http://json-schema.org/draft-07/schema#" } ```
--- # Update draft URL: https://fluxmail.ai/docs/tools/update-draft `update_draft` Replace the content of an existing draft (full replacement, not a patch). ## Permissions [#permissions] Required capabilities: `mail.drafts`. ## Inputs [#inputs] | Name | Required | Type | Details | | ------------------ | -------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `draftId` | Yes | `string` | Minimum length: 1. | | `accountId` | No | `string` | Account to operate on. Optional when exactly one account is connected. Minimum length: 1. | | `from` | No | `string` | Connected address or an available send-as address Format: `email`. | | `to` | No | array of `string` | Recipients, each "Name [a@x.com](mailto:a@x.com)" or "[a@x.com](mailto:a@x.com)" | | `cc` | No | array of `string` | Recipients, each "Name [a@x.com](mailto:a@x.com)" or "[a@x.com](mailto:a@x.com)" | | `bcc` | No | array of `string` | Recipients, each "Name [a@x.com](mailto:a@x.com)" or "[a@x.com](mailto:a@x.com)" | | `subject` | No | `string` | Defaults to "Re: ..." when replying | | `bodyText` | No | `string` | Plain-text body. Line breaks appear in the sent email. Keep each prose paragraph on one continuous line and separate paragraphs with blank lines. | | `bodyHtml` | No | `string` | HTML body | | `replyToMessageId` | No | `string` | Message being replied to; threads correctly and computes recipients if "to" is omitted | | `replyAll` | No | `boolean` | With replyToMessageId: reply to all original recipients | | `attachments` | No | array of `object` | None |
JSON input schema ```json { "type": "object", "properties": { "draftId": { "type": "string", "minLength": 1 }, "accountId": { "type": "string", "minLength": 1, "description": "Account to operate on. Optional when exactly one account is connected." }, "from": { "type": "string", "format": "email", "description": "Connected address or an available send-as address" }, "to": { "type": "array", "items": { "type": "string", "minLength": 1 }, "description": "Recipients, each \"Name \" or \"a@x.com\"" }, "cc": { "$ref": "#/properties/to", "description": "Recipients, each \"Name \" or \"a@x.com\"" }, "bcc": { "$ref": "#/properties/to", "description": "Recipients, each \"Name \" or \"a@x.com\"" }, "subject": { "type": "string", "description": "Defaults to \"Re: ...\" when replying" }, "bodyText": { "type": "string", "description": "Plain-text body. Line breaks appear in the sent email. Keep each prose paragraph on one continuous line and separate paragraphs with blank lines." }, "bodyHtml": { "type": "string", "description": "HTML body" }, "replyToMessageId": { "$ref": "#/properties/draftId", "description": "Message being replied to; threads correctly and computes recipients if \"to\" is omitted" }, "replyAll": { "type": "boolean", "description": "With replyToMessageId: reply to all original recipients" }, "attachments": { "type": "array", "items": { "type": "object", "properties": { "filename": { "type": "string", "minLength": 1 }, "mimeType": { "type": "string", "minLength": 1 }, "content": { "type": "string", "description": "base64" } }, "required": [ "filename", "mimeType", "content" ], "additionalProperties": false } } }, "required": [ "draftId" ], "additionalProperties": false, "$schema": "http://json-schema.org/draft-07/schema#" } ```
--- # Upgrade to 0.11.0 URL: https://fluxmail.ai/docs/upgrades/0.11.0 This release changes the response shapes for sends, forwards, and bulk message actions. Update clients before upgrading a production instance. | Interface | Client changes | | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | MCP | Add `idempotencyKey` to sends and forwards; read delivery operations and per-message bulk results; follow thread and body continuations; request inline attachment bytes when needed. | | CLI | Add `--idempotency-key` to sends and forwards; read delivery operations and per-message bulk results; parse the default JSON envelope and handle the new exit codes. | | REST | Keep `Idempotency-Key` on sends and forwards; read delivery operations and per-message bulk results. Existing keys may return the old send response during their remaining 24 hour lifetime. | Apply only the row for each interface your clients use. Back up existing installations as described below. ## Back up the data directory [#back-up-the-data-directory] Stop every Fluxmail process that shares the data directory and back up the complete directory, including the SQLite database and `encryption.key`. The first new process advances the store from format 3 to format 5 and writes a migration backup. Older releases cannot open the migrated store. To roll back, stop Fluxmail and restore the complete backup. ## Update send and forward clients [#update-send-and-forward-clients] REST still requires `Idempotency-Key`. MCP `send_email` and `forward_email` now require `idempotencyKey`. CLI `emails send` and `emails forward` now require `--idempotency-key`. Generate a stable key for each intended delivery and save it with the request. Reuse that key if the result is lost. New delivery operation keys have no automatic expiry. Keep each key with its intended request so a later retry cannot send a duplicate. Reusing the key with different request data returns a conflict. All three interfaces return a delivery operation instead of a sent message. Read `operationId` and `status`; the sent message ID is in `result.id` after success. A scheduled request starts at `queued`. Use REST `GET /accounts/{accountId}/delivery-operations/{operationId}`, MCP `get_delivery_operation`, or CLI `emails delivery-status` to check it. A `failed` result was rejected. An `uncertain` result may already have been delivered and is never retried automatically. Check the sent folder or recipient before creating another delivery request. Status lookups work across a member's sessions and API keys when that member can access the account. Scheduled delivery status is available to anyone with access to the account. Existing REST idempotency records remain available for their original 24 hour life. A retry during that period gets the old response shape. Handle that response during the transition, then remove the compatibility branch after old keys expire. ## Update bulk actions [#update-bulk-actions] The `modified` count is gone. Read `succeededIds`, `failed`, and `uncertainIds` instead. Each `failed` entry has a `messageId` and safe `code`. Requests may contain at most 100 distinct IDs. Fluxmail processes independent messages after a failure, so check every result before retrying. Inspect uncertain messages first. ## Update MCP and CLI clients [#update-mcp-and-cli-clients] MCP tools provide `structuredContent.data` alongside readable text. Message bodies can be selected with `bodyFormat`; large bodies are truncated with continuation information. Use `get_email_body` to continue. `get_thread` pages messages. Attachment downloads provide a resource link unless you request inline content. The CLI defaults to a JSON envelope. Use `--format table` or `--format ndjson` when needed. Scripts that read the old account, status, or mail text output need to parse `data` instead. Management commands wrap their displayed lines in `data`; interactive setup and connection flows still print prompts directly. JSON and NDJSON errors are JSON on stderr. Exit codes are `0` for success, `2` for input errors, `3` for partial or uncertain results, `4` for access errors, `5` for provider or network errors, and `1` for internal or uncategorized errors. `emails list --all` and `emails search --all` follow pages up to 1,000 results by default; `--max-results` can raise the limit to 10,000. Drafts can be fetched with `get_draft`, `drafts get`, or REST `GET /drafts/{draftId}`. A send preview resolves sender and recipients without delivery. Draft updates still replace the full draft. Partial edits are withheld until a provider revision check can be proven to reject concurrent external edits. --- # Upgrade from 0.4 to 0.5 URL: https://fluxmail.ai/docs/upgrades/0.5.0 Use this guide when upgrading an existing Fluxmail 0.4.x installation to 0.5.0. New installations do not need these steps. ## Before upgrading [#before-upgrading] Back up the complete Fluxmail data directory before installing 0.5.0. The default directory is `~/.fluxmail` for a local installation and `/data` in the Docker image. The upgrade performs a breaking SQLite migration. An older Fluxmail binary cannot use the migrated database, so the backup is required if you need to roll back. ## What the migration keeps [#what-the-migration-keeps] Fluxmail preserves member IDs and roles, mailbox messages and provider state, encrypted provider credentials, existing mailbox owners, selected member grants, and share-with-all behavior. The old sharing modes map to the current fields as follows: | Previous setting | Current setting | | ---------------- | ----------------------------------------------------------- | | Private | `sharedWithAll = false`, with no explicit grants | | Selected members | `sharedWithAll = false`, with the selected grants preserved | | All members | `sharedWithAll = true` | Mailboxes without a real owner remain unavailable to authenticated clients until the local administrator claim. The claim assigns those mailboxes to the chosen administrator. Mailboxes already owned by another member keep that owner. ## What the migration changes [#what-the-migration-changes] All existing members become pending because old member records do not have password credentials. Every legacy API key is revoked. Fluxmail does not convert memberless or implicitly trusted credentials. Authenticated MCP and REST access remains blocked until one existing administrator claims the instance. Health checks and the server process remain available during this step. `FLUXMAIL_AUTH=none` is no longer supported. ## Claim the instance [#claim-the-instance] Run setup on the instance host: ```bash fluxmail setup --existing-admin --email admin@example.com ``` Use an existing administrator ID or email. Supply `--email` when the legacy record has no login email. Fluxmail asks for a new password, activates that administrator, assigns ownerless mailboxes, creates the `local` CLI profile, and logs it in. If you do not know the administrator ID, run `fluxmail setup` once. The error lists the existing administrators that can be claimed. It does not modify the database. ## Enroll the remaining members [#enroll-the-remaining-members] The claimed administrator issues new enrollment codes: ```bash fluxmail members list fluxmail members invite ``` Each member enrolls from their own CLI: ```bash fluxmail --instance work login --server https://mail.example.com --enroll ``` Enrollment codes last seven days and work once. Members use their email and password for later logins. ## Replace API keys [#replace-api-keys] Create new keys after the owner has enrolled: ```bash fluxmail apikey create --name agent --profile read-only ``` Each key now has an explicit member owner and capability policy. An optional mailbox allowlist can only narrow the owner's current mailbox access. Recreate administrative keys with the specific `admin.*` capabilities they need. ## Verify the upgrade [#verify-the-upgrade] Confirm that the administrator can log in, each mailbox has the intended owner and grants, and newly created API keys can reach only their allowed mailboxes. Keep the backup until these checks pass. ## Recovery and rollback [#recovery-and-rollback] Use `fluxmail auth recover-admin ` on the instance host if the claimed administrator loses access. The command resets that administrator's password and revokes their sessions. To return to Fluxmail 0.4.x, stop Fluxmail and restore the complete data-directory backup. Do not open the migrated database with an older binary. --- # Upgrade to 0.6.0 URL: https://fluxmail.ai/docs/upgrades/0.6.0 Fluxmail 0.6.0 separates restart-bound deployment configuration from OAuth and license settings that can change while the server runs. ## Before upgrading [#before-upgrading] Back up the Fluxmail data directory, including the SQLite database and `encryption.key`. Fluxmail also creates a database backup before advancing the store to format 2. Older Fluxmail releases cannot open format 2. Stop every process that shares the data directory before upgrading. Do not start the 0.6.0 server until you import the old configuration. ## Migrate config.env [#migrate-configenv] Fluxmail 0.6.0 does not read `config.env`. Use the new binary to import the file manually. If the file sets `FLUXMAIL_DATA_DIR`, Fluxmail uses that directory as the migration target. Otherwise, run the command with the same `FLUXMAIL_DATA_DIR` used by the old installation: ```bash fluxmail config migrate --from /absolute/path/to/data-dir/config.env --dry-run fluxmail config migrate --from /absolute/path/to/data-dir/config.env fluxmail config show fluxmail oauth status ``` The import moves deployment settings to `config.toml` and stores custom OAuth applications and the license key as encrypted SQLite records. It does not delete `config.env`. Remove that file after you verify the imported settings. If the target database contains encrypted values, the migration requires its existing encryption key. Provide the key through the migration file, `FLUXMAIL_ENCRYPTION_KEY`, or `FLUXMAIL_ENCRYPTION_KEY_FILE`. Fluxmail does not replace a missing or mismatched key. ## Command changes [#command-changes] The generic `fluxmail config set`, `unset`, and `list` commands have been replaced: ```bash fluxmail config init fluxmail config show fluxmail oauth status fluxmail oauth configure google --client-id fluxmail oauth configure outlook --client-id --public-client fluxmail oauth reset ``` `fluxmail license activate` now prompts for the key. Automation can use `--key-file `. The positional key remains available for this release with a deprecation warning. ## Environment compatibility [#environment-compatibility] Existing environment variable names still work. Secret variables also support `_FILE` forms. A provider controlled by environment overrides cannot be changed through the CLI or REST API until the complete override group is removed and Fluxmail restarts. Fluxmail no longer reads `.env.local` or `.env` from the working directory. Import a file explicitly if it contains settings that should move into Fluxmail: ```bash fluxmail config migrate --from /absolute/path/to/old.env --dry-run fluxmail config migrate --from /absolute/path/to/old.env ``` The command preserves the source file. Remove the imported Fluxmail settings from it after checking the result. Docker Compose and process-manager env files still work because they set the process environment before Fluxmail starts. ## Package API changes [#package-api-changes] The public `config.env` read, write, mask, and dotenv mutation helpers have been removed. Packages should use the typed deployment resolver and `ConfigurationService`. `createContext()` keeps the same call signature and now exposes the service as `context.configuration`; `context.config` remains the current effective snapshot. --- # Upgrade to 0.7.0 URL: https://fluxmail.ai/docs/upgrades/0.7.0 Fluxmail 0.7.0 gives the CLI, MCP, REST API, and email providers the same portable search contract. Existing mailbox data and credentials do not need a database migration, but search clients and custom providers must update before upgrading. ## Find your migration [#find-your-migration] Only follow the rows for interfaces you use. If you do not call search from scripts or custom clients, you do not need to migrate mailbox data, configuration, or credentials. | Interface | Required changes | | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | CLI | Replace `--unread-only` with `--read false`, replace `--starred-only` with `--starred true`, pass a boolean to `--has-attachment`, and use typed syntax for `emails search`. | | MCP | Replace the `unreadOnly` and `starredOnly` arguments with `read` and `starred`. Convert `after` and `before` timestamps to `YYYY-MM-DD` calendar dates. Treat `list_emails.text` as literal text and use typed syntax for `search_emails.query`. | | REST | Replace the `unreadOnly` and `starredOnly` query parameters with `read` and `starred`. Treat `text` as literal text. The new `query` parameter accepts typed syntax. | | Custom providers | Handle `EmailQuery.read` and `EmailQuery.starred` instead of `unreadOnly` and `starredOnly`. Add `Capabilities.search` and advertise both values for each supported boolean filter. | Clients that paginate through any of these interfaces must discard tokens issued before 0.7.0 and restart without a token. ## Query changes [#query-changes] Replace `unreadOnly` with `read` and replace `starredOnly` with `starred`. The new fields accept both boolean values: ```json { "read": false, "starred": true, "hasAttachment": false } ``` `hasAttachment` is also a true tri-state filter. An omitted value does not filter messages, `true` requires a non-inline attachment, and `false` excludes messages with a non-inline attachment. The `text` field is now literal. Gmail and Outlook operators inside `text` no longer reach the provider as operators. Move Gmail search syntax or Outlook KQL to `rawProviderQuery`. Dates now require `YYYY-MM-DD`. Fluxmail treats `after` as inclusive and `before` as exclusive UTC boundaries over the received or provider internal time. A query fails when `after` is not earlier than `before`. ## CLI and MCP search strings [#cli-and-mcp-search-strings] The positional value for `fluxmail emails search` and the MCP `search_emails.query` field now use typed portable syntax: ```text from:ann@example.com is:unread after:2026-07-01 quarterly report ``` See [Email search](/docs/email-search) for the grammar. Use `rawProviderQuery` through a structured list request when an integration needs Gmail or Outlook syntax. The CLI search flags now accept explicit boolean values: ```bash fluxmail emails list --read false --starred true --has-attachment false ``` ## Capability changes for custom providers [#capability-changes-for-custom-providers] `Capabilities` has a required `search` field. It lists portable filters, folder-role availability, and native query support. `serverSearch` remains deprecated throughout 0.7.x so clients have time to migrate. Custom providers must implement both values of every boolean filter they advertise. Omit a filter from `search.filters` when the provider cannot implement both values correctly. Fluxmail returns `unsupported_capability` without running the search when an account reports that a filter or native query is unavailable. Capabilities marked `unknown` are checked when the request runs. Custom folders do not participate in portable capability intersection. Discover them on the selected account with `listFolders()`. ## Page tokens [#page-tokens] All page tokens issued before 0.7.0 are invalid immediately. Start each paginated search again without a token. New tokens are signed by the Fluxmail server and expire after one hour. A continuation request must use the same account, normalized query, and page size. Replacing the instance encryption key invalidates outstanding tokens. ## Custom clients [#custom-clients] Custom clients should send typed searches through the REST `query` parameter or MCP `search_emails.query`. Do not import Fluxmail's internal packages directly. Remove autocomplete entries for unsupported boolean expressions and relative dates. Keep provider-native queries limited to one account. An incomplete page may be empty even when more candidates exist. Follow a small number of empty incomplete pages automatically, then let the person choose whether to continue. --- # Upgrade to 0.9.0 URL: https://fluxmail.ai/docs/upgrades/0.9.0 Fluxmail 0.9.0 adds send-as addresses and multi-account search. Existing installations advance to store format 3, and custom providers must report when a search has examined its full scope. ## Find your migration [#find-your-migration] Only follow the rows for the surfaces you use. | Surface | Required changes | | ------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | | Stored data | Stop every Fluxmail process that shares the data directory, back up the directory, and keep the migration backup if you may need to roll back. | | Custom providers | Return `MessageSearchPage` from `EmailProvider.listMessages()` and set its required `exhausted` field. | | MCP, CLI, and REST clients | No migration is required. Search responses now include `exhausted`, and existing 0.8.1 page tokens remain valid until their normal one-hour expiry. | | Built-in Gmail, Outlook, and IMAP providers | No provider code change is required. | ## Prepare stored data [#prepare-stored-data] Stop every Fluxmail process that uses the data directory. Back up the complete directory, including the SQLite database and `encryption.key`, before installing 0.9.0. The first 0.9.0 process to open the database creates the send-as table and advances the store from format 2 to format 3. Fluxmail also writes a database backup to the `backups` directory before the migration. The migration keeps existing accounts, credentials, messages, members, configuration, and license data. Fluxmail 0.8.x cannot open a format 3 store. To roll back, stop Fluxmail and restore the complete data-directory backup. Do not open the migrated database with an older release. ## Update custom providers [#update-custom-providers] `EmailProvider.listMessages()` now returns `MessageSearchPage` instead of `Page`. Every result must include `exhausted`: ```ts import type { EmailQuery, MessageSearchPage, PageOpts } from '@fluxmail/core'; async function listMessages(query: EmailQuery, page?: PageOpts): Promise { const result = await searchMailbox(query, page); const response = { items: result.items, ...(result.nextPageToken ? { nextPageToken: result.nextPageToken } : {}), }; if (result.providerLimited) { return { ...response, exhausted: false, incomplete: true, incompleteReason: 'provider_limit', }; } return { ...response, exhausted: result.fullScopeExamined, }; } ``` Set `exhausted` from whether the provider examined the full requested scope, not from whether it returned a continuation token. Return `false` when a continuation token exists or when a provider limit prevents a complete search. A capped result must remain `false` even when the provider does not return a token. `PageOpts` also has optional `includeSnippet`, `signal`, and `softDeadlineAt` fields. A custom provider can ignore `includeSnippet` when it has no preview support. Honor the abort signal and soft deadline when possible so searches stop promptly and return a continuation at a safe boundary. The optional `EmailProvider.listSendAs()` method does not require a custom provider change. Implement it only when the provider can discover send-as identities. ## Check search clients [#check-search-clients] MCP, CLI, and REST request fields remain compatible. Search pages now include `exhausted`, which is `true` only when Fluxmail has examined the full requested scope. Clients that validate response objects against a closed schema should allow this field. Existing 0.8.1 search page tokens remain valid with the same account, query, page size, instance encryption key, and snippet setting. New tokens still expire after one hour. --- # fluxmail accounts access URL: https://fluxmail.ai/docs/cli/accounts-access `fluxmail accounts access` Set who can access a mailbox ## Usage [#usage] ```bash fluxmail accounts access [options] ``` ## Arguments [#arguments] | Name | Required | Details | Default | | ----------- | -------- | ------- | ------- | | `accountId` | Yes | None | None | ## Options [#options] | Option | Required | Details | Default | | ----------------------- | -------- | ---------------------------------------------------------- | ------- | | `--owner-only` | No | Only the owner can access the mailbox | None | | `--shared` | No | Share the mailbox with every member | None | | `--share-with ` | No | Replace selected access with this member; repeat as needed | None | --- # fluxmail accounts add URL: https://fluxmail.ai/docs/cli/accounts-add `fluxmail accounts add` Connect a Gmail, Outlook, or IMAP account ## Usage [#usage] ```bash fluxmail accounts add [options] ``` ## Arguments [#arguments] | Name | Required | Details | Default | | ---------- | -------- | --------------------------------------- | ------- | | `provider` | Yes | Email provider: gmail, outlook, or imap | None | ## Options [#options] | Option | Required | Details | Default | | ---------------------------- | -------- | ------------------------------------------------------------ | ---------- | | `--reauthorize ` | No | Reconnect an existing account | None | | `--local` | No | Use the local browser callback for OAuth | None | | `--hosted` | No | Use FLUXMAIL\_PUBLIC\_URL for the OAuth callback | None | | `--email
` | No | Mailbox address (required for IMAP) | None | | `--display-name ` | No | Sender name for IMAP messages | None | | `--imap-host ` | No | IMAP server hostname | None | | `--imap-port ` | No | IMAP server port | `993` | | `--imap-security ` | No | IMAP security: tls or starttls | `tls` | | `--imap-user ` | No | IMAP username; defaults to the mailbox address | None | | `--imap-password-env ` | No | Read the IMAP password from this environment variable | None | | `--smtp-host ` | No | SMTP server hostname | None | | `--smtp-port ` | No | SMTP server port | `587` | | `--smtp-security ` | No | SMTP security: tls or starttls | `starttls` | | `--smtp-user ` | No | SMTP username; defaults to the IMAP username | None | | `--smtp-password-env ` | No | Read a separate SMTP password from this environment variable | None | | `--sent-folder ` | No | Sent mailbox path | None | | `--drafts-folder ` | No | Drafts mailbox path | None | | `--trash-folder ` | No | Trash mailbox path | None | | `--archive-folder ` | No | Archive mailbox path | None | | `--spam-folder ` | No | Spam mailbox path | None | | `--no-save-sent` | No | Do not append SMTP submissions to the Sent folder | None | --- # fluxmail accounts assign URL: https://fluxmail.ai/docs/cli/accounts-assign `fluxmail accounts assign` Change mailbox ownership ## Usage [#usage] ```bash fluxmail accounts assign [options] ``` ## Arguments [#arguments] | Name | Required | Details | Default | | ----------- | -------- | ------- | ------- | | `accountId` | Yes | None | None | ## Options [#options] | Option | Required | Details | Default | | ------------------ | -------- | ------------------------------------- | ------- | | `--owner ` | Yes | Member id or email to own the mailbox | None | --- # fluxmail accounts configure URL: https://fluxmail.ai/docs/cli/accounts-configure `fluxmail accounts configure` Set special folder paths for an IMAP account ## Usage [#usage] ```bash fluxmail accounts configure [options] ``` ## Arguments [#arguments] | Name | Required | Details | Default | | ----------- | -------- | ------- | ------- | | `accountId` | Yes | None | None | ## Options [#options] | Option | Required | Details | Default | | ------------------------- | -------- | ------------------------------------------- | ------- | | `--sent-folder ` | No | Sent path, or auto to clear the override | None | | `--drafts-folder ` | No | Drafts path, or auto to clear the override | None | | `--trash-folder ` | No | Trash path, or auto to clear the override | None | | `--archive-folder ` | No | Archive path, or auto to clear the override | None | | `--spam-folder ` | No | Spam path, or auto to clear the override | None | --- # fluxmail accounts list URL: https://fluxmail.ai/docs/cli/accounts-list `fluxmail accounts list` List connected accounts ## Usage [#usage] ```bash fluxmail accounts list ``` ## Options [#options] This command has no command-specific options. --- # fluxmail accounts remove URL: https://fluxmail.ai/docs/cli/accounts-remove `fluxmail accounts remove` Disconnect an account and delete its stored tokens ## Usage [#usage] ```bash fluxmail accounts remove ``` ## Arguments [#arguments] | Name | Required | Details | Default | | ----------- | -------- | ------- | ------- | | `accountId` | Yes | None | None | ## Options [#options] This command has no command-specific options. --- # fluxmail accounts send-as add URL: https://fluxmail.ai/docs/cli/accounts-send-as-add `fluxmail accounts send-as add` Add a configured Outlook or IMAP sender address ## Usage [#usage] ```bash fluxmail accounts send-as add [options] ``` ## Arguments [#arguments] | Name | Required | Details | Default | | ------------ | -------- | ----------------------- | ------- | | `account-id` | Yes | Email account ID | None | | `email` | Yes | Existing provider alias | None | ## Options [#options] | Option | Required | Details | Default | | --------------- | -------- | ------------------- | ------- | | `--name ` | No | Sender display name | None | --- # fluxmail accounts send-as list URL: https://fluxmail.ai/docs/cli/accounts-send-as-list `fluxmail accounts send-as list` List available sender addresses ## Usage [#usage] ```bash fluxmail accounts send-as list ``` ## Arguments [#arguments] | Name | Required | Details | Default | | ------------ | -------- | ---------------- | ------- | | `account-id` | Yes | Email account ID | None | ## Options [#options] This command has no command-specific options. --- # fluxmail accounts send-as remove URL: https://fluxmail.ai/docs/cli/accounts-send-as-remove `fluxmail accounts send-as remove` Remove a configured Outlook or IMAP sender address ## Usage [#usage] ```bash fluxmail accounts send-as remove ``` ## Arguments [#arguments] | Name | Required | Details | Default | | ------------ | -------- | ------------------------- | ------- | | `account-id` | Yes | Email account ID | None | | `email` | Yes | Configured sender address | None | ## Options [#options] This command has no command-specific options. --- # fluxmail accounts send-as URL: https://fluxmail.ai/docs/cli/accounts-send-as `fluxmail accounts send-as` Manage sender addresses ## Usage [#usage] ```bash fluxmail accounts send-as [command] ``` ## Options [#options] This command has no command-specific options. ## Subcommands [#subcommands] | Command | Description | | ----------------------------------------------------------------------- | -------------------------------------------------- | | [`fluxmail accounts send-as list`](/docs/cli/accounts-send-as-list) | List available sender addresses | | [`fluxmail accounts send-as add`](/docs/cli/accounts-send-as-add) | Add a configured Outlook or IMAP sender address | | [`fluxmail accounts send-as remove`](/docs/cli/accounts-send-as-remove) | Remove a configured Outlook or IMAP sender address | --- # fluxmail accounts URL: https://fluxmail.ai/docs/cli/accounts `fluxmail accounts` Manage connected email accounts ## Usage [#usage] ```bash fluxmail accounts [command] ``` ## Options [#options] This command has no command-specific options. ## Subcommands [#subcommands] | Command | Description | | ------------------------------------------------------------- | -------------------------------------------------- | | [`fluxmail accounts send-as`](/docs/cli/accounts-send-as) | Manage sender addresses | | [`fluxmail accounts add`](/docs/cli/accounts-add) | Connect a Gmail, Outlook, or IMAP account | | [`fluxmail accounts configure`](/docs/cli/accounts-configure) | Set special folder paths for an IMAP account | | [`fluxmail accounts list`](/docs/cli/accounts-list) | List connected accounts | | [`fluxmail accounts remove`](/docs/cli/accounts-remove) | Disconnect an account and delete its stored tokens | | [`fluxmail accounts assign`](/docs/cli/accounts-assign) | Change mailbox ownership | | [`fluxmail accounts access`](/docs/cli/accounts-access) | Set who can access a mailbox | --- # fluxmail apikey accounts URL: https://fluxmail.ai/docs/cli/apikey-accounts `fluxmail apikey accounts` Replace or clear an API key mailbox allowlist ## Usage [#usage] ```bash fluxmail apikey accounts [options] ``` ## Arguments [#arguments] | Name | Required | Details | Default | | ------- | -------- | ------- | ------- | | `keyId` | Yes | None | None | ## Options [#options] | Option | Required | Details | Default | | --------------------- | -------- | --------------------------------------------------------- | ------- | | `--account ` | No | Replace the allowlist with this mailbox; repeat as needed | None | | `--all-accounts` | No | Clear the allowlist | None | --- # fluxmail apikey capabilities URL: https://fluxmail.ai/docs/cli/apikey-capabilities `fluxmail apikey capabilities` List capabilities for API key permission policies ## Usage [#usage] ```bash fluxmail apikey capabilities ``` ## Options [#options] This command has no command-specific options. --- # fluxmail apikey create URL: https://fluxmail.ai/docs/cli/apikey-create `fluxmail apikey create` Create an API key (shown once) ## Usage [#usage] ```bash fluxmail apikey create [options] ``` ## Options [#options] | Option | Required | Details | Default | | ---------------------- | -------- | ------------------------------------------------------------- | ------- | | `--name ` | Yes | Human-readable key name | None | | `--member ` | No | Admin only: issue the key to another member | None | | `--account ` | No | Limit the key to one mailbox; repeat as needed | None | | `--profile ` | No | Tool profile: read-only, read-write, full | None | | `--allow ` | No | Allow one capability in a custom policy; repeat as needed | None | | `--admin ` | No | Add one admin capability to a named profile; repeat as needed | None | --- # fluxmail apikey list URL: https://fluxmail.ai/docs/cli/apikey-list `fluxmail apikey list` List API keys ## Usage [#usage] ```bash fluxmail apikey list ``` ## Options [#options] This command has no command-specific options. --- # fluxmail apikey permissions URL: https://fluxmail.ai/docs/cli/apikey-permissions `fluxmail apikey permissions` Change the permissions for an API key ## Usage [#usage] ```bash fluxmail apikey permissions [options] ``` ## Arguments [#arguments] | Name | Required | Details | Default | | ------- | -------- | ------- | ------- | | `keyId` | Yes | None | None | ## Options [#options] | Option | Required | Details | Default | | ---------------------- | -------- | ------------------------------------------------------------- | ------- | | `--profile ` | No | Tool profile: read-only, read-write, full | None | | `--allow ` | No | Allow one capability in a custom policy; repeat as needed | None | | `--admin ` | No | Add one admin capability to a named profile; repeat as needed | None | --- # fluxmail apikey revoke URL: https://fluxmail.ai/docs/cli/apikey-revoke `fluxmail apikey revoke` Revoke an API key ## Usage [#usage] ```bash fluxmail apikey revoke ``` ## Arguments [#arguments] | Name | Required | Details | Default | | ------- | -------- | ------- | ------- | | `keyId` | Yes | None | None | ## Options [#options] This command has no command-specific options. --- # fluxmail apikey URL: https://fluxmail.ai/docs/cli/apikey `fluxmail apikey` Manage API keys for the HTTP MCP and REST APIs ## Usage [#usage] ```bash fluxmail apikey [command] ``` ## Options [#options] This command has no command-specific options. ## Subcommands [#subcommands] | Command | Description | | --------------------------------------------------------------- | ------------------------------------------------- | | [`fluxmail apikey capabilities`](/docs/cli/apikey-capabilities) | List capabilities for API key permission policies | | [`fluxmail apikey create`](/docs/cli/apikey-create) | Create an API key (shown once) | | [`fluxmail apikey list`](/docs/cli/apikey-list) | List API keys | | [`fluxmail apikey accounts`](/docs/cli/apikey-accounts) | Replace or clear an API key mailbox allowlist | | [`fluxmail apikey permissions`](/docs/cli/apikey-permissions) | Change the permissions for an API key | | [`fluxmail apikey revoke`](/docs/cli/apikey-revoke) | Revoke an API key | --- # fluxmail attachments download URL: https://fluxmail.ai/docs/cli/attachments-download `fluxmail attachments download` Download an attachment ## Usage [#usage] ```bash fluxmail attachments download [options] ``` ## Arguments [#arguments] | Name | Required | Details | Default | | --------------- | -------- | ------------------------------------------ | ------- | | `message-id` | Yes | Provider message ID | None | | `attachment-id` | Yes | Opaque attachment ID from message metadata | None | ## Options [#options] | Option | Required | Details | Default | | ----------------- | -------- | --------------------------------- | ------- | | `--output ` | Yes | Write the attachment to this path | None | | `--force` | No | Overwrite an existing file | None | --- # fluxmail attachments URL: https://fluxmail.ai/docs/cli/attachments `fluxmail attachments` Download message attachments ## Usage [#usage] ```bash fluxmail attachments [command] ``` ## Options [#options] This command has no command-specific options. ## Subcommands [#subcommands] | Command | Description | | ----------------------------------------------------------------- | ---------------------- | | [`fluxmail attachments download`](/docs/cli/attachments-download) | Download an attachment | --- # fluxmail auth recover-admin URL: https://fluxmail.ai/docs/cli/auth-recover-admin `fluxmail auth recover-admin` Reset an administrator password using local filesystem access ## Usage [#usage] ```bash fluxmail auth recover-admin ``` ## Arguments [#arguments] | Name | Required | Details | Default | | -------- | -------- | ------------------------- | ------- | | `member` | Yes | Administrator id or email | None | ## Options [#options] This command has no command-specific options. --- # fluxmail auth revoke-session URL: https://fluxmail.ai/docs/cli/auth-revoke-session `fluxmail auth revoke-session` Revoke one of the current member's sessions ## Usage [#usage] ```bash fluxmail auth revoke-session ``` ## Arguments [#arguments] | Name | Required | Details | Default | | ----------- | -------- | ------- | ------- | | `sessionId` | Yes | None | None | ## Options [#options] This command has no command-specific options. --- # fluxmail auth sessions URL: https://fluxmail.ai/docs/cli/auth-sessions `fluxmail auth sessions` List sessions for the current member ## Usage [#usage] ```bash fluxmail auth sessions ``` ## Options [#options] This command has no command-specific options. --- # fluxmail auth URL: https://fluxmail.ai/docs/cli/auth `fluxmail auth` Manage interactive authentication ## Usage [#usage] ```bash fluxmail auth [command] ``` ## Options [#options] This command has no command-specific options. ## Subcommands [#subcommands] | Command | Description | | --------------------------------------------------------------- | ------------------------------------------------------------- | | [`fluxmail auth recover-admin`](/docs/cli/auth-recover-admin) | Reset an administrator password using local filesystem access | | [`fluxmail auth sessions`](/docs/cli/auth-sessions) | List sessions for the current member | | [`fluxmail auth revoke-session`](/docs/cli/auth-revoke-session) | Revoke one of the current member's sessions | --- # fluxmail config init URL: https://fluxmail.ai/docs/cli/config-init `fluxmail config init` Create config.toml in the Fluxmail data directory ## Usage [#usage] ```bash fluxmail config init ``` ## Options [#options] This command has no command-specific options. --- # fluxmail config migrate URL: https://fluxmail.ai/docs/cli/config-migrate `fluxmail config migrate` Import settings from an env file without deleting it ## Usage [#usage] ```bash fluxmail config migrate [options] ``` ## Options [#options] | Option | Required | Details | Default | | ------------------- | -------- | ------------------------------------------------------- | ------- | | `--from ` | Yes | Read recognized settings from this env file | None | | `--dry-run` | No | Show recognized setting names without changing Fluxmail | None | --- # fluxmail config show URL: https://fluxmail.ai/docs/cli/config-show `fluxmail config show` Show effective configuration, sources, paths, and restart requirements ## Usage [#usage] ```bash fluxmail config show ``` ## Options [#options] This command has no command-specific options. --- # fluxmail config URL: https://fluxmail.ai/docs/cli/config `fluxmail config` Inspect and initialize deployment configuration ## Usage [#usage] ```bash fluxmail config [command] ``` ## Options [#options] This command has no command-specific options. ## Subcommands [#subcommands] | Command | Description | | ----------------------------------------------------- | ---------------------------------------------------------------------- | | [`fluxmail config init`](/docs/cli/config-init) | Create config.toml in the Fluxmail data directory | | [`fluxmail config show`](/docs/cli/config-show) | Show effective configuration, sources, paths, and restart requirements | | [`fluxmail config migrate`](/docs/cli/config-migrate) | Import settings from an env file without deleting it | --- # fluxmail drafts create URL: https://fluxmail.ai/docs/cli/drafts-create `fluxmail drafts create` Create a draft ## Usage [#usage] ```bash fluxmail drafts create [options] ``` ## Options [#options] | Option | Required | Details | Default | | ------------------------- | -------- | --------------------------------------------------------------------------- | ------- | | `--from
` | No | Send from an available address | None | | `--to
` | No | Add a To recipient; repeat as needed | None | | `--cc
` | No | Add a Cc recipient; repeat as needed | None | | `--bcc
` | No | Add a Bcc recipient; repeat as needed | None | | `--subject ` | No | Set the subject | None | | `--body ` | No | Set the plain-text body; use blank lines between unwrapped prose paragraphs | None | | `--body-file ` | No | Read the plain-text body from a file; keep prose paragraphs unwrapped | None | | `--html ` | No | Set the HTML body | None | | `--html-file ` | No | Read the HTML body from a file | None | | `--attach ` | No | Attach a local file; repeat as needed | None | | `--reply-to ` | No | Reply to a message | None | | `--reply-all` | No | Include the original recipients in the reply | None | | `--input ` | No | Read an exact REST JSON body from a file, or pass - for stdin | None | --- # fluxmail drafts delete URL: https://fluxmail.ai/docs/cli/drafts-delete `fluxmail drafts delete` Delete a draft ## Usage [#usage] ```bash fluxmail drafts delete ``` ## Arguments [#arguments] | Name | Required | Details | Default | | ---------- | -------- | ----------------- | ------- | | `draft-id` | Yes | Provider draft ID | None | ## Options [#options] This command has no command-specific options. --- # fluxmail drafts get URL: https://fluxmail.ai/docs/cli/drafts-get `fluxmail drafts get` Read a draft ## Usage [#usage] ```bash fluxmail drafts get ``` ## Arguments [#arguments] | Name | Required | Details | Default | | ---------- | -------- | ----------------- | ------- | | `draft-id` | Yes | Provider draft ID | None | ## Options [#options] This command has no command-specific options. --- # fluxmail drafts update URL: https://fluxmail.ai/docs/cli/drafts-update `fluxmail drafts update` Replace the content of a draft ## Usage [#usage] ```bash fluxmail drafts update [options] ``` ## Arguments [#arguments] | Name | Required | Details | Default | | ---------- | -------- | ----------------- | ------- | | `draft-id` | Yes | Provider draft ID | None | ## Options [#options] | Option | Required | Details | Default | | ------------------------- | -------- | --------------------------------------------------------------------------- | ------- | | `--from
` | No | Send from an available address | None | | `--to
` | No | Add a To recipient; repeat as needed | None | | `--cc
` | No | Add a Cc recipient; repeat as needed | None | | `--bcc
` | No | Add a Bcc recipient; repeat as needed | None | | `--subject ` | No | Set the subject | None | | `--body ` | No | Set the plain-text body; use blank lines between unwrapped prose paragraphs | None | | `--body-file ` | No | Read the plain-text body from a file; keep prose paragraphs unwrapped | None | | `--html ` | No | Set the HTML body | None | | `--html-file ` | No | Read the HTML body from a file | None | | `--attach ` | No | Attach a local file; repeat as needed | None | | `--reply-to ` | No | Reply to a message | None | | `--reply-all` | No | Include the original recipients in the reply | None | | `--input ` | No | Read an exact REST JSON body from a file, or pass - for stdin | None | --- # fluxmail drafts URL: https://fluxmail.ai/docs/cli/drafts `fluxmail drafts` Create and manage drafts ## Usage [#usage] ```bash fluxmail drafts [command] ``` ## Options [#options] This command has no command-specific options. ## Subcommands [#subcommands] | Command | Description | | --------------------------------------------------- | ------------------------------ | | [`fluxmail drafts get`](/docs/cli/drafts-get) | Read a draft | | [`fluxmail drafts create`](/docs/cli/drafts-create) | Create a draft | | [`fluxmail drafts update`](/docs/cli/drafts-update) | Replace the content of a draft | | [`fluxmail drafts delete`](/docs/cli/drafts-delete) | Delete a draft | --- # fluxmail emails delivery-status URL: https://fluxmail.ai/docs/cli/emails-delivery-status `fluxmail emails delivery-status` Check a send or forward outcome ## Usage [#usage] ```bash fluxmail emails delivery-status ``` ## Arguments [#arguments] | Name | Required | Details | Default | | -------------- | -------- | --------------------- | ------- | | `operation-id` | Yes | Delivery operation ID | None | ## Options [#options] This command has no command-specific options. --- # fluxmail emails forward URL: https://fluxmail.ai/docs/cli/emails-forward `fluxmail emails forward` Forward a message ## Usage [#usage] ```bash fluxmail emails forward [options] ``` ## Arguments [#arguments] | Name | Required | Details | Default | | ------------ | -------- | ------------------- | ------- | | `message-id` | Yes | Provider message ID | None | ## Options [#options] | Option | Required | Details | Default | | ------------------------- | -------- | -------------------------------------------------------------------------- | ------- | | `--from
` | No | Send from an available address | None | | `--to
` | No | Add a To recipient; repeat as needed | None | | `--cc
` | No | Add a Cc recipient; repeat as needed | None | | `--comment ` | No | Add a comment above the forwarded message; keep prose paragraphs unwrapped | None | | `--no-attachments` | No | Do not include attachments from the original message | None | | `--idempotency-key ` | No | Reuse a delivery request safely | None | | `--input ` | No | Read an exact REST JSON body from a file, or pass - for stdin | None | --- # fluxmail emails get URL: https://fluxmail.ai/docs/cli/emails-get `fluxmail emails get` Get a complete message ## Usage [#usage] ```bash fluxmail emails get ``` ## Arguments [#arguments] | Name | Required | Details | Default | | ------------ | -------- | ------------------- | ------- | | `message-id` | Yes | Provider message ID | None | ## Options [#options] This command has no command-specific options. --- # fluxmail emails list URL: https://fluxmail.ai/docs/cli/emails-list `fluxmail emails list` List and filter messages ## Usage [#usage] ```bash fluxmail emails list [options] ``` ## Options [#options] | Option | Required | Details | Default | | ------------------------------------ | -------- | -------------------------------------------------------- | ------- | | `--folder ` | No | Filter by folder ID, role, or name | None | | `--from
` | No | Filter by sender | None | | `--to
` | No | Filter by recipient | None | | `--subject ` | No | Filter by subject | None | | `--read ` | No | Filter by read state | None | | `--starred ` | No | Filter by starred state | None | | `--has-attachment ` | No | Filter by attachment state | None | | `--after ` | No | Return messages on or after this YYYY-MM-DD date | None | | `--before ` | No | Return messages before this YYYY-MM-DD date | None | | `--raw-provider-query ` | No | Pass a provider-native query | None | | `--page-size ` | No | Return 1 to 100 messages | None | | `--page-token ` | No | Continue from a previous response | None | | `--include-snippet ` | No | Request or suppress message previews | None | | `--include-search-context ` | No | Include a body excerpt around the search match | None | | `--all` | No | Fetch every page up to --max-results | None | | `--max-results ` | No | Maximum results with --all (default 1000, maximum 10000) | None | | `--text ` | No | Filter by literal full-text search | None | --- # fluxmail emails modify URL: https://fluxmail.ai/docs/cli/emails-modify `fluxmail emails modify` Apply one action to one or more messages ## Usage [#usage] ```bash fluxmail emails modify [action] [message-ids...] [options] ``` ## Arguments [#arguments] | Name | Required | Details | Default | | ---------------- | -------- | --------------------------------------------------------------- | ------- | | `action` | No | Message action, such as mark-read, archive, move, or add-labels | None | | `message-ids...` | No | Provider message IDs | None | ## Options [#options] | Option | Required | Details | Default | | ------------------- | -------- | ------------------------------------------------------------- | ------- | | `--folder ` | No | Destination folder for move | None | | `--label