---
title: "Send email"
method: POST
path: "/v1/inboxes/{inbox_id}/messages"
tags: ["Messages"]
---

# Send email

`POST /v1/inboxes/{inbox_id}/messages`

## Request

- Base URL: `https://api.deadsimple.email`
- URL: `https://api.deadsimple.email/v1/inboxes/{inbox_id}/messages`
- Auth: HTTP bearer

## Path parameters

- `inbox_id` string, required

## Headers

- `X-Workspace-Id` string, uuid

## Request body

- object
  - `to` union, required
    - string
    - string[]
  - `subject` string, required
  - `text_body` string
  - `html_body` string
  - `cc` string[]
  - `bcc` string[]
  - `send_at` string, date-time: Schedule send for a future time (ISO 8601)
  - `labels` string[]: Labels to attach to the message on creation
  - `reply_to` string
  - `headers` object
  - `tracking` boolean: Enable open/click tracking (HTML emails only)
  - `template_id` string, uuid: Render a template instead of using body fields
  - `variables` object: Template variable substitutions
  - `in_reply_to` string: Parent message to thread onto. Accepts either a message_id from this inbox or a raw Message-ID header.
  - `references` string[]: Message-ID headers for threading
  - `attachments` object[]
    - `filename` string
    - `content_type` string
    - `data` string: Base64-encoded file content
  - `calendar_invite` CalendarInvite: A calendar invitation carried in the message body, which is what makes the recipient's mail client show Accept/Decline and puts the event on their calendar. Attaching an .ics file does not do this: it arrives as a download nobody can act on. Times need a zone -- a trailing "Z", an offset, or `timezone`. Attendees default to the message's own to + cc. The send response returns `calendar_uid`; keep it, because rescheduling (same uid, higher sequence) and cancelling (method CANCEL) are matched to the original event by UID.
    - `title` string: Event title, as it appears on the calendar
    - `start` string: ISO 8601 start. A bare date ("2026-09-15") makes it all-day.
    - `end` string: ISO 8601 end. Omit to use duration_minutes.
    - `duration_minutes` integer: Length when `end` is absent
    - `timezone` string: IANA zone for a local time carrying no offset, e.g. "America/New_York". Required for a naive start/end, since otherwise the meeting would land at the wrong hour.
    - `location` string
    - `description` string
    - `attendees` union[]: Defaults to the message's to + cc
      - union
        - string
        - object
          - `email` string
          - `name` string
          - `optional` boolean
    - `reminder_minutes` integer: Alarm this many minutes before the event
    - `all_day` boolean
    - `recurrence` string: RFC 5545 rule, e.g. "FREQ=WEEKLY;COUNT=4"
    - `uid` string: Pass the uid of an event already sent to reschedule or cancel it. Omit for a new invitation.
    - `sequence` integer: Revision number. Must rise above the last one sent whenever an existing event changes, or clients ignore the update.
    - `method` 'REQUEST' | 'CANCEL' | 'PUBLISH': REQUEST asks for an RSVP. CANCEL withdraws an event (uid required). PUBLISH announces one with no RSVP.
    - `ics` string: Your own iCalendar object, instead of the fields above. The MIME method parameter is read from its METHOD line.

## Response `201`

Email sent

## Other responses

- `402`: Payment required. The request had no API key and this route can be paid per call. The x402 requirements are in the PAYMENT-REQUIRED header and repeated in the body; routes priced at or above $0.50 (inbox creation) also carry a Stripe MPP challenge in WWW-Authenticate. A rejected or mismatched payment gets this same response again with error.reason explaining why. Responses are Cache-Control no-store and expose the payment headers to browsers.

---

[API](https://skmtc.dev/deadsimple/apis/dead-simple-email-api.md) · [All operations](https://skmtc.dev/deadsimple/apis/dead-simple-email-api/llms.txt) · [OpenAPI document](https://skmtc.dev/deadsimple/apis/dead-simple-email-api/revisions/c697881be131?raw)
