Configuration¶
Version scope: Managed mode and the embedded React UI on this page are Local Email App V2 behavior. See Version availability before using these commands with a PyPI installation.
mcp-email-server supports two explicitly selectable configuration modes:
legacykeeps account configuration in TOML and composes documented environment overlays;managedkeeps account authority in private SQLite. On Linux and Windows, credentials default to its dedicatedmanaged_secrettable. Windows requires a local fixed NTFS catalog protected by handle-bound DACL, reparse, identity, and locking checks. macOS uses the operating-system keyring. Managed catalogs are not supported without the complete platform filesystem-security profile.
A missing configuration file or a v1 TOML source without separate bootstrap
authority remains legacy for backward compatibility. Historical db_location
continues to name the rebuildable legacy metadata index; it is not a managed
catalog selection. For the default source config.toml, selection authority is
stored separately in the owner-only sibling config.bootstrap.toml. Every new
sidecar write records bootstrap_version = 1, a monotonic bootstrap_revision,
an explicit mode, a managed_selection marker, and any selected catalog as
managed_db_location. Selection uses the bootstrap revision as a
compare-and-swap token under the private config.bootstrap.toml.lock; it is
separate from the managed catalog revision. Selection and import never reserialize
or rewrite the v1 source, so comments, ordering, whitespace, and rollback bytes
remain unchanged. A pre-release combined file is accepted read-only; a later
selection write, or the authority step preceding an explicit legacy source write,
materializes its selection into the sidecar without that step changing source
bytes.
Configuration file¶
The default path is:
~/.config/mcp-email-server/config.toml
Set MCP_EMAIL_SERVER_CONFIG_PATH to use a different legacy TOML source path.
Relative paths are resolved against the server process's working directory. The
bootstrap sidecar is derived in the same directory by adding .bootstrap before
the TOML suffix: /path/work.toml uses /path/work.bootstrap.toml.
On first use, if the current file does not exist and a legacy file exists at
~/.config/zerolib/mcp_email_server/config.toml, the legacy file is copied to
the current location automatically. The destination is created owner-only on
POSIX and with the protected private DACL on Windows; concurrent destination
creation is never overwritten. An explicitly managed file at the old path is
not copied as an import-time side effect.
Local management UI¶
mcp-email-server ui [--no-open] [--port PORT] provides the user-facing managed
management plane through an embedded React application. The low-level CLI is the
complete headless superset, including provider-connectivity diagnostics. The UI
always binds to 127.0.0.1; the default port 0 asks the operating system for
an ephemeral port. There is no host, share, debug, reload, daemon, or remote-UI
option. The
default opens the one-time URL directly in the browser; --no-open requires an
attached terminal and prints the URL only there. A noninteractive invocation
fails before serving rather than exposing its bootstrap token in logs.
After authentication and status inspection, a truly empty installation issues
one CSRF-protected POST that prepares managed.sqlite3 in the same private
directory as the active source and bootstrap sidecar. The POST rechecks the
effective legacy source, then binds
both the zero revision and absent-file proof under the same secure cross-process
platform lock used by legacy settings writes. No GET mutates state.
If effective TOML/environment legacy content exists, the UI does not initialize
automatically; Import existing settings is an explicit preparation and
review action. A fresh installation creates the catalog and selects managed mode
in one step. With existing v1 content, preparation records the migration
destination while legacy remains selected; it does not import or contact a
provider. A complete reviewed import automatically selects managed mode when all
source account types are supported. Failure or unsupported provider types leave
legacy selected, and no path restarts the process automatically.
The UI is account-first and has two primary destinations. Email accounts
lists saved accounts and keeps edit, pause/enable, soft removal, and password
rotation in each account's context. The add form is email/password-first.
It derives an editable sender name and account nickname, uses finite presets for
common email services, and otherwise suggests imap.<email-domain> and
smtp.<email-domain>. Suggestions continue changing only while their fields are
untouched. There is no redundant connection preview. Advanced server, login,
port, security, certificate, and Sent-folder fields are folded behind progressive
disclosure, as is optional outgoing mail; changing an untouched security default
also moves between the corresponding standard ports. Settings & help folds
importing earlier settings, sending/attachment safety, account checks, and email
search checks into optional sections and does not load a section until it is
opened. Per-role password changes remain in the affected account's Password
context. A failed save displays an error and leaves the current binding authority
unchanged. Provider connectivity testing and its route are absent from
the Web UI; use the CLI account test diagnostic instead. When the
catalog reports inactive password data left by a failed external deletion,
Email accounts shows one bounded cleanup action even if no active account
remains; cleanup is catalog-wide and never removes an active password.
A contextual status area distinguishes settings chosen for the next restart from those currently running and exposes import, explicit recovery selection, and restart steps when actionable. Banners with no next action are hidden for an empty workspace and for settled ready state. There is no catalog activation or second save step. Account completeness is evaluated per account: an incomplete account appears in diagnostics and is omitted from MCP discovery without blocking complete accounts. Ordinary status, conflict, credential, import, and troubleshooting messages map implementation states to task language. Catalog- dependent content remains unavailable until the catalog is usable. Mutable catalog operations carry the exact reviewed catalog path and bootstrap revision as well as the relevant catalog or account revision. A selection change therefore conflicts instead of redirecting a write to a different catalog with a coincidentally equal numeric revision. A conflict displays a current bounded non-secret summary and requires explicit review rather than automatic replay. Legacy mode remains inspectable and importable, but the UI is not a legacy TOML editor.
The browser process is only an adapter over shared management application services. It has no provider-connectivity route, mail, generic RPC, filesystem browser, OpenAPI, or MCP App surface. Managed catalog and attachment effects, plus oversized-result spill, require the documented POSIX or Windows filesystem-security profile and fail closed when that complete profile is unavailable. See Security for its one-time bootstrap, platform, and session boundaries.
Managed CLI setup¶
A fresh managed setup creates and selects its catalog in one step:
mcp-email-server config init --database ~/.config/mcp-email-server/catalog.sqlite3
mcp-email-server account add work \
--email [email protected] \
--full-name "John Doe" \
--imap-host imap.example.com \
--imap-user [email protected]
mcp-email-server account test work incoming
Restart MCP clients when config status reports restart_required=true.
account add prompts for the IMAP password with masked input. Add SMTP with
--smtp-host, --smtp-port, and --smtp-user; the command then prompts for a
separate SMTP password. For non-interactive setup, pass --password-stdin and
provide one line for IMAP, followed by one SMTP line when SMTP is configured.
Passwords are never accepted as ordinary command-line values.
config init creates a usable SQLite catalog with no staging lifecycle. On a
fresh installation it selects managed mode immediately. If it detects effective
v1 TOML accounts, environment configuration, providers, or customized policy,
it records the migration destination but leaves legacy mode in use until the
reviewed import succeeds. Retrying the same owner-only, structurally valid path
adopts it without resetting data or revisions; a corrupt, foreign, insecure, or
incompatible target is rejected. This makes a retry possible if catalog creation
committed but the bootstrap compare-and-swap did not. Initialization cannot
replace a different catalog while managed mode is selected.
Accounts may be added or updated at any time. A complete account becomes
available without catalog activation or another save. An incomplete enabled
account remains visible to config doctor but is omitted from runtime discovery;
it does not block complete accounts. config select managed validates catalog
schema/security and the reviewed revision, not global account completeness.
Restart every MCP server process after a selection change.
Useful inspection and management commands are:
mcp-email-server config status
mcp-email-server config doctor
mcp-email-server config index-health
mcp-email-server config policy
mcp-email-server config update-policy --expected-revision 1 \
--allowed-recipients '[email protected],[email protected]'
mcp-email-server account list
mcp-email-server account show work
mcp-email-server account set-secret work incoming
mcp-email-server account test work incoming
mcp-email-server account disable work --expected-revision 3
mcp-email-server account enable work --expected-revision 4
mcp-email-server config cleanup-credentials
mcp-email-server config select legacy
Machine-readable CLI output¶
The managed CLI is the low-level agent management API. Its exact catalog,
revision, binding-state, and restart-state terms are intentional and are more
technical than Web UI task language. Every finite config and account command
supports a leaf --json option, as do reset and migrate-credentials. Put it
after the command:
mcp-email-server config status --json
mcp-email-server config doctor --json
mcp-email-server account list --json
mcp-email-server account show work --json
A dispatched success writes one JSON document to stdout with
schema_version: 1, ok: true, a stable command identifier, command-specific
data, and an always-present warnings array. Mutations include the relevant
resulting account, binding, catalog, bootstrap-revision, or restart-state fields.
A dispatched application failure
keeps its nonzero exit status and writes one schema-version-1 document with
ok: false, a typed stable error.code, that code's fixed safe message, and
reviewed non-secret details. Click usage errors such as a
missing required option happen before command dispatch and remain normal Click
errors in this release.
Schema-version-1 management failures use the following public codes. Callers must still treat an unknown code as unsupported rather than guessing from its message.
error.code |
Meaning and recovery |
|---|---|
revision_conflict |
Reviewed state changed; inspect the safe details revisions and reread. |
account_limit_reached |
The managed account cap was reached; remove an unused account. |
account_name_exists |
The normalized nickname is reserved, including by a removed account. |
bootstrap_unavailable |
Bootstrap authority is invalid, unavailable, or busy; inspect status. |
catalog_not_configured |
Initialize or select a managed catalog before the catalog command. |
catalog_unavailable |
The selected catalog cannot be opened or validated; run status/doctor. |
credential_store_unavailable |
Restore access to the selected managed secret store and retry. |
import_credential_conflict |
Legacy and active managed passwords differ; reconcile before cutover. |
import_preview_stale |
Source or destination changed, or preview expired; preview again. |
import_target_changed |
The selected import destination changed; preview the new target. |
invalid_input |
Correct the command values; framework usage errors remain non-JSON. |
storage_unavailable |
Required local management storage is inaccessible; repair access. |
management_error |
A bounded management failure has no narrower recovery category. |
runtime_error |
An unexpected bounded command failure occurred; inspect status. |
JSON presentation fields are explicit rather than generic dataclass dumps. They
do not include local configuration or database paths, import preview tokens,
secret values, or secret locators. Credential migration JSON reports cleanup
counts, completion state, and warning codes; exact keyring entry names remain
available only in the human-facing text result. Bootstrap parse/write failures
use bounded remediation rather than embedding the private path. config status
--json reports catalog_status as not_configured, available, or
unavailable, includes restart_required, and nests the bounded
doctor report when available. Empty account list --json results use
{"accounts": []} rather than silent output. account show --json includes all
mutable non-secret identity, endpoint/TLS, Sent-copy, revision, and binding
fields so automation can review before a revisioned write.
JSON output is a presentation contract and grants no command authority.
account add --json and account set-secret --json require
--password-stdin; secrets enter the low-level API only through user-controlled
stdin. This prevents an interactive prompt from corrupting the single document
and is intended for user-owned automation, not for sending a credential through
an agent. Interactive config import-legacy --apply
rejects --json because review and same-process confirmation cannot be reduced
to one result document; JSON preview without --apply is supported.
Managed account and binding summaries never print secret locators or values.
Account-create commands carry non-secret endpoint summaries separately from
SecretStr credential fields; command representation and equality exclude those
fields. config doctor also verifies active secret availability without printing
the secret or locator. Disabled accounts are revalidated and excluded before
every provider access, including calls in an already-running stdio session.
Selecting managed mode never deletes preserved legacy TOML rows, and selecting
legacy mode never deletes the managed catalog.
Managed policy updates use the same canonicalization as legacy configuration:
recipient addresses are extracted and lowercased, sender glob patterns are
trimmed and lowercased, and empty or duplicate entries are removed while
preserving first occurrence order. config update-policy preserves omitted
fields; pass an empty value to --allowed-recipients or --allowed-senders to
clear that list. These empty values differ deliberately: empty allowed recipients
disables sending, while empty allowed senders does not restrict reading. The Web
UI represents each recipient or sender pattern as an individual add/edit/remove
item rather than a comma-separated field. Every update requires the revision
shown by config policy.
Endpoint ports must be between 1 and 65535, and implicit TLS cannot be combined
with STARTTLS. account add checks the selected catalog and these non-secret
endpoint rules before prompting or reading a credential; application services
revalidate them for every caller.
A failed account set-secret returns a typed error and does not persist an
intermediate binding or change the current binding authority. config
index-health prints bounded rebuildable-projection status and problems. account
test ACCOUNT [incoming|outgoing] is the retained low-level, agent-facing
connectivity diagnostic (not a Web UI capability) and exits nonzero for a typed
connection failure and never prints a success sentence in that case. JSON
failures use one of timeout, endpoint_unavailable, credential_unavailable,
authentication_or_provider_rejected, or tls_or_connection_failed; messages
contain bounded remediation rather than provider exception text. An outgoing test
checks for a configured SMTP endpoint before resolving its credential, authenticates,
submits MAIL FROM with the configured account email address, and resets the
transaction without issuing RCPT TO or DATA. Success therefore proves that
the server accepted the envelope sender, but not that it would accept a recipient
or message body. Typed IMAP/SMTP authentication, sender rejection, and timeout
failures retain the correct category.
Managed account lifecycle¶
On Linux and Windows, account add and account set-secret insert the new value
into the private managed_secret table and activate its binding/revision in one
SQLite transaction. On macOS, the system keyring write precedes one
compare-and-swap activation transaction. Any failure before
activation returns an error without persisting an intermediate binding or
changing current binding authority. During rotation, activation first marks the
old active value CLEANUP_REQUIRED; confirmed deletion clears that state, while
an external or follow-up deletion failure retains it.
account show prints the current account revision. Pass that value with
--expected-revision to account update, account disable, account enable,
account remove-secret, and account remove. A stale value is rejected without
applying the write; inspect the account again and decide whether to retry against
the new state.
account update can rename an account, change identity fields and endpoint
settings, add or remove SMTP, and change Sent-copy behavior. A new SMTP endpoint
requires all host, port, username, and TLS fields. An enabled account cannot be
left with an incomplete endpoint/binding pair. Remove its SMTP credential before
using --remove-outgoing.
Disable an account before removing one of its credentials. Credential removal
first detaches the active binding in SQLite, then attempts deletion from the
selected managed secret store. If deletion cannot be confirmed, config doctor
reports CLEANUP_REQUIRED; run the bounded config cleanup-credentials --limit
100 command after storage access is restored. Re-enabling validates all required
active credentials outside a SQLite transaction and rejects concurrent revision
changes. A failed new save returns an error, leaves no intermediate binding, and
preserves the prior binding authority.
account remove NAME --expected-revision REV --confirm NAME is an intentional
soft removal. The exact name confirmation is required. The row no longer appears
as an available account, while its stable operational identity, endpoints, and
binding metadata remain for bounded cleanup; hard purge is not part of this
release. Before committing the tombstone, the service marks every referenced
credential value CLEANUP_REQUIRED, then attempts bounded deletion from the
selected store.
Successfully deleted values are finalized as superseded; failures remain visible
to config doctor and config cleanup-credentials. The normalized-name
tombstone is permanent in this delivery, so the removed account name cannot be
reused.
Legacy and managed authority each allow at most 1,000 configured live accounts,
1,000 recipient allowlist entries, and 1,000 sender allowlist entries. Managed
writes reject larger snapshots before commit. Discovery also applies the shared
8 MiB canonical serialized-result ceiling and fails with limit_exceeded rather
than truncating authority data.
Import stored legacy configuration¶
Import is explicit and preview-first. Initialize a migration destination, then run:
mcp-email-server config import-legacy
mcp-email-server config import-legacy --apply
# Review the displayed plan, then type IMPORT at the prompt.
The preview reads the effective legacy view without resolving secrets: stored
TOML email accounts, unsupported provider names, exact-name environment account
replacement or environment-account insertion, and environment boolean/allowlist
overrides. Credential source is reported as plaintext, keyring, or
environment; preview uses redacted endpoint models, does not read environment
password values or the keyring, and does not place TOML password material in the
snapshot or plan. Password-variable presence is detected by enumerating names,
not retrieving values. Apply resolves required plaintext, keyring, or current
environment credentials through the normal managed save workflow and leaves the
source TOML, environment, and legacy keyring entries unchanged. Preparation keeps
legacy selected. A complete successful import automatically selects managed mode only when every
source account type is supported and no cleanup attention remains. Final cutover
holds the shared source/selection lock and a managed-catalog writer fence while
rechecking the exact source snapshot, imported private credential values, final
catalog/account revisions, and bootstrap compare-and-swap. Any failure or drift
keeps legacy selected; unsupported provider-style accounts are reported and
prevent automatic cutover until the user explicitly decides whether to select
the supported managed subset.
Each preview has a random one-time token, a SHA-256 fingerprint of the bounded
non-secret source snapshot, creation time, a ten-minute lifetime, and exact
catalog, policy, and per-account target revisions. Account rows show their full
non-secret endpoint/TLS/user/save-to-sent settings and whether each credential
comes from plaintext TOML, the legacy keyring, or environment; no secret value
or reusable locator is shown. CLI --apply prints this plan before it prompts
for the exact word IMPORT, so confirmation cannot be supplied before review.
A no-change plan needs no prompt, but when all source account types are supported,
Finish setup/--apply still verifies that each legacy password equals its
active managed counterpart and attempts the guarded final cutover; it never
returns early merely because no rows need writing.
Apply consumes the token, verifies that the selected catalog path and bootstrap revision still
match the private preview, and rejects expiry or source/target drift before the
next credential resolution or write. Selection is checked again immediately
before every account, credential, and policy write; apply advances only revisions
caused by its own completed steps. Preview capability state is expired on access and capped at
32 entries per process. In the UI, preview creation is a CSRF-protected POST,
not a state-changing GET.
A repeated import is deterministic: exact matching accounts and policy are
reported unchanged only after their active managed passwords are privately proven
equal to the current legacy values, genuinely MISSING bindings can be filled,
and a changed, renamed, normalized-name-colliding, or previously soft-removed
destination is reported as a conflict before any destination write. A password
mismatch is a credential conflict: neither side is overwritten and legacy remains
selected until the user updates or removes the managed credential and retries.
Planning also rejects normalized collisions within the source and account-limit
overflow. If the effective source account changes between planning and
credential resolution, apply fails and requires a new preview rather than
mixing an old endpoint with a new secret. A committed credential outcome that needs cleanup is reported explicitly rather
than claimed as clean success. A cleanup-required binding becomes an explicit
conflict until cleanup completes. Failed credential saves preserve prior binding
authority. Resolve conflicts or cleanup attention, preview again, and test
imported endpoints. A complete supported import has already selected managed
mode; otherwise make any later selection explicit.
Operational metadata database¶
list_emails_metadata uses db_location for a bounded, rebuildable metadata
projection. Managed mode stores that projection beside the authoritative catalog
in the selected managed database. Legacy and environment-composited accounts use
the configured db_location, whose default is db.sqlite3 next to the active
configuration file. The server creates this operational database only when the
metadata workflow first needs it.
Legacy source mapping stores a stable non-secret fingerprint and never copies an account password, keyring entry, endpoint row, or secret locator into managed configuration tables. The projection may contain mailbox names and message headers needed by the public metadata result. Removing the operational database only discards rebuildable observations; it does not remove accounts or mail.
Managed storage uses one exact current schema for account authority, the
platform-selected secret binding, and the operational projection. On Linux and
Windows, any copy, snapshot, or backup of this database includes plaintext values
from managed_secret; protect every copy with private access equivalent to the
original and never treat the catalog as a non-secret database. There are no
released managed-catalog users, so pre-release development schemas receive no
compatibility or automatic-migration promise. Legacy TOML, environment, and
keyring sources remain supported through explicit import. Unsupported, corrupt,
or insecure managed storage fails closed. In legacy mode, an unavailable or unsafe operational
database produces a bounded warning and the metadata query uses its bounded IMAP
fallback instead.
Legacy configuration precedence¶
The following composition applies only in legacy mode. The TOML file provides
the base settings, then environment variables are applied as follows:
- Global boolean and allowlist environment variables override the matching TOML values.
MCP_EMAIL_SERVER_CREDENTIAL_STORAGEoverrides the TOML storage mode.- A complete environment-provided email account replaces a TOML account with
the same
account_name. - If no TOML account has that name, the environment-provided account is added before the TOML accounts.
An environment account is created only when MCP_EMAIL_SERVER_EMAIL_ADDRESS,
a non-empty MCP_EMAIL_SERVER_PASSWORD, and MCP_EMAIL_SERVER_IMAP_HOST are all
present. The generic password remains required even when separate IMAP or SMTP
password variables are provided. An absent or explicitly empty role-specific
password falls back to that generic password in both legacy runtime and managed
import.
migrate-credentials is intentionally different: it migrates only the stored
TOML configuration and ignores environment-provided accounts and overrides. Its
stored load, keyring/TOML commit, and checked plaintext cleanup run under the same
legacy write transaction as store/reset, so concurrent operations cannot leave a
sentinel referring to a deleted credential.
Legacy runtime continues to compose this view without persisting it. Managed import explicitly copies the reviewed effective account/policy view and required credentials into managed SQLite/SecretStore state; it never rewrites the legacy TOML or environment. Legacy TOML/environment/keyring behavior remains a compatibility input and explicit import source; account management is available only through the managed CLI and authenticated local UI.
credential_storage controls only how persistent settings are written. It does
not protect passwords stored in an MCP client configuration, process
environment, CI definition, or container metadata. Prefer the platform's secret
injection mechanism and restrict access to any file containing literal values.
TOML example¶
The following example contains all commonly used account fields:
credential_storage = "auto"
enable_attachment_download = false
allowed_recipients = []
allowed_senders = []
report_blocked_mutations = false
[[emails]]
account_name = "work"
description = "Work mailbox"
full_name = "John Doe"
email_address = "[email protected]"
save_to_sent = true
sent_folder_name = "Sent"
[emails.incoming]
user_name = "[email protected]"
password = "your-password"
host = "imap.example.com"
port = 993
use_ssl = true
start_ssl = false
verify_ssl = true
[emails.outgoing]
user_name = "[email protected]"
password = "your-password"
host = "smtp.example.com"
port = 465
use_ssl = true
start_ssl = false
verify_ssl = true
description, save_to_sent, and sent_folder_name are optional. Remove the
entire [emails.outgoing] table for an IMAP-only account.
When credentials are stored in the operating system keyring, password values in
this file are replaced by the reserved __KEYRING__ marker. Do not enter that
value as a real password. See Credential storage.
Multiple accounts¶
Add one [[emails]] entry per account:
[[emails]]
account_name = "personal"
full_name = "John Doe"
email_address = "[email protected]"
[emails.incoming]
user_name = "[email protected]"
password = "personal-password"
host = "imap.example.com"
port = 993
use_ssl = true
start_ssl = false
verify_ssl = true
[[emails]]
account_name = "work"
full_name = "John Doe"
email_address = "[email protected]"
[emails.incoming]
user_name = "[email protected]"
password = "work-password"
host = "imap.company.example"
port = 993
use_ssl = true
start_ssl = false
verify_ssl = true
Every account_name must be unique across the configuration. MCP tools use this
name to select an account.
The environment variable interface describes one account. Use TOML or the UI when persistent configuration requires multiple accounts.
TLS modes¶
Each IMAP or SMTP server has three related fields:
| Mode | use_ssl |
start_ssl |
Typical port |
|---|---|---|---|
| Implicit TLS | true |
false |
IMAP 993, SMTP 465 |
| STARTTLS | false |
true |
IMAP 143, SMTP 587 |
| Plain connection, insecure | false |
false |
Trusted local or isolated networks only |
Do not enable both implicit TLS and STARTTLS for the same server. Keep
verify_ssl = true unless connecting to a trusted local service with a
self-signed certificate.
Without implicit TLS or STARTTLS, credentials and message content can travel in
plaintext, and verify_ssl has no effect. Do not use a plain connection to a
remote mail service. Limit it to a trusted local bridge, an encrypted tunnel,
or an otherwise isolated network.
IMAP-only accounts¶
SMTP configuration is optional. The MCP tool catalog is static, so send_email
and forward_email are still advertised when every account omits SMTP; a call
for an IMAP-only account fails its capability check before SMTP access.
forward_email is a send even though it begins by reading a message over IMAP,
so it also requires SMTP and cannot be used with an IMAP-only account. Its
source read is attempted only after that capability check.
IMAP-only does not mean read-only. These tools can still change mailbox state:
save_to_mailboxset_email_flagsmark_emails_as_readmove_emailsarchive_emailsdelete_emails
See IMAP-only accounts for examples.
Saving sent email¶
After SMTP delivery, save_to_sent = true asks the server to append the sent
message to an IMAP Sent folder. This is enabled by default.
The server attempts to detect common folders, including:
SentINBOX.SentSent ItemsSent Mail[Gmail]/Sent Mail
Set a custom folder when auto-detection is not suitable:
[[emails]]
account_name = "work"
save_to_sent = true
sent_folder_name = "INBOX.Sent"
Set save_to_sent = false to disable the IMAP append after sending. The
environment equivalents are MCP_EMAIL_SERVER_SAVE_TO_SENT and
MCP_EMAIL_SERVER_SENT_FOLDER_NAME.
Outgoing message headers¶
Every outgoing MIME message carries a single top-level MIME-Version: 1.0
header. The configured full name is an RFC 5322 display name: punctuation such as
@, commas, and quotes is safely quoted, while non-ASCII display text paired with
an ASCII addr-spec is encoded without forcing SMTPUTF8. SMTP MAIL FROM always
uses the separate configured account email address as its RFC 5321 reverse-path.
An internationalized addr-spec or thread-header identifier requires SMTPUTF8 for
delivery and RFC 6855 UTF8 support for Draft or Sent-copy APPEND. RFC 6531 also
requires the SMTP server to advertise 8BITMIME and the client to request
BODY=8BITMIME whenever SMTPUTF8 is used. Drafts and Sent copies use the same
correctly formatted From header and fail before APPEND when the provider cannot
negotiate the required UTF8 mode.
The server also adds User-Agent: mcp-email-server and
X-Mailer: mcp-email-server as de-facto application identifiers for
compatibility with providers that inspect sender-software identification. These
identifiers are fixed and contain no account-specific information.
Global settings¶
| Setting | Default | Description |
|---|---|---|
credential_storage |
"auto" |
Select auto, keyring, or plaintext credential storage. |
enable_attachment_download |
false |
Allow download_attachment to write files. |
allowed_recipients |
[] |
Exact recipients; empty disables sending and recipient-bound saves. |
allowed_senders |
[] |
Incoming From patterns; empty does not restrict reading. |
report_blocked_mutations |
false |
Report blocked message IDs instead of returning privacy-preserving no-ops. |
See Security before enabling attachment downloads or applying allowlists.
Environment variable reference¶
Account variables¶
| Variable | Default | Required | Description |
|---|---|---|---|
MCP_EMAIL_SERVER_ACCOUNT_NAME |
default |
No | Account identifier used by MCP tools. |
MCP_EMAIL_SERVER_FULL_NAME |
Email local part | No | Display name used in outgoing messages. |
MCP_EMAIL_SERVER_EMAIL_ADDRESS |
None | Yes | Account email address. |
MCP_EMAIL_SERVER_USER_NAME |
Email address | No | Shared IMAP and SMTP username. |
MCP_EMAIL_SERVER_PASSWORD |
None | Yes | Shared password and required environment-account trigger. |
MCP_EMAIL_SERVER_IMAP_HOST |
None | Yes | IMAP server host. |
MCP_EMAIL_SERVER_IMAP_PORT |
993 |
No | IMAP server port. |
MCP_EMAIL_SERVER_IMAP_SSL |
true |
No | Use implicit TLS for IMAP. |
MCP_EMAIL_SERVER_IMAP_START_SSL |
false |
No | Upgrade the IMAP connection with STARTTLS. |
MCP_EMAIL_SERVER_IMAP_VERIFY_SSL |
true |
No | Verify the IMAP TLS certificate. |
MCP_EMAIL_SERVER_IMAP_USER_NAME |
Shared username | No | IMAP-specific username. |
MCP_EMAIL_SERVER_IMAP_PASSWORD |
Shared password | No | Non-empty IMAP-specific password; empty uses shared. |
MCP_EMAIL_SERVER_SMTP_HOST |
None | No | SMTP server host; enables sending when present. |
MCP_EMAIL_SERVER_SMTP_PORT |
465 |
No | SMTP server port. |
MCP_EMAIL_SERVER_SMTP_SSL |
true |
No | Use implicit TLS for SMTP. |
MCP_EMAIL_SERVER_SMTP_START_SSL |
false |
No | Upgrade the SMTP connection with STARTTLS. |
MCP_EMAIL_SERVER_SMTP_VERIFY_SSL |
true |
No | Verify the SMTP TLS certificate. |
MCP_EMAIL_SERVER_SMTP_USER_NAME |
Shared username | No | SMTP-specific username. |
MCP_EMAIL_SERVER_SMTP_PASSWORD |
Shared password | No | Non-empty SMTP-specific password; empty uses shared. |
MCP_EMAIL_SERVER_SAVE_TO_SENT |
true |
No | Append sent messages to an IMAP Sent folder. |
MCP_EMAIL_SERVER_SENT_FOLDER_NAME |
Auto-detected | No | Override the Sent folder name. |
Boolean values accept true, 1, yes, or on as true, ignoring case. Other
values are treated as false. Do not add surrounding whitespace to these values.
Global variables¶
| Variable | Default | Description |
|---|---|---|
MCP_EMAIL_SERVER_CONFIG_PATH |
~/.config/mcp-email-server/config.toml |
Use a custom TOML path. |
MCP_EMAIL_SERVER_ENABLE_ATTACHMENT_DOWNLOAD |
false |
Override attachment download access. |
MCP_EMAIL_SERVER_ALLOWED_RECIPIENTS |
Empty | Comma-separated recipients; empty disables sending. |
MCP_EMAIL_SERVER_ALLOWED_SENDERS |
Empty | Comma-separated sender globs; empty does not restrict reading. |
MCP_EMAIL_SERVER_REPORT_BLOCKED_MUTATIONS |
false |
Override blocked mutation reporting. |
MCP_EMAIL_SERVER_CREDENTIAL_STORAGE |
TOML value or auto |
Override credential storage with auto, keyring, or plaintext. |
MCP_EMAIL_SERVER_LOG_LEVEL |
INFO |
Set the Loguru logging level, such as DEBUG or WARNING. |
HTTP transport variables are documented separately in Transports.
In managed mode, MCP_EMAIL_SERVER_CONFIG_PATH still selects the legacy source
path from which the bootstrap sidecar path is derived, but legacy account,
allowlist, attachment, mutation-reporting, and credential-storage overlays do
not replace managed catalog values.
Reset configuration¶
Delete the configuration file and perform best-effort cleanup of referenced keyring entries with:
mcp-email-server reset --confirm RESET
In legacy mode this operation removes all persistently configured accounts from
the legacy source. The independent bootstrap sidecar is retained, including any
managed catalog selected for a future restart; reset never needs to rewrite the
source to preserve that authority. Environment-based configuration remains
effective as long as its variables are present. In managed mode reset is rejected
before any TOML, database, or keyring mutation; select legacy and restart before
intentionally resetting the legacy source. An unparseable bootstrap sidecar also
fails closed because its selected mode cannot be established safely. Resetting a
truly absent source with no sidecar creates no directory or lock artifact. A
newly created legacy configuration parent uses 0700 on POSIX, while an existing
legacy parent is not silently changed.