---
title: "Send an email"
method: POST
path: "/api/email/send"
tags: ["Email"]
---

# Send an email

`POST /api/email/send`

## Request

- Base URL: `https://core-api.getaptly.com`
- URL: `https://core-api.getaptly.com/api/email/send`
- Auth: one of:
  - API key in header `x-token`
  - API key in header `Authorization`
  - HTTP bearer
- TypeScript: <https://skmtc.dev/getaptly/apis/aptly-api/docs/api/email/send/post.ts> (a function with typed inputs; its response is checked against the schema)

Sends an outbound email scoped to your company. Two usage patterns:

`userId` and `channelId` are required on every call.

**From an existing draft** — also provide `discussionId` and `uuid` returned by
`POST /api/email/create-draft`. The draft's stored recipients, subject, and body are
used.

**On-the-fly** — omit `uuid` and provide `userId`, `channelId`, recipients, subject,
and body. A draft is created automatically before sending. Supplying `discussionId`
(without `uuid`) sends the message as a reply into that existing thread — the
thread's subject is kept; omitting both `discussionId` and `uuid` starts a new thread.

### Adding attachments

Attachments apply to the **on-the-fly** pattern (for an existing draft, attach files
when you call `POST /api/email/create-draft`). Upload each file with the three-step
direct upload flow first — you cannot post file bytes to this endpoint:

1. **Get an upload URL** — `POST /api/files/upload-url` with `attachEntityType: "channel"`,
   `attachEntityId` set to the same `channelId` you're sending from, and the file's
   `name`, `extension`, `size`, and `contentType`. Returns `{ fileId, url, fields }`.
2. **Upload to S3** — `multipart/form-data` `POST` to `url`, all `fields` first then the
   file bytes last as a `file` field. S3 returns `204`.
3. **Mark complete** — `POST /api/files/upload-complete` with the `fileId`.

Then, on this request:
- **Regular attachment** — add the `fileId`(s) to `attachmentIds`.
- **Inline image** — embed an `<img>` in the HTML `body` whose `src` is the file's
  download URL (`.../cdn/storage/AptlyFiles/<fileId>/original/...`). Auto-detected and
  registered; do **not** also list it in `attachmentIds`.

Each `fileId` must reference a finished upload.

## Request body

- object
  - `discussionId` string: Stream ID from `POST /api/email/create-draft` (required if `uuid` is set). When supplied without `uuid`, the on-the-fly draft is appended as a reply into this existing thread (same company + channel) instead of starting a new discussion; the thread's subject is kept.
  - `uuid` string: Draft UUID from `POST /api/email/create-draft`. Required if `discussionId` is set.
  - `failOnCreateNewThread` boolean: If `true` (default), the send fails when the email would create a new discussion thread rather than reply to an existing one.
  - `userId` string, required: Required when sending on-the-fly (no `discussionId`/`uuid`).
  - `channelId` string, required: Required when sending on-the-fly.
  - `companyId` string: Company ID. Required only when authenticating with a partner token; resolved automatically for API key and delegate token auth.
  - `to` EmailRecipient[]
    - `value` string, required: Email address.
    - `label` string: Optional display name for the recipient.
  - `cc` EmailRecipient[]
    - `value` string, required: Email address.
    - `label` string: Optional display name for the recipient.
  - `bcc` EmailRecipient[]
    - `value` string, required: Email address.
    - `label` string: Optional display name for the recipient.
  - `subject` string
  - `body` string: Email body (plain text or HTML). To embed an uploaded image inline, add an `<img>` whose `src` is the file's download URL from `POST /api/files/upload-complete` (`.../cdn/storage/AptlyFiles/<fileId>/original/...`). Inline images are auto-detected, tagged with `data-inline-image-id`, and registered on the draft — do not also list them in `attachmentIds`. Applies when the draft is created on-the-fly (no `discussionId`/`uuid`).
  - `attachmentIds` string[]: File ids to include as regular attachments (applies when the draft is created on-the-fly). Upload each file first (`POST /api/files/upload-url` with attachEntityType `channel` and the same channelId → upload to S3 → `POST /api/files/upload-complete`), then pass the resulting `fileId`s here. Each must reference a finished upload.
  - `aptletInstanceId` string: Card to link the outbound to. Logs the email as an activity on the card and tags the discussion. Works whether the draft was pre-created or is created on-the-fly.

## Response `200`

Email sent successfully.

- object

## Other responses

- `400`: The request body failed validation, for example a recipient that is not an email address, or a missing `userId` or `channelId`. See `meta.issues` for each field.
- `401`: Invalid or missing API key.

---

[API](https://skmtc.dev/getaptly/apis/aptly-api.md) - [All operations](https://skmtc.dev/getaptly/apis/aptly-api/llms.txt) - [OpenAPI document](https://skmtc.dev/getaptly/apis/aptly-api/revisions/75c367e0b8e5?raw)
