> ## Documentation Index
> Fetch the complete documentation index at: https://docs.12m.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Sending email

> How to send a new conversation, how to reply to an existing one, and the operational details that matter at scale.

Sending is one endpoint, two modes:

* **New conversation** — pass `to`, `subject`, and a body. We pick a
  mailbox from the pool, register the conversation, fire `email.sent`.
* **Reply to existing** — pass `convId` and a body. We resolve recipient,
  subject, threading headers, and the bound mailbox from the conv.

```
POST /v1/identities/:handle/send
```

## New conversation

```bash theme={null}
curl https://api.inboxbase.ai/v1/identities/alice.acme@inboxbase.ai/send \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "to":      "morgan@northwindrobotics.com",
    "subject": "Quick intro — fleet rotation",
    "text":    "Hi Morgan, ...",
    "html":    "<p>Hi Morgan, ...</p>"
  }'
```

`text` and `html` can both be set; recipients see the multipart message
their client prefers. Most production senders set both.

If you're stitching to a thread that started outside 12m (e.g. you
imported a CRM history), pass `inReplyTo` and `references`:

```json theme={null}
{
  "to":         "morgan@northwindrobotics.com",
  "subject":    "Re: Fleet rotation",
  "text":      "Following up...",
  "inReplyTo": "<original-message-id@northwindrobotics.com>",
  "references": ["<original-message-id@northwindrobotics.com>"]
}
```

## Reply to a thread

When you have the `convId` from a prior send (or from a webhook),
replying is one field:

```bash theme={null}
curl https://api.inboxbase.ai/v1/identities/alice.acme@inboxbase.ai/send \
  -H "Authorization: Bearer sk_live_..." \
  -d '{
    "convId": "conv_dd6e7130674645d3",
    "text":   "Friday at 10 works."
  }'
```

We pull recipient, subject (with the `Re:` prefix), threading headers,
and — critically — the same backing mailbox from the conversation
state. Recipients see a coherent thread from one consistent sender.

`convId` is mutually exclusive with `to` / `subject`. Cross-identity
replies (a `convId` that lives on a different identity) return `404`.

## Idempotency

Every send accepts an optional `Idempotency-Key` header. Same key with
the same body returns the original response (with
`Idempotent-Replayed: true`); same key with a different body returns
`409`. Keys live for 24 hours.

```bash theme={null}
curl https://api.inboxbase.ai/v1/identities/alice.acme@inboxbase.ai/send \
  -H "Authorization: Bearer sk_live_..." \
  -H "Idempotency-Key: 9b3e84c2-7c0b-4f9c-8cb2-..." \
  -d '{ "to": "morgan@...", "subject": "Hi", "text": "..." }'
```

For sequencers, the right key is `<leadId>:<step>` — if the worker
crashes after we accepted the send but before your DB recorded it, the
retry returns the same response and you don't double-send.

## Response

```json theme={null}
{
  "accepted":  1,
  "rejected":  0,
  "remaining": 49,
  "dailyCap":  150,
  "identity":  "alice.acme@inboxbase.ai",
  "messages": [
    {
      "to":       "morgan@northwindrobotics.com",
      "id":       "<provider-message-id>",
      "status":   "accepted",
      "convId":   "conv_dd6e7130674645d3",
      "affinity": "new",
      "account":  { "id": "acc_...", "email": "alice.chen@tryacme.com" }
    }
  ]
}
```

The fields worth knowing:

* **`convId`** — store this against your lead/contact record. Every
  follow-up uses it.
* **`affinity`** — `new` (we created an affinity row), `existing` (we
  reused the recipient's pinned mailbox), or `reassigned` (the pinned
  mailbox was unhealthy or capped, we picked another).
* **`account.email`** — the rotated mailbox we used. Surfaced for
  transparency and deliverability dashboards. You don't need to act on
  it.
* **`remaining`** — daily-cap budget left on this identity today.

Status code: `202` if anything was accepted, `429` if every recipient
was rejected (typically `cap_exceeded`).

## What we don't support yet

In the interest of not lying to you:

* **Scheduled sends.** No `sendAt`. Every send dispatches immediately.
  If you need "fire at 9am Tuesday in the prospect's timezone," run a
  scheduler in your own infra and call us at fire time. The
  `Idempotency-Key` makes the retry semantics safe.
* **Attachments.** Not supported. If your use case needs them, tell us.
* **Custom headers.** No way to set `List-Unsubscribe` /
  `List-Unsubscribe-Post` today. This is high-priority because
  Gmail/Yahoo bulk-sender requirements increasingly need it; we'll ship
  it.
* **Multi-recipient sends.** `to` accepts an array, but we send to each
  recipient separately so each gets its own conversation. Bulk
  broadcasts to `cc` lists aren't a 12m use case — that's transactional
  email territory.
