---
title: "Send Email"
method: POST
path: "/emails"
tags: ["Emails"]
---

# Send Email

`POST /emails`

## Request

- Base URL: `https://app.lettr.com/api`
- URL: `https://app.lettr.com/api/emails`
- Auth: HTTP bearer

Send a transactional email with optional attachments, tracking, and personalization. At least one of `html` or `text` content must be provided. Supply `Idempotency-Key` for safe retries using SparkPost native transmission idempotency. Keys are namespaced per Lettr API key and retained by SparkPost for 24 hours. Repeating the same transmission payload returns its original result without another delivery; conflicting payloads or in-progress transmissions return 409. Retry transport failures with the same key. Lettr still validates authorization, domains and sending quota before contacting SparkPost, so an exhausted quota returns 429 even for a retry. Replayed responses do not increment sending counters again. Requests without this header are sent independently.

## Headers

- `Idempotency-Key` string

## Request body

- SendEmailRequest: Email sending request. **Required:** `from`, `to`, and at least one of `html`, `text`, or `template_slug`. The `subject` is required unless `template_slug` is provided — when using a template, the subject defaults to the template's subject (or template name as fallback), but can be overridden. When using `template_slug`, if `project_id` is not provided, the team's default project will be used.
  - `from` string, email, required: Sender email address
  - `from_name` string, nullable: Sender display name
  - `subject` string, nullable: Email subject line. Required when not using a template. When using `template_slug`, defaults to the template's subject (or template name as fallback). If provided alongside a template, overrides the template subject.
  - `to` string[], required: Recipient email addresses
  - `cc` string[]: Carbon copy recipient email addresses
  - `bcc` string[]: Blind carbon copy recipient email addresses
  - `reply_to` string, email, nullable: Reply-To email address
  - `reply_to_name` string, nullable: Reply-To display name
  - `html` string, nullable: HTML content of the email. At least one of `html` or `text` is required, but providing both is recommended for best compatibility across email clients.
  - `text` string, nullable: Plain text content of the email. At least one of `html` or `text` is required, but providing both is recommended for best compatibility across email clients.
  - `amp_html` string, nullable: AMP HTML content for supported email clients
  - `project_id` integer, nullable: Project ID containing the template. If not provided when using template_slug, the team's default project will be used.
  - `template_slug` string, nullable: Template slug to use for email content. When provided, the template's HTML will be used instead of the html field.
  - `template_version` integer, nullable: Specific template version to use. If not provided, the active version will be used.
  - `tag` string: Tag for tracking and analytics. Automatically set from template_slug if not provided.
  - `metadata` object: Custom metadata attached to the email for tracking purposes
  - `headers` object: Custom email headers. Up to 10 headers allowed. Standard envelope headers (From, To, Subject, etc.), SparkPost internal headers (X-MSYS-API), and List-Unsubscribe and List-Unsubscribe-Post headers are managed by the system and cannot be set manually.
  - `substitution_data` object: Variables for template substitution in email content
  - `options` object: Email delivery options
    - `click_tracking` boolean: Enable click tracking for links in the email
    - `open_tracking` boolean: Enable open tracking via tracking pixel
    - `transactional` boolean: Mark email as transactional (not marketing). **Defaults to `true`.** Transactional mail bypasses unsubscribe suppression, so any send a recipient can opt out of must explicitly set this to `false`.
    - `inline_css` boolean: Inline CSS styles in HTML content
    - `perform_substitutions` boolean: Perform variable substitutions in content
  - `attachments` Attachment[]: File attachments. When provided, each attachment must include name, type, and data.
    - `name` string, required: Filename of the attachment
    - `type` string, required: MIME type of the attachment
    - `data` string, required: Base64 encoded file content (no line breaks)

## Response `200`

Email queued for delivery. Free tier teams receive quota headers indicating their usage and limits.

- SendEmailSuccessResponse
  - `message` string, required: Human-readable success message
  - `data` object, required
    - `request_id` string, required: Unique identifier for this email transmission
    - `accepted` integer, required: Number of recipients accepted for delivery
    - `rejected` integer, required: Number of recipients rejected

## Other responses

- `400`: Failed to send email (domain errors)
- `401`: Unauthorized - Missing or invalid API key
- `404`: Template or project not found
- `409`: SparkPost idempotency conflict: the key was used with a different transmission payload, or the original transmission is still processing.
- `422`: Validation error
- `429`: Sending quota exceeded. The response includes quota headers to help determine current usage and when the limit resets.
- `500`: Server error
- `502`: Email transmission failed (upstream provider error). Retry with the same Idempotency-Key so SparkPost can resolve an uncertain outcome without creating a duplicate transmission.
- `503`: Service unavailable - the API key could not be verified, so the request was not processed. This does not mean the key is invalid; retry after the delay given in the Retry-After header.

---

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