---
title: "Sending"
description: "Sending from a MachineMail inbox: from addresses, display names, recipients, reply-to, text and HTML bodies, headers, attachments, replies, forwards and limits."
canonical: "https://machinemail.dev/docs/concepts/sending"
---

# Sending

> Sending from a MachineMail inbox: from addresses, display names, recipients, reply-to, text and HTML bodies, headers, attachments, replies, forwards and limits.

Source: https://machinemail.dev/docs/concepts/sending

Every message is sent from an inbox. MachineMail builds the MIME message, sends it, stores a copy with the `SENT` label, threads it and emits `message.sent`.

## Sending a message

**curl**

```bash title="Terminal"
curl https://api.machinemail.dev/v0/inboxes/support-agent@machinemail.dev/messages/send \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to": ["ada@example.com"],
    "subject": "Hello",
    "text": "Sent by an agent.",
    "html": "<p>Sent by an agent.</p>"
  }'
```

**TypeScript**

```ts title="send.ts"
const inbox = encodeURIComponent('support-agent@machinemail.dev');
const res = await fetch(`https://api.machinemail.dev/v0/inboxes/${inbox}/messages/send`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.MACHINEMAIL_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    to: ['ada@example.com'],
    subject: 'Hello',
    text: 'Sent by an agent.',
    html: '<p>Sent by an agent.</p>',
  }),
});
const { message_id, thread_id } = await res.json();
```

**Python**

```python title="send.py"
import os, requests

sent = requests.post(
    "https://api.machinemail.dev/v0/inboxes/support-agent@machinemail.dev/messages/send",
    headers={"Authorization": f"Bearer {os.environ['MACHINEMAIL_API_KEY']}"},
    json={
        "to": ["ada@example.com"],
        "subject": "Hello",
        "text": "Sent by an agent.",
        "html": "<p>Sent by an agent.</p>",
    },
).json()
```

```json title="Response"
{
  "message_id": "msg_01m4fy8h340000kzb2kp66c161",
  "thread_id": "thd_01m4fy8h340001pp6c74x4688h",
  "timestamp": "2026-10-09T09:00:15.844Z"
}
```

The response comes back with `201` once the message has been handed off for delivery. Whether it reached the recipient's server arrives later as a `message.delivered`, `message.bounced` or `message.complained` [event](https://machinemail.dev/docs/concepts/events), and as `delivery_status` on the stored message.

People can send a new message from the dashboard too, with **Compose**. See [Write a new message in the dashboard](https://machinemail.dev/docs/guides/send-from-the-dashboard).

## Request fields

| Field             | Notes                                                                                                                                                                     |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `to`, `cc`, `bcc` | A string or an array of addresses. `Name <addr@example.com>` is accepted. At least one recipient is required across the three, and at most 50, each address counted once. |
| `subject`         | Defaults to empty.                                                                                                                                                        |
| `text`            | Plain-text body.                                                                                                                                                          |
| `html`            | HTML body. Send both `text` and `html` for the best rendering everywhere.                                                                                                 |
| `reply_to`        | A string or array. Sets the `Reply-To` header so replies go elsewhere.                                                                                                    |
| `headers`         | Extra headers as a string-to-string map, such as `{ "X-Ticket-Id": "4821" }`.                                                                                             |
| `attachments`     | See [Attachments](#attachments).                                                                                                                                          |
| `labels`          | Labels for the stored copy, in addition to `SENT`.                                                                                                                        |

## From address and display name

The `From` address is always the inbox's address. You cannot send as another address. If the inbox has a `display_name`, it is used as the sender name:

```text
From: Support agent <support-agent@machinemail.dev>
```

Change it with `PATCH /v0/inboxes/{inbox_id}` and `display_name`. To send from your own domain, create the inbox on a [verified custom domain](https://machinemail.dev/docs/concepts/domains).

## Threading

A new send starts a new thread unless you pass `In-Reply-To` or `References` in `headers` that match a message in the inbox. The easier way to continue a conversation is to use the reply endpoints, which set the headers for you.

| Endpoint                                                  | Recipients                                                                                                       | Subject                                                  |
| --------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
| `POST /v0/inboxes/{inbox_id}/messages/{message_id}/reply` | The original's `Reply-To`, else its sender. For a message you sent, its original recipients. Override with `to`. | `Re: ` added unless present.                             |
| `POST .../{message_id}/reply-all`                         | Sender plus original `to` and `cc`, minus this inbox.                                                            | Same.                                                    |
| `POST .../{message_id}/forward`                           | `to`, `cc` or `bcc` (at least one required).                                                                     | `Fwd: ` added; the original is quoted below your `text`. |

Replies accept `text`, `html`, `to`, `cc`, `bcc`, `reply_to`, `labels`, `attachments` and `headers`. See [Reply in thread](https://machinemail.dev/docs/guides/reply-in-thread).

## Attachments

Each attachment is an object with either base64 `content` or a `url` that MachineMail fetches for you:

```json title="Attachments"
{
  "attachments": [
    { "filename": "invoice.pdf", "content_type": "application/pdf", "content": "JVBERi0xLjcK..." },
    { "url": "https://files.example.com/report.csv" },
    { "filename": "logo.png", "content_type": "image/png", "content": "iVBORw0KGgo...", "content_disposition": "inline", "content_id": "logo" }
  ]
}
```

| Field                               | Notes                                                                                                                                                                                                |
| ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `content`                           | Base64-encoded bytes.                                                                                                                                                                                |
| `url`                               | Public `http` or `https` URL. Fetched once at send time: at most 10 MB, 20 second timeout, no redirects, private addresses refused. `filename` and `content_type` default from the URL and response. |
| `filename`, `content_type`          | Recommended with `content`.                                                                                                                                                                          |
| `content_disposition`, `content_id` | For inline images referenced as `cid:logo` in your HTML.                                                                                                                                             |

A URL that cannot be fetched fails the whole send with a `validation` error naming the attachment, for example `attachments[1].url`. See the [attachments guide](https://machinemail.dev/docs/guides/attachments).

## When sending is refused

| Status             | Cause                                                                                                                                                                                                                                   |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400 validation`   | No recipients, more than 50 recipients (5 from an unclaimed sandbox inbox), an invalid address, or an attachment that could not be loaded.                                                                                              |
| `403 forbidden`    | The inbox is paused, a recipient is [suppressed](https://machinemail.dev/docs/concepts/lists-and-suppressions#suppressions), a recipient is blocked by a `send` list, or the key lacks `message_send` (or `message_reply` for replies). |
| `404 not_found`    | The inbox is not in the key's scope.                                                                                                                                                                                                    |
| `429 rate_limited` | An unclaimed agent's sandbox inbox has used its sends or its different recipients for the past 24 hours (`Retry-After` says when the next send fits).                                                                                   |

All recipients are checked before anything is sent; if one is refused, none receive the message.

## Limits

- One message can have at most 50 recipients across `to`, `cc` and `bcc`, each address counted once. This applies to every way of sending: new messages, replies, reply-all, forwards and drafts. To reach more people, send separate messages.
- Sandbox inboxes of agents that registered themselves and have not been [claimed](https://machinemail.dev/docs/agents/claiming) have caps on messages and different recipients per 24 hours and on recipients per message (see [Rate limits](https://machinemail.dev/docs/reference/rate-limits#sandbox-sends)). Claimed agents and inboxes created with your API keys have no per-inbox send cap.
- Attachments fetched by URL are capped at 10 MB each, and all attachments of a message at 10 MB together.
- Scheduled sending goes through [drafts](https://machinemail.dev/docs/concepts/drafts) with `send_at`.

See [Limits](https://machinemail.dev/docs/reference/limits) for the full list.

## Deliverability

- Send from a [custom domain](https://machinemail.dev/docs/concepts/domains) with SPF and DKIM verified for anything customer-facing. The shared `machinemail.dev` domain is fine for agents talking to services and to each other.
- Include a `text` body even when you send `html`.
- Watch bounce and complaint rates at `/v0/metrics/rates`. Hard bounces and complaints are [suppressed](https://machinemail.dev/docs/concepts/lists-and-suppressions#suppressions) automatically.

## Next

- [Reply in thread](https://machinemail.dev/docs/guides/reply-in-thread)
- [Drafts](https://machinemail.dev/docs/concepts/drafts)
- [Attachments](https://machinemail.dev/docs/guides/attachments)
