curl -X POST "https://api.wirebox.sh/api/v1/mailboxes/eva/drafts" \
-H "Authorization: Bearer $WIREBOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": ["alex@example.com"],
"subject": "Invoice follow-up",
"text": "Hi Alex, just checking in on invoice #1042."
}'
from wirebox import Wirebox
with Wirebox() as wirebox:
eva = wirebox.get_identity("eva")
draft = eva.create_draft(
to=["alex@example.com"],
subject="Invoice follow-up",
text="Hi Alex, just checking in on invoice #1042.",
)
print("Draft ID:", draft.id, "version:", draft.version)
import { Wirebox } from "@wirebox-sh/sdk";
const wirebox = new Wirebox();
const eva = await wirebox.getIdentity("eva");
const draft = await eva.createDraft({
to: ["alex@example.com"],
subject: "Invoice follow-up",
text: "Hi Alex, just checking in on invoice #1042.",
});
console.log("Draft ID:", draft.id, "version:", draft.version);
wirebox mail draft create \
--identity eva \
--to alex@example.com \
--subject "Invoice follow-up" \
--text "Hi Alex, just checking in on invoice #1042."
{
"id": "drf_01J8ABC123XYZ",
"mailbox_id": "mbx_01J8ABC123XYZ",
"thread_id": null,
"in_reply_to_message_id": null,
"forward_of_message_id": null,
"reply_all": false,
"forward_attachments": true,
"to": ["alex@example.com"],
"cc": [],
"bcc": [],
"subject": "Invoice follow-up",
"snippet": "Hi Alex, just checking in on invoice #1042.",
"text": "Hi Alex, just checking in on invoice #1042.",
"html": null,
"status": "draft",
"version": 1,
"has_attachments": false,
"attachments": [],
"headers": {},
"created_at": "2026-10-06T10:00:00Z",
"updated_at": "2026-10-06T10:00:00Z"
}
Mail
Email Drafts
Compose, revise, and send email drafts with optimistic versioning.
POST
/
api
/
v1
/
mailboxes
/
{email_address}
/
drafts
curl -X POST "https://api.wirebox.sh/api/v1/mailboxes/eva/drafts" \
-H "Authorization: Bearer $WIREBOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": ["alex@example.com"],
"subject": "Invoice follow-up",
"text": "Hi Alex, just checking in on invoice #1042."
}'
from wirebox import Wirebox
with Wirebox() as wirebox:
eva = wirebox.get_identity("eva")
draft = eva.create_draft(
to=["alex@example.com"],
subject="Invoice follow-up",
text="Hi Alex, just checking in on invoice #1042.",
)
print("Draft ID:", draft.id, "version:", draft.version)
import { Wirebox } from "@wirebox-sh/sdk";
const wirebox = new Wirebox();
const eva = await wirebox.getIdentity("eva");
const draft = await eva.createDraft({
to: ["alex@example.com"],
subject: "Invoice follow-up",
text: "Hi Alex, just checking in on invoice #1042.",
});
console.log("Draft ID:", draft.id, "version:", draft.version);
wirebox mail draft create \
--identity eva \
--to alex@example.com \
--subject "Invoice follow-up" \
--text "Hi Alex, just checking in on invoice #1042."
{
"id": "drf_01J8ABC123XYZ",
"mailbox_id": "mbx_01J8ABC123XYZ",
"thread_id": null,
"in_reply_to_message_id": null,
"forward_of_message_id": null,
"reply_all": false,
"forward_attachments": true,
"to": ["alex@example.com"],
"cc": [],
"bcc": [],
"subject": "Invoice follow-up",
"snippet": "Hi Alex, just checking in on invoice #1042.",
"text": "Hi Alex, just checking in on invoice #1042.",
"html": null,
"status": "draft",
"version": 1,
"has_attachments": false,
"attachments": [],
"headers": {},
"created_at": "2026-10-06T10:00:00Z",
"updated_at": "2026-10-06T10:00:00Z"
}
Drafts let an agent compose an email without sending it. A draft can be plain, a reply (
Response shape:
Response: the updated draft object (see Draft Object) with an incremented
in_reply_to), or a forward (forward_of), and it keeps a monotonically increasing version so concurrent edits can be detected instead of silently overwritten. Sending a draft converts it into a permanent message and deletes the draft record.
All endpoints below are scoped to a mailbox:
/api/v1/mailboxes/{email_address}/drafts
Create Draft
Path Parameters
string
required
Full mailbox address (
eva@wireboxmail.com) or local agent handle (eva).Body Parameters
string | string[]
Recipient email address(es). Required before the draft can be sent, but optional at creation time.
string
Draft subject line.
string
Plain-text body (alias:
body_text).string
HTML body (alias:
body_html).string | string[]
Optional CC recipients.
string | string[]
Optional BCC recipients.
string
Message ID to draft a reply to. Copies thread context when the reply is sent.
boolean
default:"false"
Draft a reply to every recipient of the parent message.
string
Message ID to draft a forward of.
boolean
default:"true"
Whether a forwarded draft copies the parent message’s attachments.
object[]
Optional attachments. Each object requires
filename and base64 content; content_type and content_id are optional.object
Optional custom RFC headers as a key/value map.
Draft Object
All draft endpoints return this object:string
Unique draft identifier (
drf_ prefix).string
Mailbox the draft belongs to.
string | null
Thread the draft will join when sent (set for replies).
string | null
Parent message for reply drafts.
string | null
Parent message for forward drafts.
boolean
Whether the reply targets all parent recipients.
boolean
Whether forwarding copies parent attachments.
string[]
Recipient addresses.
string[]
CC addresses.
string[]
BCC addresses.
string | null
Draft subject.
string | null
Short preview of the body.
string | null
Plain-text body.
string | null
HTML body.
string
draft, sending, or sent. Drafts are removed once sent.integer
Optimistic concurrency version, incremented on every update.
boolean
Whether the draft has attachments.
object[]
Attachment metadata:
id, filename, content_type, size_bytes, content_id, and a signed download url.object
Custom RFC headers.
string
ISO 8601 creation timestamp.
string
ISO 8601 update timestamp.
curl -X POST "https://api.wirebox.sh/api/v1/mailboxes/eva/drafts" \
-H "Authorization: Bearer $WIREBOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": ["alex@example.com"],
"subject": "Invoice follow-up",
"text": "Hi Alex, just checking in on invoice #1042."
}'
from wirebox import Wirebox
with Wirebox() as wirebox:
eva = wirebox.get_identity("eva")
draft = eva.create_draft(
to=["alex@example.com"],
subject="Invoice follow-up",
text="Hi Alex, just checking in on invoice #1042.",
)
print("Draft ID:", draft.id, "version:", draft.version)
import { Wirebox } from "@wirebox-sh/sdk";
const wirebox = new Wirebox();
const eva = await wirebox.getIdentity("eva");
const draft = await eva.createDraft({
to: ["alex@example.com"],
subject: "Invoice follow-up",
text: "Hi Alex, just checking in on invoice #1042.",
});
console.log("Draft ID:", draft.id, "version:", draft.version);
wirebox mail draft create \
--identity eva \
--to alex@example.com \
--subject "Invoice follow-up" \
--text "Hi Alex, just checking in on invoice #1042."
{
"id": "drf_01J8ABC123XYZ",
"mailbox_id": "mbx_01J8ABC123XYZ",
"thread_id": null,
"in_reply_to_message_id": null,
"forward_of_message_id": null,
"reply_all": false,
"forward_attachments": true,
"to": ["alex@example.com"],
"cc": [],
"bcc": [],
"subject": "Invoice follow-up",
"snippet": "Hi Alex, just checking in on invoice #1042.",
"text": "Hi Alex, just checking in on invoice #1042.",
"html": null,
"status": "draft",
"version": 1,
"has_attachments": false,
"attachments": [],
"headers": {},
"created_at": "2026-10-06T10:00:00Z",
"updated_at": "2026-10-06T10:00:00Z"
}
List Drafts
Query Parameters
integer
default:"50"
Number of drafts to return (1–100).
integer
default:"0"
Number of drafts to skip.
{ "drafts": [...], "count": <total>, "limit": <n>, "offset": <n> }, newest update first.
curl -X GET "https://api.wirebox.sh/api/v1/mailboxes/eva/drafts?limit=20" \
-H "Authorization: Bearer $WIREBOX_API_KEY"
wirebox mail draft list --identity eva
Get Draft
Returns a single draft with its attachments.curl -X GET "https://api.wirebox.sh/api/v1/mailboxes/eva/drafts/drf_01J8ABC123XYZ" \
-H "Authorization: Bearer $WIREBOX_API_KEY"
Update Draft
Updates recipients and bodies. Passingnull explicitly clears a field; omitting it leaves the field unchanged.
Body Parameters
integer
Expected current version. If it does not match, the update is rejected with
409 instead of overwriting a newer revision.string | string[] | null
Replace recipients, or clear them with
null.string | null
Replace or clear the subject.
string | null
Replace or clear the plain-text body (alias:
body_text).string | null
Replace or clear the HTML body (alias:
body_html).string | string[] | null
Replace or clear CC recipients.
string | string[] | null
Replace or clear BCC recipients.
object[]
Attachments to append (
filename + base64 content).string[]
Attachment IDs to remove.
object | null
Replace or clear custom RFC headers.
A
409 with draft_version_conflict means someone else updated the draft first — refetch it and re-apply your changes. A 409 with draft_not_editable means the draft is currently sending or has already been sent.curl -X PATCH "https://api.wirebox.sh/api/v1/mailboxes/eva/drafts/drf_01J8ABC123XYZ" \
-H "Authorization: Bearer $WIREBOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"version": 1,
"text": "Hi Alex, just following up on invoice #1042 — the payment is now overdue."
}'
from wirebox import Wirebox
with Wirebox() as wirebox:
eva = wirebox.get_identity("eva")
updated = eva.update_draft(
"drf_01J8ABC123XYZ",
version=1,
text="Hi Alex, just following up on invoice #1042 — the payment is now overdue.",
)
print("New version:", updated.version)
import { Wirebox } from "@wirebox-sh/sdk";
const wirebox = new Wirebox();
const eva = await wirebox.getIdentity("eva");
const updated = await eva.updateDraft("drf_01J8ABC123XYZ", {
version: 1,
text: "Hi Alex, just following up on invoice #1042 — the payment is now overdue.",
});
console.log("New version:", updated.version);
version.
Delete Draft
Permanently deletes the draft and cleans up its draft-scoped attachments.curl -X DELETE "https://api.wirebox.sh/api/v1/mailboxes/eva/drafts/drf_01J8ABC123XYZ" \
-H "Authorization: Bearer $WIREBOX_API_KEY"
wirebox mail draft delete drf_01J8ABC123XYZ --identity eva
{
"id": "drf_01J8ABC123XYZ",
"deleted": true
}
Send Draft
Sends the draft as an outbound email and deletes the draft record. The draft is claimed atomically (draft → sending → sent), so concurrent send calls cannot double-send. Draft attachments are promoted into permanent message attachments.
Headers
string
Optional client-generated token that makes retries safe: replaying a send with the same key returns the original
201 response with an Idempotent-Replayed: true header instead of sending a second email.Body Parameters
All fields are optional overrides applied only for this send (they do not modify the stored draft):string | string[]
Override recipients.
string
Override subject.
string
Override plain-text body (alias:
body_text).string
Override HTML body (alias:
body_html).string | string[]
Override CC recipients.
string | string[]
Override BCC recipients.
The draft must have at least one recipient and text or HTML content, or the send is rejected with
400 and the draft is returned to draft status. A 409 with draft_send_in_progress means the draft is already sending or was already sent.Response
string
Message ID of the sent email (
msg_ prefix).string
Thread the sent message belongs to.
string
Always
sent.curl -X POST "https://api.wirebox.sh/api/v1/mailboxes/eva/drafts/drf_01J8ABC123XYZ/send" \
-H "Authorization: Bearer $WIREBOX_API_KEY" \
-H "Idempotency-Key: 3f9c1d0e-8a2b-4f6e-9c1d-0e8a2b4f6e9c" \
-H "Content-Type: application/json" \
-d '{}'
from wirebox import Wirebox
with Wirebox() as wirebox:
eva = wirebox.get_identity("eva")
res = eva.send_draft(
"drf_01J8ABC123XYZ",
idempotency_key="3f9c1d0e-8a2b-4f6e-9c1d-0e8a2b4f6e9c",
)
print("Sent message ID:", res.id)
import { Wirebox } from "@wirebox-sh/sdk";
const wirebox = new Wirebox();
const eva = await wirebox.getIdentity("eva");
const res = await eva.sendDraft("drf_01J8ABC123XYZ", {
idempotencyKey: "3f9c1d0e-8a2b-4f6e-9c1d-0e8a2b4f6e9c",
});
console.log("Sent message ID:", res.id);
wirebox mail draft send drf_01J8ABC123XYZ \
--identity eva \
--idempotency-key 3f9c1d0e-8a2b-4f6e-9c1d-0e8a2b4f6e9c
{
"id": "msg_01J8SENT789ABC",
"thread_id": "thrd_01J8XYZ987ABC",
"status": "sent"
}