> ## Documentation Index
> Fetch the complete documentation index at: https://docs.langmail.me/llms.txt
> Use this file to discover all available pages before exploring further.

# update_draft

> Edit a staged draft. Returns a new draft id, because editing replaces the message.

Edits a draft that has not been sent. Omitted fields keep their staged values; a supplied field replaces it; an empty recipient array clears that field.

**The draft id changes, and the previous version is not recoverable.** JMAP makes a message's content immutable — only its keywords and folder membership can be patched — so editing a draft means writing a new message and retiring the old one. The new message is written first and the old one retired only once it exists, so a rejected write (a quota error, say) leaves the original intact rather than losing the content. The returned `draftId` is the one every later call, including [`send_draft`](/reference/mcp/send-draft), must use.

Labels the user put on the draft are carried onto the replacement, so an edit does not quietly untag it.

The sender and the reply threading are not editable here. Changing who a message is from, or which conversation it belongs to, makes it a different message — stage that with [`create_draft`](/reference/mcp/create-draft).

## Parameters

<ParamField body="draftId" type="string" required>
  The draft to edit, as returned by [`create_draft`](/reference/mcp/create-draft) or a previous `update_draft`.
</ParamField>

<ParamField body="to" type="string[]">
  Replace the recipients. Omit to keep them; pass `[]` to clear them. Bare address or `Name <address>` form.
</ParamField>

<ParamField body="cc" type="string[]">
  Replace the carbon-copy recipients, same rules as `to`.
</ParamField>

<ParamField body="bcc" type="string[]">
  Replace the blind-copy recipients, same rules as `to`.
</ParamField>

<ParamField body="subject" type="string">
  Replace the subject. Omit to keep it.
</ParamField>

<ParamField body="text" type="string">
  Replace the plain-text body. Omit to keep it. If the draft has **both** a plain-text and an HTML body, pass both or neither — see the note below.
</ParamField>

<ParamField body="html" type="string">
  Replace the HTML body. Omit to keep it. If the draft has both bodies, pass both or neither.
</ParamField>

<ParamField body="attachments" type="object[]">
  Replace the attached files, same entry shape as [`create_draft`](/reference/mcp/create-draft): `blobId` **or** base64 `content`. `filename` is **required** with `blobId` — a blob carries no name of its own, and the one [`get_draft`](/reference/mcp/get-draft) lists beside it is the one to pass — and optional but worth setting with `content`. `mimeType` is guessed from the filename's extension when omitted.

  Omit to keep the files already attached — the rewrite re-references their blobs, so this transfers nothing. Pass `[]` to remove them all. Supplying a list replaces the whole thing, so to *add* a file, read the existing `blobId`s back with [`get_draft`](/reference/mcp/get-draft) and list them alongside the new one.
</ParamField>

## Example

```json Call theme={null}
{ "draftId": "M5109", "subject": "Re: Quarterly numbers (final)" }
```

```text Result theme={null}
Draft updated and still unsent — its id is now M5133 (the previous id is gone; use the new one for send_draft).
draftId: M5133
from: Dana Okonjo <dana@langmail.me>
to: Nadia Bram <nadia@example.org>
subject: Re: Quarterly numbers (final)
threadId: T77
threading: In-Reply-To/References set — this message continues an existing conversation
body (text): Confirmed — the Q2 figures are final.
```

## Notes

* **A draft with both bodies must have both replaced at once.** Replacing only `text` on a text+HTML draft is refused, because mail clients render the HTML alternative: the tool would report the corrected body and deliver the old one.
* A draft whose body is too large to read back in full is refused rather than edited, since re-staging a truncated read would silently amputate the message.
* **Attached files survive an edit that never mentions them.** The rewrite re-references the blobs the draft already points at, so keeping them transfers nothing. Supplying `attachments` replaces the whole list instead — to add one more file, read the existing `blobId`s back with [`get_draft`](/reference/mcp/get-draft) and list them alongside the new one; an empty array removes them all.
* **An attachment that cannot be re-referenced blocks the edit.** A stored part with no `blobId` could not be carried onto the replacement, and the original is destroyed on the way, so the loss would be permanent and reported as a success. Such a draft is left unchanged — edit it in Langmail, or pass `attachments` explicitly to say what the edited draft should carry.
* An edit that changes nothing is refused too, and the existing `draftId` keeps working. Replacing a draft for no change would invalidate every stored reference to it for no benefit.

## Errors

* `Draft not found: <id>` — no such message, or a stale id from before an earlier edit.
* `<id> is not a draft — it has already been sent or received, and cannot be edited.`
* `Not a valid email address: …` — a replacement recipient was malformed. Nothing was changed.
* `This draft has both a plain-text and an HTML body, and only \`text\` was given…\` — pass both, or stage a fresh draft.
* `Draft <id> has a body too large to edit without risking losing part of it…`
* `Draft <id> carries a file this tool cannot carry across an edit (<names>), so it was left unchanged.`
* `The server refused this draft (invalidProperties).` — most often an attachment `blobId` the server does not recognise; blobIds belong to one account and do not outlive the message they were read from. The draft is left unchanged and its id still works.
* `No changes were given, so draft <id> was left exactly as it is — its id still works.`
* `Note: the previous draft <id> could not be removed and is still in Drafts. It holds the PRE-EDIT content and is still sendable…` — appended to a successful result when the replacement landed but the superseded draft couldn't be retired. Send the new id, not the old one.
