---
title: "Create a recipient-safe inbox reply draft"
method: POST
path: "/mailboxes/{id}/inbox/threads/{thread_id}/drafts"
tags: ["Mailboxes", "Messages"]
---

# Create a recipient-safe inbox reply draft

`POST /mailboxes/{id}/inbox/threads/{thread_id}/drafts`

## Request

- Base URL: `https://shipmail.to/api/v1`
- URL: `https://shipmail.to/api/v1/mailboxes/{id}/inbox/threads/{thread_id}/drafts`
- Auth: one of:
  - HTTP bearer
  - OAuth 2 (authorization code, authorization URL `https://shipmail.to/api/auth/oauth2/authorize`, token URL `https://shipmail.to/api/auth/oauth2/token`)

Shipmail derives To/Cc from the latest inbound message and binds the draft to expected_version, the version returned by GET /mailboxes/{id}/inbox/threads/{thread_id}. The response lists in removed_formatting any formatting the HTML sanitiser dropped. Supported HTML tags: p, br, strong/b, em/i, u, s, a (http, https, mailto, tel), ul, ol, li, blockquote, code, pre, h2, h3, span/mark with the composer's styles, and inline cid: images. h1 becomes h2. Tables and h4-h6 are not supported: their text stays as paragraphs and removed_formatting lists them ("table" for any table part, "h4", ...), as it lists other dropped elements such as script, style or iframe. Attributes and inline styles outside the composer set are dropped and not reported. Paragraphs are spaced like the Shipmail composer, so do not add <p><br></p> between them. When html is given without text, the text part is derived from it.

## Headers

- `X-Shipmail-Organization` string

## Request body

- union
  - object
    - `text` string, required: Plain text body. At least one of html or text is required.
    - `html` string: HTML body. At least one of html or text is required. Supported HTML tags: p, br, strong/b, em/i, u, s, a (http, https, mailto, tel), ul, ol, li, blockquote, code, pre, h2, h3, span/mark with the composer's styles, and inline cid: images. h1 becomes h2. Tables and h4-h6 are not supported: their text stays as paragraphs and removed_formatting lists them ("table" for any table part, "h4", ...), as it lists other dropped elements such as script, style or iframe. Attributes and inline styles outside the composer set are dropped and not reported. Paragraphs are spaced like the Shipmail composer, so do not add <p><br></p> between them. When html is given without text, the text part is derived from it.
    - `reply_mode` 'reply' | 'reply_all'
    - `expected_version` integer, required: The conversation version from GET /mailboxes/{id}/inbox/threads/{thread_id} (version) or the inbox thread queue.
  - object
    - `text` string: Plain text body. At least one of html or text is required.
    - `html` string, required: HTML body. At least one of html or text is required. Supported HTML tags: p, br, strong/b, em/i, u, s, a (http, https, mailto, tel), ul, ol, li, blockquote, code, pre, h2, h3, span/mark with the composer's styles, and inline cid: images. h1 becomes h2. Tables and h4-h6 are not supported: their text stays as paragraphs and removed_formatting lists them ("table" for any table part, "h4", ...), as it lists other dropped elements such as script, style or iframe. Attributes and inline styles outside the composer set are dropped and not reported. Paragraphs are spaced like the Shipmail composer, so do not add <p><br></p> between them. When html is given without text, the text part is derived from it.
    - `reply_mode` 'reply' | 'reply_all'
    - `expected_version` integer, required: The conversation version from GET /mailboxes/{id}/inbox/threads/{thread_id} (version) or the inbox thread queue.

## Response `201`

Saved reply draft and derived recipients.

- InboxReplyDraftWrite: A reply draft returned by create and update, with the formatting the HTML sanitiser dropped.
  - `object` 'inbox_reply_draft', required
  - `id` string, required
  - `mailbox_id` string, required
  - `thread_id` string, required: Deprecated and not stable: a legacy thread ID that changes when the mail server re-threads its IDs or a relayed send's placeholder key is replaced. It remains supported in thread paths; store conversation_id instead.
  - `conversation_id` string, required: Stable Shipmail conversation identifier (thd_...). Store this: it survives thread merges and mail-server re-threading, which thread_id does not.
  - `based_on_message_id` string, nullable, required
  - `expected_version` integer, required
  - `reply_mode` 'reply' | 'reply_all', required
  - `status` 'draft' | 'sending' | 'sent' | 'invalidated' | 'failed', required
  - `to` object[], required: Recipients derived from the source message. Empty, like cc, once the stored draft no longer exists.
    - `address` string, email, required
    - `name` string, nullable, required
  - `cc` object[], required
    - `address` string, email, required
    - `name` string, nullable, required
  - `subject` string, nullable, required: Stored subject. Null once the stored draft no longer exists (after a send or cleanup).
  - `html` string, nullable, required: Stored HTML after sanitisation. Null once the stored draft no longer exists.
  - `text` string, nullable, required: Stored text part. Null once the stored draft no longer exists.
  - `sent_message_id` string, nullable, required: ID of the sent message once the draft is sent.
  - `created_at` string, date-time, required
  - `updated_at` string, date-time, required
  - `sent_at` string, date-time, nullable, required
  - `removed_formatting` string[], required: Formatting the HTML sanitiser dropped: "table" for any table part, "h4" to "h6", and other dropped elements such as "script". Their text stays as paragraphs. Empty when nothing was dropped.

## Other responses

- `401`: Authentication failed.
- `403`: Insufficient permissions.
- `404`: Resource not found.
- `409`: Resource conflict.
- `422`: Validation failed.
- `429`: Rate limit exceeded.

---

[API](https://skmtc.dev/shipmail/apis/shipmail-api.md) · [All operations](https://skmtc.dev/shipmail/apis/shipmail-api/llms.txt) · [OpenAPI document](https://skmtc.dev/shipmail/apis/shipmail-api/revisions/2c23e59d7e30?raw)
