Safety Rails and Delete Intents
How two-step delete intents, rate limits, and audit logging protect against accidental data loss.
Article details
Type, difficulty, plans, and last updated info.
▼
Article details
Type, difficulty, plans, and last updated info.
- Type
- Reference
- Difficulty
- Intermediate
- Plans
- Starter · Pro · Agency
- Last updated
- Sep 9, 2026
The TrekMail API is designed to prevent accidental data loss. Destructive operations require multiple confirmation steps, rate limits prevent bulk mistakes, and every action is logged.
Recycle bin. Confirming a mailbox delete intent now moves the mailbox to a 7‑day recycle bin (shown as Recently deleted in the dashboard) rather than destroying it immediately. You can list trashed mailboxes and restore one within the window:
GET /api/v1/mailboxes?status=trashed # list the recycle bin POST /api/v1/mailboxes/{id}:restore # restore to active (scope mailboxes:delete)After the retention window a daily job purges trashed mailboxes permanently. Restoring re‑checks your per‑domain mailbox limit. MCP agents use the
restore_mailboxandlist_trashed_mailboxestools;confirm_delete_intentis now recoverable, not irreversible. Deleting a domain or account removes its mailboxes permanently and does not use the recycle bin.
Two-step delete (delete intents)
Mailbox deletion and domain deletion are the most impactful destructive operations in the API. It uses a two-step process:
Step 1: Create a delete intent
POST /api/v1/mailboxes/{id}:delete-intent
This creates a time-limited intent that describes what will be deleted. The response includes:
- Risk flags: warnings about forwarding rules, aliases, or active migrations that will be affected.
- Expiration: the intent expires after 10 minutes. After that, you must create a new one.
- Confirm URL: the URL to call for Step 2.
No data is deleted at this stage.
Step 2: Confirm the intent
POST /api/v1/delete-intents/{id}:confirm
Headers: X-Confirm-Delete: true
With TrekMail's mailbox recycle bin enabled, confirmation moves the mailbox to Recently deleted and returns a completed intent with status: "executed". The mailbox can be restored for seven days, provided the domain has room for it when you restore it.
{
"id": 1,
"mailbox_id": 4,
"mailbox_email": "user@acme.test",
"status": "executed",
"risk_flags": [],
"confirmed_at": "2026-05-28T11:22:08+00:00",
"executed_at": "2026-05-28T11:22:08+00:00"
}
After the recovery window, TrekMail's daily cleanup permanently removes the mailbox. Use the recycle-bin list or restore endpoint before then. Deleting a domain or account does not use this mailbox recovery path.
The X-Confirm-Delete: true header is required on the confirm request as an additional safety check.
Risk flags
When you create a delete intent, the API checks for conditions that might indicate you do not want to proceed:
| Flag | Meaning |
|---|---|
has_active_forwarding |
The mailbox has forwarding enabled, other addresses depend on it. |
has_aliases |
Virtual aliases route email to this mailbox. |
has_active_migration |
A migration is currently importing email into this mailbox. |
Review these flags before confirming. The API does not block confirmation based on risk flags. They are informational only.
Rate limits on destructive operations
Destructive operations have two layers of rate limiting beyond the standard per-minute API rate limit:
- Daily limit per token: Each token can confirm a limited number of delete intents per day.
- Cooldown between confirms: After confirming one delete, there is a short cooldown before the next confirmation is accepted.
Both return 429 Too Many Requests with a Retry-After header when triggered.
MCP safety control for locally hosted servers
If you run the stdio MCP server yourself, its administrator can require TREKMAIL_ALLOW_DESTRUCTIVE=true before delete tools are available. This is a local safety control, not a TrekMail product feature switch. Hosted MCP uses the permissions approved during OAuth.
Read tools remain available within the granted scopes. Review the agent's task and scopes before allowing delete actions.
Idempotency
Write endpoints that require an Idempotency-Key say so in the endpoint table and OpenAPI specification. Use a new key for each logical operation before retrying a request:
Idempotency-Key: create-mailbox-alice-2024
- Same key and same body replay the original response without repeating the operation.
- Same key and different body return
409 Conflict. - Different tokens use independent key spaces.
The MCP server generates repeat-safe idempotency keys for tool calls, so retries do not repeat an operation that already completed.
Sending safety gates
Email sending through the MCP server has its own dual-gate safety design, similar to the destructive operations gate but with two independent checks:
Gate 1: Local server control
For a locally hosted MCP server, set TREKMAIL_ALLOW_SENDING=true to allow the send_message tool. Hosted MCP uses the permissions approved during OAuth.
Gate 2: Per-call confirmation
Even with the environment gate enabled, each send_message call must include confirm_send=true as a parameter. Without it, the tool returns an error asking the agent to confirm.
Why two gates?
The local control is set once by the administrator who configures the MCP server. The per-call control requires the agent to actively decide to send each email. Neither control alone is sufficient; both must pass before any email leaves the server.
This prevents accidental sends from agents that explore available tools without understanding their consequences. An agent can list and read messages freely (with a message token), but it cannot send unless both safety gates are satisfied.
Migration safety gates
Email migration through the MCP server has its own safety gates, similar to sending and destructive operations.
Migration local server control
For a locally hosted MCP server, set TREKMAIL_ALLOW_MIGRATION=true to allow migration write tools (start_migration, retry_migration, delete_migration). Hosted MCP uses the permissions approved during OAuth.
cancel_migration is always available regardless of this setting. It is a safety operation that must always be accessible to stop a runaway migration.
Read-only migration tools (list_migrations, get_migration) work without any gates. test_migration_connection requires TREKMAIL_ALLOW_MIGRATION=true because it makes outbound IMAP connections.
Migration per-call confirmation
Each migration write tool requires a confirmation parameter:
start_migrationrequiresconfirm_start=truecancel_migrationrequiresconfirm_cancel=trueretry_migrationrequiresconfirm_retry=true
Without the confirmation parameter, the tool returns an error asking the agent to confirm.
Server-wide concurrency limit
The API enforces a global limit on simultaneous migrations (default: 20). When the limit is reached, new migration requests return 503 with migration_capacity_reached and retryable: true. This protects server resources when many accounts migrate simultaneously.
Audit logging
Every mutating API action is recorded in the audit log, visible under AI Agents & API → Audit Log in the dashboard. Events include:
- Token created / revoked: who created or revoked an ops token, and when.
- Message token created / revoked: who created or revoked a message token.
- Intent created: a delete intent was created for a specific mailbox.
- Intent confirmed: the deletion request was accepted.
- Delete executed: the mailbox was moved to Recently deleted and its recovery window began.
- Intent expired: an unconfirmed intent expired after 10 minutes.
- Mailbox created: a new mailbox was provisioned via the API.
- Invite created: a mailbox setup invite was sent.
- Forwarding updated: forwarding rules were changed for a mailbox.
- DNS recheck triggered: a DNS verification was requested for a domain.
- Migration started: an email migration was initiated via the API.
- Migration cancelled: a running migration was cancelled.
- Migration retried: a failed or cancelled migration was retried.
- Migration deleted: a migration record was deleted.
- Message read: messages were listed or read via the Message API.
- Message sent: an email was sent via the Message API.
- Message send failed: an email send attempt failed.
- Message flags updated: message flags (read/unread, starred) were changed.
- Message deleted: a message was deleted from a mailbox folder.
- Message moved: a message was moved between folders.
- Domain created: a domain was added via the API.
- Domain deleted: a domain was removed via the API.
- Ticket created: a support ticket was opened via the API.
- Ticket replied: a reply was posted to a ticket.
- Ticket closed: a ticket was closed via the API.
- SMTP configured: SMTP settings were updated.
- SMTP connection deleted: a custom SMTP connection was removed.
- SMTP test queued: an SMTP connection test was started.
- Cloudflare token deleted: a stored Cloudflare token was removed via the API.
All message API events, including reads, sends, flag updates, deletes, and moves, are fully logged. Audit records are retained for 90 days.
Each event records the token used, the resource affected, the IP address, and a request ID.
Filter the audit log by event type, token, or date range to investigate specific activity.
Quick fixes
- Intent expired before confirmation: Create a new delete intent. Intents expire after 10 minutes.
- "Missing confirm header": Add the
X-Confirm-Delete: trueheader to the confirmation request. - 429 on delete confirmation: You hit the daily limit or cooldown. Wait for the
Retry-Afterperiod. - A self-hosted MCP agent says delete tools are disabled: Its local administrator can set
TREKMAIL_ALLOW_DESTRUCTIVE=truein that MCP process's environment. - A self-hosted MCP agent says "Sending is disabled": Its local administrator can set
TREKMAIL_ALLOW_SENDING=truein that MCP process's environment. - MCP agent says "Send not confirmed": The agent must pass
confirm_send=trueas a parameter on eachsend_messagecall. - A self-hosted MCP agent says migration tools are disabled: Its local administrator can set
TREKMAIL_ALLOW_MIGRATION=truein that MCP process's environment. - 503 "migration_capacity_reached": Too many migrations are running server-wide. Wait a few minutes and retry.
- 409 "active migration running": Cancel or wait for the existing migration to finish before starting a new one.
Related articles
Jump to nearby guides that continue the workflow.