Skip to main content
Glama
trekmail

TrekMail MCP Server

Official
by trekmail
README.md
# TrekMail MCP Server

A Model Context Protocol (MCP) server that exposes the TrekMail API v1 as 280 agent tools. This is a thin adapter — all business logic lives in the TrekMail API; this server handles transport, authentication, retries, and safety gates.

## Connect in Claude

For the hosted service, open [TrekMail in the Claude directory](https://claude.ai/directory/connectors/trekmail), select **Connect**, sign in to TrekMail and approve the requested permissions. TrekMail is published as a **Community** connector. Available tools depend on the connected account's plan and permissions.

For a **White Label** dashboard, add a custom connector using the MCP URL shown in that dashboard and your own brand name. The shared TrekMail listing signs in on TrekMail and does not replace your branded connection.

See the [connection guide](https://trekmail.net/docs/ai-agents-api/connecting-ai-agents) for other clients. The npm and Docker instructions below run the MCP adapter locally; the adapter still calls your configured TrekMail API.

## Quickstart

### npm

```bash
git clone https://github.com/trekmail/mcp-server trekmail-mcp
cd trekmail-mcp
npm install
npm run build

TREKMAIL_BASE_URL=https://trekmail.net \
TREKMAIL_API_TOKEN=tm_live_your_token \
npm start
```

### Docker

```bash
git clone https://github.com/trekmail/mcp-server trekmail-mcp
cd trekmail-mcp
docker build -t trekmail-mcp .

docker run -i \
  -e TREKMAIL_BASE_URL=https://trekmail.net \
  -e TREKMAIL_API_TOKEN=tm_live_your_token \
  trekmail-mcp
```

## Dual-Token Architecture

The MCP server supports two independent token types. At least one is required:

| Token | Env Var | Prefix | Unlocks |
|-------|---------|--------|---------|
| **Ops token** | `TREKMAIL_API_TOKEN` | `tm_live_` | 216 infrastructure tools (White Label branding, clients, team access and activity; domains; DNS; mailboxes; Drive; migrations; SMTP; tickets; account; billing; verifier; Cloudflare; and related administration) |
| **Message token** | `TREKMAIL_MESSAGE_TOKEN` | `tm_msg_` | 64 message tools (messages, attachments, drafts, bulk actions, folders, scheduled send, contacts, contact groups, calendar, compose helpers, connected accounts, identities, templates, blocked senders) |

Tools are registered conditionally — only token types you provide get their tools. You can supply one or both:

```bash
# Infrastructure only
TREKMAIL_API_TOKEN=tm_live_your_token npm start

# Messages only
TREKMAIL_MESSAGE_TOKEN=tm_msg_your_token npm start

# Both
TREKMAIL_API_TOKEN=tm_live_your_token \
TREKMAIL_MESSAGE_TOKEN=tm_msg_your_token \
npm start
```

## Environment Variables

| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `TREKMAIL_BASE_URL` | Yes | — | Your TrekMail instance URL |
| `TREKMAIL_API_TOKEN` | At least one token | — | Ops token (must start with `tm_live_`) |
| `TREKMAIL_MESSAGE_TOKEN` | At least one token | — | Message token (must start with `tm_msg_`) |
| `TREKMAIL_TIMEOUT_MS` | No | `30000` | Request timeout in milliseconds |
| `TREKMAIL_USER_AGENT` | No | `trekmail-mcp/1.12.0` | User-Agent header |
| `TREKMAIL_ALLOW_DESTRUCTIVE` | No | `false` | Enable high-impact changes (White Label access/branding, delete intents, domain deletion, forwarding, password changes, SMTP, credential revocation, Drive trash/purge, and message deletion) |
| `TREKMAIL_ALLOW_SENDING` | No | `false` | Enable external sends, including `send_message` and White Label invitations |
| `TREKMAIL_ALLOW_MIGRATION` | No | `false` | Enable migration write tools (`start_migration`, `retry_migration`, `delete_migration`, `delete_bulk_migration`, `update_bulk_migration_job_password`, `test_migration_connection`) |
| `TREKMAIL_TOOLSETS` | No | all | Comma-separated product sets to register, for example `email` or `email,contacts,calendar` |
| `TREKMAIL_SCOPE_AWARE_REGISTRATION` | No | `true` | Discover the token's effective capabilities at startup and omit unusable tool schemas; set `false` only as a compatibility escape hatch |
| `TREKMAIL_READ_ONLY` | No | `false` | Register read tools only, even when the token can write |

Tool visibility is the intersection of token capability, `TREKMAIL_TOOLSETS`,
`TREKMAIL_READ_ONLY`, and transport support. Runtime API authorization remains
authoritative. Account Drive and Mailbox Drive deliberately share one `drive`
toolset; all White Label capabilities share `white_label`. The concrete resource,
membership, entitlement, and token constraints decide what a call can access.
Compact email, contacts, calendar, and email-settings selections also include
the existing read-only `list_mailboxes` tool so an agent can discover the
required mailbox ID without loading the full administration toolset.

For a normal mailbox project, this is the compact configuration:

```bash
TREKMAIL_MESSAGE_TOKEN=tm_msg_your_token \
TREKMAIL_TOOLSETS=email \
TREKMAIL_SCOPE_AWARE_REGISTRATION=true \
npm start
```

## Tools (280)

> The full catalog is **280** tools over stdio. On the hosted **HTTP** transport
> `drive_file_upload` is intentionally not registered (its `local_path` would read
> files on our server — see the note in `src/tools/drive.ts`), so the HTTP MCP
> exposes 279. Tools also split by token type: **64** need a message token
> (`tm_msg_`), the rest an ops token (`tm_live_`).
> These are full catalog totals. A directory profile or a restricted grant can
> expose a smaller set, including browser handoffs for sensitive setup.
>
> **Safety gates apply to the whole list, not just the rows that say so.** Read
> tools are always registered; every tool that creates, changes or deletes
> something needs `TREKMAIL_ALLOW_DESTRUCTIVE=true`, the sending tools need
> `TREKMAIL_ALLOW_SENDING`, and the migration test tools need
> `TREKMAIL_ALLOW_MIGRATION`. Some entries below repeat their gate inline — the
> absence of that note does not mean a tool is ungated.

### Domains (ops token)
- **list_domains** — List domains with optional status/search filters
- **get_domain** — Get details for a specific domain
- **get_domain_connect_setup** — Check one-time Cloudflare DNS setup eligibility and return a browser handoff URL only when available; otherwise return blockers. Read-only; no API token or DNS change
- **get_domain_alias** — Check a domain's saved receive-only alias connection and whether it is delivering now
- **set_domain_alias** — Route matching addresses on this domain to a primary domain (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **remove_domain_alias** — Disconnect the domain alias after `confirm_remove: true` (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **create_domain** — Add a new domain to the account. `mail_hosting: "external"` registers it as a sending-only domain: no MX record is asked for, it holds no mailboxes, and it serves purely as a verified From address
- **delete_domain** — Delete a domain (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **update_domain_catch_all** — Configure or clear the catch-all address
- **set_domain_mail_hosting** — Choose whether TrekMail hosts the domain's incoming mail or only sends for it. Switching to `external` stops its mailboxes receiving, so it needs `confirm_mailboxes_stop_receiving: true`
- **list_forwarding_addresses** — List mailbox-less forwarding addresses on a domain, with recipients, the per-domain limit, and whether the plan currently delivers them. Pro includes **100/domain**; Agency includes **300/domain**
- **get_forwarding_address_log** — Recent deliveries for one address: sender, destination, and outcome (delivered / deferred / rejected / blocked as spam before forwarding). Pro retains 7 days; Agency retains 30
- **create_forwarding_address** — Create a forwarding address — no mailbox, no storage. Delivery requires Pro or Agency; Nano and Starter keep saved rules inactive until upgrade (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **update_forwarding_address** — Replace recipients, or pause / resume an address (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **delete_forwarding_address** — Delete a forwarding address (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **retry_domain_dkim** — Retry DKIM key provisioning
- **update_domain_note** — Update the admin note on a domain
- **get_domain_signature** — Read per-domain email signature settings (mode, position, HTML)
- **update_domain_signature** — Set per-domain signature (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **bulk_add_domains** — Add up to 20 domains in one call

### DNS (ops token)
- **get_dns_requirements** — Get required DNS records for a domain
- **dns_recheck** — Trigger async DNS verification (returns check ID)
- **get_dns_check** — Poll DNS check status/results

### White Label (ops token)

These 20 tools are omitted unless White Label entitlement and the token's live
scopes allow them. During cancellation grace, only the owner keeps read tools;
writes and delegated access are removed.

- **get_domain_branding** — Read a domain's brand, assets, hosts, mail zone, and required DNS records
- **set_domain_branding** — Partially update domain or account-default branding (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **set_domain_brand_logo** — Upload a base64 PNG/JPEG/ICO brand asset (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **verify_domain_branding_dns** — Queue DNS and certificate verification (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **create_branding_preview** — Create a short-lived branded preview (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **remove_domain_brand_logo** — Remove a brand asset (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **remove_domain_branding** — Clear domain or account-wide branding (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **get_white_label** — Read entitlement, setup progress, account brand, and reachable domain status
- **get_white_label_access_catalog** — Read roles, permissions, and domains this caller may grant
- **list_white_label_members** — Search or filter clients, members, and invitations
- **get_white_label_member** — Read one member, effective permissions, and allowed operations
- **invite_white_label_member** — Create and email an invitation (gated: `TREKMAIL_ALLOW_SENDING`)
- **update_white_label_member** — Change role, domains, permissions, or note (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **suspend_white_label_member** — Stop access and revoke the member's keys (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **resume_white_label_member** — Resume a suspended membership without restoring old keys (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **resend_white_label_invitation** — Replace and email a pending invitation (gated: `TREKMAIL_ALLOW_SENDING`)
- **remove_white_label_member** — Remove access after explicit confirmation (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **restore_white_label_member** — Restore membership without restoring old keys (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **list_white_label_activity** — Read White Label account activity
- **get_white_label_member_activity** — Read one member's actions and sign-in history

### Mailboxes (ops token)
- **list_mailboxes** — List mailboxes with optional domain/search filters
- **get_mailbox** — Get details for a specific mailbox, including `client_auth_mode` (what mail apps may sign in with) where app passwords are available
- **get_mail_client_setup** — Get password-free IMAP/SMTP settings, actual sending readiness, localized guides for five app families, and delegated shared-mailbox folders for a regular member mailbox; `authentication.password_source` and `accepted_passwords` say whether the mail app takes the mailbox password or an app password
- **get_apple_mail_profile** — Generate a password-free Apple Mail `.mobileconfig` file as Base64 (13 locales)
- **create_mailbox_generated_password** — Create mailbox with auto-generated one-time password (optional `storage_allocation_mb` carves out dedicated storage from the account pool; omit for shared). Optional `client_auth_mode`; on an `app_password_only` mailbox the generated password opens TrekMail webmail only, so mail apps (classic webmail included) need **create_mailbox_app_password** next
- **change_mailbox_password** — Change the password for a mailbox; while app passwords are enabled, resetting the mailbox password automatically revokes all its app passwords (`mailbox_password_reset`) (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **update_mailbox** — Update a mailbox display name, a regular mailbox's webmail `conversation_view` preference, or its `drive_access` level (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **set_mailboxes_drive_access** — Set `drive_access` on many mailboxes at once, chosen by explicit `mailbox_ids`, by `domain_id`, or `all`; shared mailboxes are skipped and counted (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **suspend_mailbox_login** — Stop someone signing in to a mailbox while its mail keeps arriving: webmail/IMAP/SMTP and device passwords refused, open sessions ended, reset links dead, delivery untouched (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **resume_mailbox_login** — Lift a sign-in suspension; device passwords revoked by it are not restored (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **set_mailboxes_login_access** — Suspend or restore sign-in on many mailboxes, chosen by explicit `mailbox_ids`, by `domain_id`, or `all`; shared, paused and trashed mailboxes are skipped and counted (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **list_mailbox_app_passwords** — List a mailbox's app passwords (name, created, last used, revoked) and its `client_auth_mode`; secrets are never returned
- **create_mailbox_app_password** — Create an app password for one mail app (IMAP, SMTP, ManageSieve, CalDAV/CardDAV): 16 letters returned once, up to 25 active per mailbox; never opens TrekMail webmail, though classic webmail takes it like any IMAP app (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **rotate_mailbox_app_password** — Replace an app password with a new secret under the same name; the old one stops working at once (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **revoke_mailbox_app_password** — Revoke an app password for good and sign out the app using it (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **set_mailbox_client_auth_mode** — Set one mailbox (`mailbox_id`) or a bulk selection (`mailbox_ids`, `domain_id` or `all`) to `app_password_only` (mail apps, classic webmail included, need an app password; TrekMail webmail keeps the mailbox password) or `password_or_app_password` (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **update_mailbox_note** — Update the admin note on a mailbox
- **pause_mailbox** — Disable a mailbox entirely, delivery included — unlike `suspend_mailbox_login` (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **resume_mailbox** — Re-enable a paused mailbox
- **enable_imap** — Enable IMAP access for a mailbox (required for Message API)
- **bulk_create_mailboxes** — Create 1-100 mailboxes at once with per-item `storage_allocation_mb` (sum across the batch is validated against the available pool)

### Invites (ops token)
- **create_invite** — Send a setup invite to a recipient (optional `storage_allocation_mb` pre-allocates dedicated storage; the recipient inherits it at redeem)
- **create_invites_bulk** — Send up to 100 setup invites in one call (per-item `storage_allocation_mb` supported)

### Aliases (ops token)
- **list_aliases** — List all aliases for a mailbox (includes primary address and plan limits)
- **create_alias** — Add an alias to a mailbox (cross-domain supported, Starter+ plans)
- **update_alias** — Toggle receiving, sending, or active/inactive status
- **delete_alias** — Permanently remove an alias (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)

### Shared Mailbox Members (ops token)
- **list_shared_mailbox_members** — List members and their flat `can_read` / `can_send` permissions; membership grants Webmail and, when enabled, delegated native IMAP access
- **add_shared_mailbox_member** — Add an existing regular mailbox; `can_send` defaults to true (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **update_shared_mailbox_member** — Toggle send-as permission or set the member's personal Webmail label; retryable native-sync failures preserve the old permission (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **remove_shared_mailbox_member** — Revoke Webmail/native access without deleting the member mailbox; the last member cannot be removed (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)

Shared mailboxes never authenticate directly. Call **get_mail_client_setup** with a regular member mailbox id, wait for `native_access_ready=true` and (for sending) `send_as_ready=true`, then inspect `shared_mailboxes.items[]` for exact Inbox/Sent/Archive/Junk paths and allowed operations. SMTP does not save a Sent copy; configure the client to append it to the returned shared Sent folder.

### Shared Mailbox Lifecycle (ops token)
- **create_shared_mailbox** — Create a shared mailbox with a required display name and one or more regular member mailbox ids (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **convert_mailbox_to_shared** — Rotate a regular mailbox's credential, disable direct login, and assign members (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **convert_shared_mailbox_to_regular** — Revoke every member's Webmail/native access and set a fresh direct-login password; a retryable native-sync failure leaves it shared (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)

### Forwarding (ops token)
- **get_forwarding** — Read the current forwarding config for a mailbox. Returns the `targets` array (one or more destinations), `keep_copy`, and `destination_limit` (the plan-tier cap so the agent can preflight an `set_forwarding` call without trial-and-error).
- **set_forwarding** — Configure one or more forwarding destinations for a mailbox, plus enable/disable and keep-copy. The `targets` array accepts up to 30 entries client-side; the server enforces the actual per-plan cap — Starter **5**, Pro **15**, Agency **30** — and returns a 422 `limit_exceeded` error with the cap if you pass more. CRLF / loop / self-forward / MX validation is run per destination, so a single bad entry rejects the whole save.

### Mail Filters (ops token)
- **list_mail_rules** — List all mail filters for a mailbox
- **get_mail_rule** — Get a single mail filter by ID
- **create_mail_rule** — Create a new filter with conditions and actions
- **update_mail_rule** — Update an existing filter
- **delete_mail_rule** — Delete a filter (requires `TREKMAIL_ALLOW_DESTRUCTIVE=true`)
- **reorder_mail_rules** — Change filter execution order

### Auto-Reply (ops token)
- **get_auto_reply** — Get vacation auto-reply settings for a mailbox
- **set_auto_reply** — Configure auto-reply subject, message, dates, and list skipping

### Sieve (ops token)
- **get_sieve_script** — Get the raw Sieve script for a mailbox
- **upload_sieve_script** — Upload a raw Sieve script for a mailbox

### Delete Intents (ops token, two-step)
- **create_delete_intent** — Step 1: create a time-limited delete intent
- **confirm_delete_intent** — Step 2: confirm and execute deletion (irreversible)

### Messages (message token)

> Many message tools accept an optional **`external_account_id`** to operate on a
> connected external mailbox (Gmail/Outlook/IMAP) instead of the primary mailbox.
> The id is always scoped to the token's mailbox (cross-mailbox access is
> impossible); discover valid ids with `list_external_accounts`. Supported on:
> `list_messages`, `read_message`, `send_message`, `move_message`,
> `update_message_flags`, `delete_message`, `list_folders`, `download_attachment`,
> `download_all_attachments`, `get_raw_message`, `save_draft`, `update_draft`, and
> `bulk_action` (native actions only: read/unread/star/unstar/delete/move).
> `report_spam`/`report_ham` (and `bulk_action` spam/notspam) train THIS server's
> spam filter, which doesn't apply to a remote provider, so they reject
> `external_account_id` — move to the provider's Junk folder instead.

- **list_messages** — List messages in a mailbox folder with cursor pagination (optional `external_account_id`)
- **read_message** — Get a single message by IMAP UID with full body (optional `external_account_id`)
- **send_message** — Send an email from the mailbox — or, with `external_account_id`, from a connected account via its own SMTP, or, with `shared_mailbox_id`, as a shared team mailbox the acting member holds send permission on (dual safety gates, validates total recipients ≤ 10, requires body). The mailbox's Default CC/BCC apply exactly as they do in the web app; pass `apply_default_recipients: false` to skip them for one message. Returns once the message is accepted, not sent — confirm with `get_message_delivery`. A used-up sending allowance fails at once with `sending_limit_exceeded`, naming the allowance and when it renews (`resets_at`); it is never worth retrying before then
- **get_message_delivery** — What happened to a message `send_message` accepted (pending, sending, sent, failed, delivery_uncertain), looked up by the `request_id` it returned; a message refused by a sending allowance reports which one and when it renews. Works with any message token for the same mailbox, not only the one that sent the message, so a later hosted session or a renewed token can check an earlier send; an unknown `request_id` is a 404
- **get_mailbox_sending_limits** — How many more recipients this mailbox can send to today (`remaining_today`), the most recipients one message may have, when the allowance renews, and the API's own caps for this token. While the lowest allowance is the account-wide total, `limit_today` is `null` and so is `remaining_today` until that total is spent (then `0`); an ops token reads the total with `get_sending_limits`
- **delete_message** — Permanently delete a message by IMAP UID (requires `TREKMAIL_ALLOW_DESTRUCTIVE=true`)
- **move_message** — Move a message to a different IMAP folder
- **list_folders** — List all IMAP folders for the mailbox
- **update_message_flags** — Update flags (read/unread, starred/unstarred) on a message
- **download_attachment** — Download a single attachment by index from a message
- **download_all_attachments** — Download all attachments as a ZIP archive
- **get_raw_message** — Get the full RFC 822 raw source of a message
- **save_draft** — Save a new draft via IMAP APPEND; returns its `uid` and `uidvalidity` for later updates
- **update_draft** — Replace a draft using its required `uid` and `uidvalidity`; returns the replacement pair because the old UID stops working
- **report_spam** — Report a message as spam (trains Rspamd Bayesian filter)
- **report_ham** — Mark a message as not spam (trains Rspamd Bayesian filter)
- **bulk_action** — Perform a bulk action on up to 50 messages (read, unread, star, unstar, delete, move, spam, notspam)

### Connected accounts (message token)
Connect and manage external mailboxes (Gmail/Outlook/IMAP) the mailbox reads and sends through. Credentials are never returned by any tool.
- **list_external_accounts** — List connected external accounts (id, email, provider, status) — the source of valid `external_account_id` values
- **detect_external_account** — Detect provider preset (host/port/encryption, app-password vs OAuth) from an email address
- **test_external_account** — Test unsaved IMAP/SMTP credentials without persisting (requires `TREKMAIL_ALLOW_MIGRATION=true`)
- **create_external_account** — Connect an external account (test-gated; requires `TREKMAIL_ALLOW_DESTRUCTIVE=true`)
- **update_external_account** — Update a connected account's settings/credentials (requires `TREKMAIL_ALLOW_DESTRUCTIVE=true`)
- **test_saved_external_account** — Re-test a saved account and lift its circuit breaker (requires `TREKMAIL_ALLOW_MIGRATION=true`)
- **delete_external_account** — Remove a connected account and its stored credentials (requires `TREKMAIL_ALLOW_DESTRUCTIVE=true`)

### Folders (message token)
- **create_folder** — Create a new IMAP folder
- **rename_folder** — Rename an existing IMAP folder
- **delete_folder** — Delete a leaf IMAP folder and its messages; child folders must be deleted explicitly first (requires `TREKMAIL_ALLOW_DESTRUCTIVE=true`)
- **empty_folder** — Empty all messages from a folder without deleting the folder

### Scheduled Messages (message token)
- **schedule_message** — Schedule a message to be sent at a future time (optional IANA `timezone` resolves naïve datetimes; explicit ISO offset always wins). Default CC/BCC are applied and stored with the message, so `list_scheduled` shows what will actually go out; `apply_default_recipients: false` opts out; pass `shared_mailbox_id` to schedule as a shared team mailbox you may send as
- **list_scheduled** — List pending scheduled messages
- **reschedule_message** — Re-time a pending scheduled message in place (no resend, lighter throttle than schedule + cancel)
- **cancel_scheduled** — Cancel a scheduled message before it sends

### Contacts (message token)
- **list_contacts** — List contacts with optional search
- **create_contact** — Create a new contact
- **update_contact** — Update a contact's details
- **delete_contact** — Delete a contact (requires `TREKMAIL_ALLOW_DESTRUCTIVE=true`)
- **import_contacts** — Import contacts from CSV or VCF data
- **export_contacts** — Export all contacts as VCF

### Contact Groups (message token)
- **list_contact_groups** — List contact groups
- **list_contact_group_members** — List the contacts in a group (paginated)
- **create_contact_group** — Create a new contact group
- **update_contact_group** — Rename or update a contact group
- **delete_contact_group** — Delete a contact group (requires `TREKMAIL_ALLOW_DESTRUCTIVE=true`)
- **add_contact_group_members** — Add contacts to a group
- **remove_contact_group_members** — Remove contacts from a group

### Calendar (message token)
- **list_calendar_events** — List calendar events with optional date range filter
- **create_calendar_event** — Create a new calendar event
- **update_calendar_event** — Update an existing calendar event
- **delete_calendar_event** — Delete a calendar event (requires `TREKMAIL_ALLOW_DESTRUCTIVE=true`)

### Compose Helpers (message token)
- **prepare_reply** — Get pre-filled reply data (quoted body, headers) for a message
- **prepare_reply_all** — Get pre-filled reply-all data for a message
- **prepare_forward** — Get pre-filled forward data for a message

### Identities (message token)
- **list_identities** — List source-specific From addresses, connected-inbox Send As identities, reply policy, eligible domains, and permitted profiles; pass `shared_mailbox_id` for the addresses of a shared mailbox you may send as
- **create_identity** — Configure a managed From address, or create a Send As identity: pass `external_account_id` when that address's mail is read through a connected inbox, omit it when the mail is forwarded into this TrekMail mailbox instead
- **update_identity** — Update an identity's display name, signature, reply-to, default flag, or Send As route
- **delete_identity** — Delete a Send As identity (requires `TREKMAIL_ALLOW_DESTRUCTIVE=true`)
- **set_reply_from_policy** — Reply from the recipient address when possible, or always start from the default (requires `TREKMAIL_ALLOW_DESTRUCTIVE=true`)

### Templates (message token)
- **list_templates** — List message templates
- **create_template** — Create a new message template
- **update_template** — Update a message template
- **delete_template** — Delete a message template (requires `TREKMAIL_ALLOW_DESTRUCTIVE=true`)

### Blocked Senders (message token)
- **list_blocked_senders** — List blocked sender addresses
- **block_sender** — Block a sender address (moves future mail to Junk)
- **unblock_sender** — Unblock a sender address

### SMTP (ops token)
- **get_smtp_config** — View current SMTP mode and connection details
- **update_smtp_config** — Update SMTP configuration (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **delete_smtp_connection** — Delete a custom SMTP connection (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **test_smtp** — Start an async SMTP connection test (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **get_smtp_test_status** — Poll SMTP test results

> The five tools above are the legacy account-level SMTP controls — **deprecated for routing** (kept for back-compat only). Use the per-domain SMTP routing + account-default tools below for outbound delivery configuration.

### Domain SMTP Routing (ops token)
- **get_domain_smtp** — Get a domain's outbound route (mode + selected profile; `effective_smtp_mode` resolves `inherit` to the account default)
- **set_domain_smtp** — Set a domain's route: `platform` (managed) / `profile` (saved profile) / `not_configured` / `inherit` (follow the account default) (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **list_domain_smtp_profiles** — List the account's reusable saved SMTP profiles plus per-profile usage counts
- **get_domain_smtp_profile_usage** — List the exact domains and Send As addresses using one profile; credentials are never returned
- **create_domain_smtp_profile** — Create a reusable SMTP profile and apply it to a domain — stores credentials (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **update_domain_smtp_profile** — Update a saved profile (affects every domain using it) (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **delete_domain_smtp_profile** — Delete a saved profile (domains using it are reassigned) (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **test_domain_smtp** — Test a route, connects out (returns `job_id`) (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)
- **get_domain_smtp_test_status** — Poll a route test by `job_id`
- **get_account_smtp_default** — Get the account-wide default route new domains start on (`default_smtp_mode` + `effective_default_smtp_mode` plan-baseline fallback)
- **set_account_smtp_default** — Set the account-wide default (`platform` / `profile` / `not_configured`); optional `apply_to_all` switches every existing domain now (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)

### Tickets (ops token)
- **list_tickets** — List support tickets with optional status/category filters
- **get_ticket** — Get ticket details
- **get_ticket_messages** — Get all messages in a ticket conversation
- **create_ticket** — Create a new support ticket
- **reply_to_ticket** — Reply to an existing ticket
- **close_ticket** — Close a ticket

### Account (ops token)
- **whoami** — Get current token info and permissions
- **get_account** — Get account details, plan, limits, usage, and `new_mailbox_client_auth_mode` when both app passwords and the platform default for new mailboxes are enabled
- **update_account** — Set `new_mailbox_client_auth_mode` for future mailboxes; existing mailboxes retain their mode. Owner-only; requires `mailboxes:write`, both platform flags, and `TREKMAIL_ALLOW_DESTRUCTIVE`
- **get_sending_limits** — Today's sending allowance for the whole account: plan numbers after trial or first-payment caps, domains still in their first-week warm-up (and when they step up), what the first payment would change, and today's usage including forwarded mail
- **get_billing_status** — Get billing and subscription info
- **list_invoices** — List invoice history

### Message Token Management (ops token)
- **create_message_token** — Create a message API token for a mailbox (returns plaintext once)
- **list_message_tokens** — List all message tokens for a mailbox
- **update_message_token** — Narrow a message token in place: drop scopes, bring its expiry forward or rename it (never widens)
- **revoke_message_token** — Revoke a message token (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)

### Migrations (ops token)
- **test_migration_connection** — Validate IMAP credentials and discover source folders with message counts
- **list_migrations** — List migrations with optional status/mailbox filters
- **get_migration** — Get detailed migration status including per-folder progress
- **start_migration** — Start a new email migration (gated: `TREKMAIL_ALLOW_MIGRATION` + `confirm_start=true`)
- **cancel_migration** — Cancel a running migration (always available — safety operation, requires `confirm_cancel=true`)
- **retry_migration** — Retry a failed or cancelled migration (gated: `TREKMAIL_ALLOW_MIGRATION` + `confirm_retry=true`)
- **delete_migration** — Delete a migration record (gated: `TREKMAIL_ALLOW_MIGRATION` + `confirm_delete=true`)

### Bulk Migrations (ops token)
- **preview_bulk_migration** — Validate and preview a bulk migration batch (gated: `TREKMAIL_ALLOW_MIGRATION`)
- **start_bulk_migration** — Start a bulk migration batch (gated: `TREKMAIL_ALLOW_MIGRATION` + `confirm_start=true`)
- **list_bulk_migrations** — List bulk migration batches with optional status filter
- **get_bulk_migration** — Get details of a bulk migration batch
- **cancel_bulk_migration** — Cancel an active bulk batch (requires `confirm_cancel=true`)
- **retry_bulk_migration** — Retry failed jobs in a batch (gated: `TREKMAIL_ALLOW_MIGRATION` + `confirm_retry=true`)
- **resume_bulk_migration** — Resume a paused batch (requires `confirm_resume=true`)
- **delete_bulk_migration** — Delete a terminal bulk migration batch (gated: `TREKMAIL_ALLOW_MIGRATION` + `confirm_delete=true`)
- **update_bulk_migration_job_password** — Update source password for a failed job (gated: `TREKMAIL_ALLOW_MIGRATION`)

### Spam Metrics (ops token)
- **get_spam_metrics** — Get daily spam protection metrics for a domain
- **get_spam_summary** — Get aggregated spam protection summary for a domain

### Email Verifier (ops token)
- **verify_email** — Verify a single email address
- **verify_email_bulk** — Submit a bulk verification job
- **verify_job_status** — Check job progress and results
- **verify_job_download** — Download job results as CSV
- **verify_credits** — Check remaining credit balance
- **verify_list_jobs** — List all verification jobs
- **verify_cancel_job** — Cancel a running job and refund unprocessed credits
- **verify_delete_job** — Permanently delete a job and all results (GDPR)

### Cloudflare (ops token)
- **validate_cloudflare_token** — Validate a Cloudflare API token
- **list_cloudflare_zones** — List DNS zones accessible by a Cloudflare token
- **connect_cloudflare_domains** — Connect domains to a Cloudflare account (creates new domains if needed)
- **preview_cloudflare_dns** — Preview DNS changes that would be applied via Cloudflare. Optional `included_records` (`{ domain_id: [record_ids] }`) previews only selected records
- **apply_cloudflare_dns** — Apply DNS changes to Cloudflare-managed zones. Use `included_records` to write only chosen records and skip the rest (e.g. MX now, DKIM later); omit it to apply all. `confirmed_conflicts` authorises replacing records flagged as conflicting
- **list_cloudflare_tokens** — List stored Cloudflare tokens
- **delete_cloudflare_token** — Delete a stored Cloudflare token (gated: `TREKMAIL_ALLOW_DESTRUCTIVE`)

## Idempotency

Mutating tools on idempotent API routes generate **deterministic idempotency keys** from `sha256(tool_name + canonical_params)`. This covers `POST`, `PUT`, `PATCH`, and `DELETE` White Label operations. It means:

- The same tool call with the same params always produces the same key
- Agent retries hit the API's idempotency cache — no duplicate side effects
- You can override with an explicit `idempotency_key` parameter on any mutating tool

**Drafts are the deliberate exception.** `save_draft` and `update_draft` generate a *fresh random*
key per call, so two identical calls really do save two drafts, and updating a draft back to earlier
content really does perform the update instead of replaying an old response. Pass your own
`idempotency_key` on those two tools when you want retry-dedup.

**A failed send is not replayed.** Once a `send_message` delivery has failed (on a sending limit,
for example), the API no longer answers the same call with the earlier accepted response, so the
same message with the same content can be sent again later. A retry of a send that is still
pending or was delivered still gets the original response.

## Safety

### Two-Step Delete
Mailbox deletion requires two separate tool calls:
1. `create_delete_intent` → returns intent with 10-minute expiry
2. `confirm_delete_intent` → executes deletion (irreversible)

### Destructive Operations Gate
Both delete tools require `TREKMAIL_ALLOW_DESTRUCTIVE=true`. Without it, they return an error message explaining how to enable.

The `confirm_delete_intent` tool has an additional `confirm: true` parameter that must be explicitly set.

### Sending Safety Gates
The `send_message` tool has **two independent safety gates** that must both pass:

1. **Environment gate:** `TREKMAIL_ALLOW_SENDING=true` must be set in the environment
2. **Per-call gate:** `confirm_send=true` must be passed as a parameter

This dual-gate design prevents accidental email sends. The agent must both be configured to allow sending and explicitly confirm each send.

### Migration Safety Gates
The `start_migration`, `retry_migration`, and `delete_migration` tools require `TREKMAIL_ALLOW_MIGRATION=true` in the environment. `cancel_migration` is always available as a safety operation. `test_migration_connection` requires the gate because it makes outbound IMAP connections. Read-only tools (`list_migrations`, `get_migration`) work without any gate.

Additionally, each write tool requires a per-call confirmation parameter (`confirm_start`, `confirm_cancel`, or `confirm_retry` set to `true`).

## Claude Desktop Configuration

```json
{
  "mcpServers": {
    "trekmail": {
      "command": "node",
      "args": ["/path/to/trekmail-mcp/build/index.js"],
      "env": {
        "TREKMAIL_BASE_URL": "https://trekmail.net",
        "TREKMAIL_API_TOKEN": "tm_live_your_token",
        "TREKMAIL_MESSAGE_TOKEN": "tm_msg_your_token",
        "TREKMAIL_ALLOW_SENDING": "true"
      }
    }
  }
}
```

## Claude Code Configuration

```json
{
  "mcpServers": {
    "trekmail": {
      "command": "node",
      "args": ["/path/to/trekmail-mcp/build/index.js"],
      "env": {
        "TREKMAIL_BASE_URL": "https://trekmail.net",
        "TREKMAIL_API_TOKEN": "tm_live_your_token",
        "TREKMAIL_MESSAGE_TOKEN": "tm_msg_your_token",
        "TREKMAIL_ALLOW_SENDING": "true"
      }
    }
  }
}
```

## Workflow Examples

### DNS Recheck Loop
```
1. dns_recheck(domain_id: 5) → { check_id: 42 }
2. get_dns_check(check_id: 42) → { status: "pending" }
3. (wait) get_dns_check(check_id: 42) → { status: "complete", results: {...} }
```

### Create Mailbox + Forwarding (single destination)
```
1. create_mailbox_generated_password(domain_id: 5, local_part: "alice")
   → { id: 10, email: "alice@example.com", password: "..." }
2. set_forwarding(mailbox_id: 10, enabled: true, targets: ["alice@gmail.com"], keep_copy: true)
```

### Set Up a Mail App on a Mailbox That Takes App Passwords Only
```
# The generated password opens TrekMail webmail; Outlook, phones and calendars
# need an app password. Hand the secret to the user once and do not keep it.
# Ask for the mode explicitly: without client_auth_mode a new mailbox gets the
# platform default, password_or_app_password until the account-level default
# is switched on. The response's client_auth_mode is what was applied.
1. create_mailbox_generated_password(domain_id: 5, local_part: "dana", client_auth_mode: "app_password_only")
   → { id: 12, email: "dana@example.com", client_auth_mode: "app_password_only", one_time_password: "..." }
2. create_mailbox_app_password(mailbox_id: 12, name: "Outlook on work laptop")
   → { data: { id: 31, name: "Outlook on work laptop", password: "abcdefghijklmnop" }, message: "Shown once. ..." }
3. get_mail_client_setup(mailbox_id: 12)
   → { authentication: { username: "dana@example.com", password_source: "app_password",
       accepted_passwords: ["app_password"], ... }, incoming: {...}, outgoing: {...} }
# Lost it later? rotate_mailbox_app_password(mailbox_id: 12, app_password_id: 31)
# returns a new secret and stops the old one at once.
```

### Create Mailbox + Multi-Destination Forwarding
```
# Fan one shared mailbox out to several humans.
1. create_mailbox_generated_password(domain_id: 5, local_part: "sales")
   → { id: 14, email: "sales@example.com", password: "..." }
2. get_forwarding(mailbox_id: 14)
   → { enabled: false, targets: [], keep_copy: false, destination_limit: 15 }   # Pro plan
3. set_forwarding(
     mailbox_id: 14,
     enabled: true,
     targets: ["alice@example.com", "bob@example.com", "carol@example.com"],
     keep_copy: true        # also leave a copy in sales@ for record-keeping
   )
```

### Create Mailbox with Dedicated Storage
```
# Carve out 5 GB just for this mailbox — other shared mailboxes can't grow into it.
1. create_mailbox_generated_password(
     domain_id: 5,
     local_part: "ceo",
     storage_allocation_mb: 5120
   ) → { id: 11, email: "ceo@example.com", password: "...", is_pooled_storage: false, storage_allocation_mb: 5120 }
```

### Bulk Create with Mixed Storage Modes
```
# Mix shared and dedicated in one call. The sum of all storage_allocation_mb
# across the batch is checked against the available pool — if it would
# over-commit, the entire batch is rejected with 422 storage_pool_exceeded.
1. bulk_create_mailboxes(items: [
     { domain_id: 5, local_part: "support" },                                  # shared
     { domain_id: 5, local_part: "founder",  storage_allocation_mb: 10240 },  # 10 GB dedicated
     { domain_id: 5, local_part: "team-lead", storage_allocation_mb: 5120 },  # 5 GB dedicated
   ])
```

### Invite Flow
```
1. create_invite(domain_id: 5, local_part: "bob", recipient_email: "bob@gmail.com")
   → { id: 1, status: "pending", invite_url: "..." }
```

### Invite with Pre-Allocated Storage
```
# Pending dedicated invites count against the available pool until they
# are redeemed or expire — no over-committing.
1. create_invite(
     domain_id: 5,
     local_part: "exec",
     recipient_email: "exec@external.com",
     storage_allocation_mb: 10240
   ) → { id: 2, status: "pending", storage_allocation_mb: 10240 }
# When the recipient redeems, the new mailbox inherits the 10 GB dedicated allocation.
# If the pool no longer fits at redeem time, the new mailbox falls back to shared
# (the recipient sees a notice on the success page) — redeem itself never fails.
```

### Safe Delete
```
1. create_delete_intent(mailbox_id: 10) → { id: 7, expires_at: "...", status: "pending" }
2. confirm_delete_intent(intent_id: 7, confirm: true) → { status: "confirmed" }
```

### Monitor Inbox
```
1. list_messages(folder: "INBOX", limit: 10, unread_only: true)
   → { messages: [...], pagination: { has_more: true, next_before_uid: 45 } }
2. read_message(uid: 50) → { from, subject, body_text, body_html, attachments: [...] }
```

### Email Migration
```
1. test_migration_connection(source_host: "imap.gmail.com", source_port: 993, source_security: "ssl", source_email: "user@gmail.com", source_password: "app-password")
   → { success: true, folders: { "INBOX": 1234, "Sent": 567, ... } }
2. start_migration(mailbox_id: 10, provider: "gmail", source_host: "imap.gmail.com", source_port: 993, source_security: "ssl", source_email: "user@gmail.com", source_password: "app-password", target_password: "mailbox-pass", confirm_start: true)
   → { id: 5, status: "pending", ... }
3. get_migration(id: 5) → { status: "processing", progress: 45, folders: [...] }
4. (poll) get_migration(id: 5) → { status: "completed", progress: 100, imported_messages: 1801 }
```

### Send Email with Confirmation
```
1. send_message(
     to: ["alice@example.com"],
     subject: "Weekly Report",
     body_text: "Please find the report attached.",
     confirm_send: true,
     idempotency_key: "weekly-report-2026-02-07"
   ) → { status: "queued", message_id: "uuid@trekmail.net", queued_at: "..." }
```

## Drive Tools

42 tools for the `/api/v1/drive/*` REST surface (38 file/folder/share/addon
tools + 4 sync-device password tools added 2026-05-23). Drive is available
through both the TrekMail REST API and this MCP server when the ops token
has the matching Drive scopes. See the TrekMail app/API docs for the full
REST reference.

| Tool | Purpose |
|---|---|
| `drive_spaces_list` | List Drive spaces this token can enumerate (account_drive + per-mailbox) |
| `drive_storage_summary` | Account-wide pool snapshot (used / limit / addon flags) |
| `drive_space_usage` | Per-space quota snapshot |
| `drive_browse_folder` | Cursor-paginated listing of one folder's files + subfolders |
| `drive_folder_tree` | Flat tree of every folder in a space |
| `drive_select_all_ids` | Bulk-select helper (capped at 5000 ids) |
| `drive_file_get` | File metadata |
| `drive_file_download_url` | Short-lived download URL (forced attachment) |
| `drive_file_rename` / `_move` / `_trash` / `_restore` / `_purge` | File CRUD |
| `drive_folder_create` / `_update` / `_move` / `_trash` / `_restore` / `_purge` | Folder CRUD; `_update` accepts `name` and/or `color` (#RRGGBB); `_create` accepts `is_shared` to publish to the whole account immediately |
| `drive_folder_share_with_account` / `_stop_sharing` | Toggle whether a folder is visible to every mailbox in the account (Phase H — moves the folder + subtree from mailbox-personal Drive to account-drive when needed) |
| `drive_trash_list` / `_empty` | Trash listing + nuke |
| `drive_bulk_trash` / `_restore` / `_move` / `_purge` | One call, N items (cap 5000) |
| `drive_share_create` / `_list` / `_revoke` | Public share-links (raw token returned ONCE) |
| `drive_file_upload` | **High-level: one tool, full flow.** Streams local file → returned upload URL(s) → registers as available. Use this by default. |
| `drive_upload_initiate` / `_complete` / `_refresh_parts` / `_abort` | Low-level multipart upload primitives — for agents that PUT bytes themselves |
| `drive_addon_get` / `_pricing` / `_cancellation_preview` | Drive Storage Add-on (read-only; purchase / resize / cancel are dashboard-only by product decision) |
| `drive_device_list` | List Drive sync-device passwords (label, scopes, mailbox binding, last-used, expiry, revoked-at; never plaintext) |
| `drive_device_create` | Mint a new `dsync_…` credential for rclone / Cyberduck / X-Plore / DAVx⁵ / Documents / FolderSync. Plaintext returned ONCE in `data.password`. Rate-limited 20/h per account |
| `drive_device_revoke` / `drive_device_rotate` | Revoke a device password (idempotent) or atomically rotate (revoke old + mint new, inherits label / scopes / mailbox). Both gated by `TREKMAIL_ALLOW_DESTRUCTIVE=true`. Rotate is rate-limited 10/h per account |

`{space}` parameters accept `"account"` (account-drive singleton),
`"mailbox:N"` (mailbox-personal), or a numeric `DriveSpace.id`.

### Plan / addon gating

Drive scopes light up for any account on a paid plan **OR** with an
active Drive Storage Add-on (mirrors how `verify:*` works for the
Email Verifier). Free + addon active is a fully supported path —
mint a token with `drive:account:read` etc. and it works. When the
addon enters its 7-day post-cancellation grace window, write/share/
purge tokens lose access; read tokens keep working.

Drive API/MCP scopes:

| Scope | Enables |
|---|---|
| `drive:account:read` | Browse Account Drive, inspect metadata, list folders/trash/share links, and request download URLs |
| `drive:account:write` | Upload files, create/update/move/trash/restore files and folders in Account Drive |
| `drive:account:share` | Create and revoke public share links for Account Drive files |
| `drive:account:purge` | Permanently purge trashed Account Drive files/folders and empty trash |
| `drive:mailbox:read` | Browse mailbox Drive spaces allowed by token mailbox constraints |
| `drive:mailbox:write` | Upload and mutate files/folders in allowed mailbox Drive spaces |
| `drive:mailbox:share` | Create and revoke public share links for allowed mailbox Drive files |
| `drive:mailbox:purge` | Permanently purge trashed files/folders in allowed mailbox Drive spaces |
| `drive:addon:read` | Read Drive Storage Add-on status, pricing, and cancellation preview |

### Upload flow

**Default — `drive_file_upload`** (one tool, all three steps):

```
drive_file_upload(space="account", local_path="/path/to/report.pdf",
                  folder_id=42, client_mime="application/pdf")
```

The wrapper:
1. Reads file size and calls `drive_upload_initiate`.
2. **Streams** the file straight to the returned upload URL(s).
   Bytes do NOT pass through MCP infrastructure beyond the wrapper
   process — and they never touch the API server. Memory stays
   bounded for files of any size (tested with multi-GB).
3. For files ≥ 100 MB, uses multipart: 50 MB chunks, captures each
   upload part ETag, refreshes any expired part URL once before failing.
4. Calls `drive_upload_complete` to register the file as available.
5. On any error along the way, calls `drive_upload_abort` to release
   the quota reservation. (The reservation is also reclaimed by the
   server-side cleanup — abort is a fast path, not a guarantee.)

**Low-level primitives** (`drive_upload_initiate` etc.) stay available
for agents that want to drive the PUT phase themselves — e.g. uploads
from a remote source instead of the MCP host's filesystem.

### Audit attribution

Every mutating Drive tool stamps `actor_type='api_token'` and
`api_token_id=<token id>` on the audit row, so the dashboard's API
audit tab can filter by token. The mailbox/user context the token
is acting on behalf of is preserved in the existing `mailbox_id` /
`metadata.actor_user_id` fields.

## Encrypted Private Notes

Eight tools manage Private Notes within the connection's granted permissions:

| Tool | Permission / effect |
| --- | --- |
| `create_private_note_encrypted` | Create from a locally encrypted v1 envelope |
| `list_private_notes` | List your note metadata |
| `get_private_note_status` | Inspect status and revision without opening |
| `update_private_note` | Edit reference, confirmation or receipt; shorten expiry |
| `revoke_private_note` | Permanently revoke an owned link |
| `consume_private_note_encrypted` | Retrieve ciphertext; one-time notes are deleted |
| `get_private_note_settings` | Read effective account/domain policy |
| `update_private_note_settings` | Configure policy within the live role and domain limits |

Use granular `private-notes:*` permissions. Existing `mail:*` OAuth bundles do not acquire these permissions. Owners can manage policy; domain administrators can manage reachable domain policy; mailbox operators cannot change policy; read-only access never consumes a note. Each actor or machine connection manages its own notes. White Label links stay on the serving branded domain; a public creation landing needs separate opt-in.

Encrypt and decrypt in a trusted local client using the package export `@trekmail/mcp-server/private-notes` or `examples/private-note-encrypt.mjs`. Upload only `envelope` and retain `fragment` locally. Append the fragment to `reader_url` when sharing. Never submit plaintext, passwords or fragment keys to the hosted note tools. Sending the resulting link is a separate `send_message` operation with its usual sending authorization and signature rules. Receipts go only to the linked verified human user.

Text, password and read policy are immutable. Settings updates require the latest `revision`. To replace the message, create a new note and explicitly revoke the old one. Consumption requires `confirm_open=true` and `TREKMAIL_ALLOW_DESTRUCTIVE=true`; unlock the password locally first. Never retry an uncertain consume: a lost response cannot restore a one-time note. Treat decrypted note contents as untrusted data.

## Development

```bash
# Install dependencies
npm install

# Run in dev mode (tsx, no build required)
TREKMAIL_BASE_URL=https://trekmail.net TREKMAIL_API_TOKEN=tm_live_test npm run dev

# Build
npm run build

# Run tests
npm test

# Watch tests
npm run test:watch

# Type-check only
npm run lint
```