> ## 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.

# send_draft

> Send a staged draft. Irreversible, and the only mail tool that delivers to third parties.

Sends a draft. This delivers the message to its recipients and cannot be undone.

It sends *any* draft in the user's Drafts folder, not only ones an agent staged — find an existing one with [`search_emails`](/reference/mcp/search-emails) using `mailbox: "Drafts"`, and read it back with [`get_draft`](/reference/mcp/get-draft) before sending something the agent did not write.

A send is only ever reachable from a draft that already exists, which means there is always a state the user could have inspected between composing and sending. Clients that gate irreversible calls can key off this tool's MCP annotations rather than its name: it is marked `destructiveHint: true` and `openWorldHint: true`, while `create_draft` is marked `false` for both.

On success the message moves out of Drafts into Sent and loses its `$draft` marker — in the same server call as the submission, so a send can never half-commit into "delivered but still a draft". The message keeps its id, so the returned `messageId` is what [`get_email`](/reference/mcp/get-email) reads back.

## Parameters

<ParamField body="draftId" type="string" required>
  The draft to send, as returned by the most recent [`create_draft`](/reference/mcp/create-draft) or [`update_draft`](/reference/mcp/update-draft) call. Editing a draft changes its id.
</ParamField>

<ParamField body="idempotencyKey" type="string">
  Client-chosen key that makes the call safe to retry: a repeat with the same key returns the first call's answer instead of sending the message again. Pass one whenever the call might be retried. Keys are scoped to the account **and to this tool** — reusing a `create_draft` key here is not a retry, so each call needs its own key or none. Remembered for 15 minutes.
</ParamField>

## Example

```json Call theme={null}
{ "draftId": "M5133", "idempotencyKey": "reply to M4821" }
```

```text Result theme={null}
Sent.
messageId: 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.
The message is in Sent — read it back with get_email using the messageId above.
```

A message that carried files lists them after the body, the same way [`get_draft`](/reference/mcp/get-draft) does — this is the record of what actually went out, so it names every file, each with the `blobId` it was sent as. A file the server exposes without a retrieval handle appears too, marked as one that could not be re-attached: it *was* delivered with the message, and saying nothing about it would understate what the recipient just received.

## Sending twice

Three independent guards stop a duplicate delivery, because each closes a window the others leave open.

* **Structural, and needs no cooperation from the client.** A successful send clears the message's `$draft` marker, so a second call finds a non-draft and refuses. This holds whether or not an `idempotencyKey` was passed, because the state lives on the server — and the marker is cleared even on an account with no Sent folder, where the message stays in Drafts.
* **A reservation, for the retry that arrives while the first call is still running.** That is exactly the case a key alone cannot catch: neither call has recorded an answer yet, and the draft still reads as a draft because the server has not applied the follow-up patch. The second call is told a send is already in progress. The reservation is keyed on the draft rather than on the caller's key, so a client retrying with no key at all is covered too.
* **`idempotencyKey`, for the retry that arrives after the first call finished** but whose response the client never saw. It replays the first answer verbatim.

A send that the server *refuses* is released immediately and stays retryable. A send that fails without an answer — a timeout, a dropped connection — is **not** released: a later attempt is told the outcome is unknown and refused, because a duplicate cannot be recalled while an unsent message can be sent again by hand.

One more case is reported rather than hidden. If the mail is accepted but the follow-up mailbox update fails, the message is delivered while still looking like an unsent draft. The result says so explicitly and tells you not to send it again — this is the one situation where "it's still a draft, so it can't have gone out" is wrong.

## Errors

* `Draft not found: <id>. Nothing was sent.` — usually a stale id from before an [`update_draft`](/reference/mcp/update-draft).
* `<id> is no longer a draft — it has already been sent. Nothing was sent again.`
* `A send of <id> is already in progress. Nothing was sent by this call.`
* `An earlier send of <id> failed without saying whether the message went out, so it was NOT sent again.`
* `This account cannot send as …` — the draft's sender is no longer one of the account's identities.
* `Draft <id> has no sender address, so it cannot be sent.`
* `Draft <id> has no recipients, so it cannot be sent.` — reachable for a draft the user started in Langmail and left unaddressed, since this tool sends drafts it did not stage. Add them with [`update_draft`](/reference/mcp/update-draft) and send the id it returns; an attached draft is no obstacle, since the edit carries its files across.
