Skip to main content

Overview

Moves a message from its current mailbox to a destination mailbox within the same account. The message is removed from the source mailbox and appears in the destination mailbox. The server uses the native IMAP MOVE command when available, or falls back to COPY + DELETE + EXPUNGE when the server doesn’t support MOVE.
This tool requires MAIL_IMAP_WRITE_ENABLED=true to be set in your environment variables. Write operations are disabled by default as a safety measure.
To move messages between different accounts, use imap_copy_message followed by imap_delete_message.

Common use cases

  • Move messages to Archive or Trash folders
  • Organize messages into project or category folders
  • Move spam to Junk folder
  • Relocate drafts to Sent folder after sending
  • File messages into date-based folders

Input parameters

body.account_id
string
default:"default"
Account identifier. Must match pattern ^[A-Za-z0-9_-]{1,64}$.
body.message_id
string
required
Message identifier in format imap:{account_id}:{mailbox}:{uidvalidity}:{uid}.The account_id in the message_id must match the account_id parameter.
body.destination_mailbox
string
required
Destination mailbox name (1-256 characters). Must not contain control characters.The mailbox must exist on the IMAP server. Use imap_list_mailboxes to see available mailboxes.

Response

summary
string
Human-readable one-line outcome: "Message moved"
data
object
meta
object

Example request

{
  "account_id": "default",
  "message_id": "imap:default:INBOX:1234567890:42",
  "destination_mailbox": "Archive"
}

Example response

{
  "summary": "Message moved",
  "data": {
    "status": "ok",
    "issues": [],
    "account_id": "default",
    "source_mailbox": "INBOX",
    "destination_mailbox": "Archive",
    "message_id": "imap:default:INBOX:1234567890:42",
    "new_message_id": null,
    "steps_attempted": 2,
    "steps_succeeded": 2
  },
  "meta": {
    "now_utc": "2026-03-03T22:30:15.123Z",
    "duration_ms": 345
  }
}

Error responses

{
  "error": {
    "code": "invalid_input",
    "message": "write tools are disabled; set MAIL_IMAP_WRITE_ENABLED=true",
    "details": {}
  },
  "meta": {
    "now_utc": "2026-03-03T22:30:15.123Z",
    "duration_ms": 5
  }
}

Implementation notes

Move strategy selection

The server checks IMAP server capabilities to determine which strategy to use: Native MOVE (preferred):
  1. Connect and authenticate (steps_attempted=1)
  2. Check server capabilities (steps_attempted=2, internally tracked)
  3. Execute UID MOVE command (steps_attempted=2)
COPY+DELETE fallback:
  1. Connect and authenticate (steps_attempted=1)
  2. Check server capabilities (steps_attempted=2)
  3. Copy message to destination using UID COPY (steps_attempted=3)
  4. Mark original as deleted using UID STORE +FLAGS.SILENT (\\Deleted) (steps_attempted=4)
  5. Expunge the deleted message using UID EXPUNGE (steps_attempted=4)

Atomicity considerations

  • Native MOVE: Atomic operation guaranteed by the IMAP server
  • COPY+DELETE fallback: Not atomic - if the delete or expunge step fails, the message will exist in both mailboxes

Partial failures

When using COPY+DELETE fallback, partial failures can occur:
  • Copy succeeds, but delete fails: Message appears in both mailboxes
  • Copy and delete succeed, but expunge fails: Message marked as deleted but still visible in source mailbox until next expunge
Check steps_succeeded and issues to determine the exact failure point.

Message visibility

After a successful move:
  • The message immediately appears in the destination mailbox
  • The message is removed from the source mailbox (or marked as \Deleted if expunge failed)
  • The message UID changes in the destination mailbox
  • The old message_id from the source mailbox becomes invalid

See also

Build docs developers (and LLMs) love