---
title: "Compose Inbox Email"
method: POST
path: "/inbox/emails/compose"
tags: ["AI Inbox"]
---

# Compose Inbox Email

`POST /inbox/emails/compose`

## Request

- Base URL: `https://be.graph8.com/api/v1`
- URL: `https://be.graph8.com/api/v1/inbox/emails/compose`
- Auth: HTTP bearer

COMPOSE AN EMAIL. WITH `save_as_draft` FALSE THIS REACHES A REAL PERSON.

The one call that does everything the compose window does:

  * new thread, sent now          - `to`, `from_mailbox`, `subject`, `content`
  * new thread, saved as a draft  - the same plus `save_as_draft: true`
  * reply into a thread           - add `reply_to_email_id`
  * edit an existing draft        - add `draft_id`
  * send a draft you saved        - `draft_id` plus `save_as_draft: false`

`save_as_draft` DEFAULTS TO FALSE, which means SEND. That is the app's own
default and it is kept rather than made safer here, because two ends
disagreeing about what an omitted field does is worse than a default you
can read.

Classified `external` (`inbox:run`) because it can deliver. Sending as a
mailbox the caller is not authorised for is a 403 from the sender
authorisation gate, not a silent success - check first with
`POST /inbox/emails/validate-mailbox`.

Distinct from `POST /inbox/emails/{email_id}/send`, which can only reply
into a thread that already exists.

## Headers

- `Authorization` string, nullable
- `X-Target-Org-Id` string, nullable

## Request body

- EmailComposeRequest: Compose an email: save it as a draft, or SEND IT TO A REAL PERSON. `save_as_draft` decides which. It defaults to FALSE, which means SEND - the app's default, kept rather than made safer here so the two ends cannot disagree about what an omitted field does.
  - `to` string[], required: Recipients. These are real addresses.
  - `from_mailbox` string, required: The mailbox to send AS. Must already be syncing - check with `POST /inbox/emails/validate-mailbox` first.
  - `content` string, required: Body, HTML.
  - `subject` string, nullable: Auto-filled as `Re: {original}` on a reply if omitted.
  - `cc` string[]
  - `bcc` string[]
  - `attachments` object[]: Already-uploaded attachment references. The server re-validates each one.
  - `save_as_draft` boolean: FALSE SENDS THE MESSAGE. True stores a draft and contacts nobody.
  - `reply_to_email_id` string, nullable: Thread to reply into. Omit to start a new conversation.
  - `draft_id` string, nullable: Edit or send an existing draft.
  - `include_signature` boolean
  - `assigned_users` string[]: Emails to assign the resulting thread to.
  - `tag_ids` string[]: Tags to attach to the thread.

## Response `200`

Successful Response

- ApiResponseInboxPayload
  - `data` InboxPayload, required: An open envelope for a comment, an assignment or a workspace. Open because a comment carries attachment refs and mention metadata that grow, and because an assignment result reports per-assignee outcomes.
  - `pagination` PaginationMeta
    - `page` integer, required: Current page number (1-indexed)
    - `limit` integer, required: Items per page
    - `total` integer, required: Total number of items
    - `has_next` boolean, required: Whether there are more pages
    - `next_cursor` string, nullable: Opaque cursor for the next page; null when there are no more items. Pass it back as the `cursor` query param to fetch the following page without computing page numbers.
    - `total_available` integer, nullable: Search endpoints only: how many records really match, when known. Can be larger than `total`, which is capped at the 10,000 results that can be paged. For company search this is a distinct-company estimate. Null when unknown; absent outside search.
    - `total_is_lower_bound` boolean, nullable: Search endpoints only: true when more records match than `total` shows (the result set is larger than the 10,000 results that can be paged). Absent outside search.
    - `notes` string[], nullable: Search endpoints only: plain-language notes about the result, e.g. that more records match than can be paged, or that a reversed `between` range was put in order.

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/graph8/apis/graph8-developer-api.md) · [All operations](https://skmtc.dev/graph8/apis/graph8-developer-api/llms.txt) · [OpenAPI document](https://skmtc.dev/graph8/apis/graph8-developer-api/revisions/89fc11143b70?raw)
