# Send a single email

`POST /v1/email` sends one message. It can go to a single recipient or to
several who all share one envelope.

## The request

```bash
curl https://api.anypost.com/v1/email \
  -H "Authorization: Bearer $ANYPOST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "Acme <hello@example.com>",
    "to": ["alex@customer.com"],
    "reply_to": "support@example.com",
    "subject": "Welcome to Acme",
    "html": "<p>Glad you are here.</p>",
    "text": "Glad you are here."
  }'
```

```ts
const { id } = await anypost.email.send({
  from: "Acme <hello@example.com>",
  to: ["alex@customer.com"],
  reply_to: "support@example.com",
  subject: "Welcome to Acme",
  html: "<p>Glad you are here.</p>",
  text: "Glad you are here.",
});
```

```python
client.email.send({
    "from": "Acme <hello@example.com>",
    "to": ["alex@customer.com"],
    "reply_to": "support@example.com",
    "subject": "Welcome to Acme",
    "html": "<p>Glad you are here.</p>",
    "text": "Glad you are here.",
})
```

```php
$client->email->send([
    "from" => "Acme <hello@example.com>",
    "to" => ["alex@customer.com"],
    "reply_to" => "support@example.com",
    "subject" => "Welcome to Acme",
    "html" => "<p>Glad you are here.</p>",
    "text" => "Glad you are here.",
]);
```

```ruby
client.email.send(
  from: "Acme <hello@example.com>",
  to: ["alex@customer.com"],
  reply_to: "support@example.com",
  subject: "Welcome to Acme",
  html: "<p>Glad you are here.</p>",
  text: "Glad you are here."
)
```

```rust
client.email.send(
    &SendEmail::new("Acme <hello@example.com>", ["alex@customer.com"])
        .reply_to("support@example.com")
        .subject("Welcome to Acme")
        .html("<p>Glad you are here.</p>")
        .text("Glad you are here."),
).await?;
```

```go
client.Email.Send(ctx, &anypost.SendEmailRequest{
	From:    "Acme <hello@example.com>",
	To:      []string{"alex@customer.com"},
	ReplyTo: []string{"support@example.com"},
	Subject: "Welcome to Acme",
	HTML:    "<p>Glad you are here.</p>",
	Text:    "Glad you are here.",
})
```

```java
client.email.send(SendEmailRequest.builder()
        .from("Acme <hello@example.com>")
        .to("alex@customer.com")
        .replyTo("support@example.com")
        .subject("Welcome to Acme")
        .html("<p>Glad you are here.</p>")
        .text("Glad you are here.")
        .build());
```

```csharp
await client.Email.SendAsync(new SendEmailRequest
{
    From = "Acme <hello@example.com>",
    To = ["alex@customer.com"],
    ReplyTo = ["support@example.com"],
    Subject = "Welcome to Acme",
    Html = "<p>Glad you are here.</p>",
    Text = "Glad you are here.",
});
```

A `202` response means the message was accepted.

## Fields

| Field | Required | Description |
|---|---|---|
| `from` | Yes | Sender address, on a verified domain. |
| `to` | Yes | Array of recipient addresses, 1 to 50. |
| `cc` | No | Array of copied recipients. Counts toward the 50-recipient total. |
| `bcc` | No | Array of blind-copied recipients. Counts toward the 50-recipient total. |
| `reply_to` | No | One address, or an array of up to 10, that replies are directed to. |
| `subject` | Yes | Subject line, 1 to 998 characters. |
| `text` | One of | Plain-text body, up to 1,000,000 characters. |
| `html` | One of | HTML body, up to 1,000,000 characters. |

Provide `subject` and at least one of `text` or `html`. Sending with a
template can supply all three instead; see
[**Sending with templates**](/docs/templates).

## Address format

`from` and every recipient field accept two forms:

- A bare address: `hello@example.com`.
- A name and address: `Acme <hello@example.com>`. Quote a name that
  contains a comma: `"Acme, Inc." <hello@example.com>`.

A display name appears in the message headers only. The delivery envelope
always uses the bare address. CR and LF characters are stripped from
addresses before the message is built.

The domain in `from` must be verified for your team. A send from an
unverified domain is rejected. See [**Domains & DNS setup**](/docs/domains).

## Recipients

`to`, `cc`, and `bcc` together may name at most 50 recipients. Everyone in
`to` and `cc` is visible to the others in the message headers; `bcc`
recipients are not.

All recipients of one `POST /v1/email` share a single envelope: one message,
delivered to each address. To send distinct messages, with different
subjects or bodies, in one request, use
[**Batch sending**](/docs/batch-sending) instead.

## The response

```json
{
  "id": "email_018f4f3e-7b2c-7c80-8e21-1a3a4f5b6c7d",
  "created_at": "2026-04-30T12:00:00.123000Z"
}
```

The `202` and this `id` mean Anypost accepted the message, not that it was
delivered. Delivery, bounces, and engagement arrive later as events; see
[**Webhooks**](/docs/webhooks). Use the `id` to correlate every event to this message.

An invalid request returns `400` or `422` with a `validation_error` naming
the fields at fault. See [**API conventions**](/docs/api-conventions) for the error shape.

## Idempotency

A retry is made safe by an `Idempotency-Key` header. If the first request
already reached Anypost, the replay returns that original response verbatim
and the message is not sent again. A network failure that leaves the `202`
in doubt costs you nothing to retry.

```bash
curl https://api.anypost.com/v1/email \
  -H "Authorization: Bearer $ANYPOST_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 9f8c2b1e-4a6d-4f1e-8c3a-2b1e4a6d4f1e" \
  -d '{ "from": "Acme <hello@example.com>", "to": ["alex@customer.com"], "subject": "Welcome to Acme", "html": "<p>Glad you are here.</p>" }'
```

```ts
const { id } = await anypost.email.send(
  {
    from: "Acme <hello@example.com>",
    to: ["alex@customer.com"],
    subject: "Welcome to Acme",
    html: "<p>Glad you are here.</p>",
  },
  { idempotencyKey: "9f8c2b1e-4a6d-4f1e-8c3a-2b1e4a6d4f1e" },
);
```

```python
client.email.send(
    {
        "from": "Acme <hello@example.com>",
        "to": ["alex@customer.com"],
        "subject": "Welcome to Acme",
        "html": "<p>Glad you are here.</p>",
    },
    idempotency_key="9f8c2b1e-4a6d-4f1e-8c3a-2b1e4a6d4f1e",
)
```

```php
$client->email->send(
    [
        "from" => "Acme <hello@example.com>",
        "to" => ["alex@customer.com"],
        "subject" => "Welcome to Acme",
        "html" => "<p>Glad you are here.</p>",
    ],
    "9f8c2b1e-4a6d-4f1e-8c3a-2b1e4a6d4f1e",
);
```

```ruby
client.email.send(
  {
    from: "Acme <hello@example.com>",
    to: ["alex@customer.com"],
    subject: "Welcome to Acme",
    html: "<p>Glad you are here.</p>"
  },
  "9f8c2b1e-4a6d-4f1e-8c3a-2b1e4a6d4f1e"
)
```

```rust
client.email.send_with_idempotency_key(
    &SendEmail::new("Acme <hello@example.com>", ["alex@customer.com"])
        .subject("Welcome to Acme")
        .html("<p>Glad you are here.</p>"),
    "9f8c2b1e-4a6d-4f1e-8c3a-2b1e4a6d4f1e",
).await?;
```

```go
client.Email.Send(ctx, &anypost.SendEmailRequest{
	From:    "Acme <hello@example.com>",
	To:      []string{"alex@customer.com"},
	Subject: "Welcome to Acme",
	HTML:    "<p>Glad you are here.</p>",
}, anypost.WithIdempotencyKey("9f8c2b1e-4a6d-4f1e-8c3a-2b1e4a6d4f1e"))
```

```java
client.email.send(SendEmailRequest.builder()
        .from("Acme <hello@example.com>")
        .to("alex@customer.com")
        .subject("Welcome to Acme")
        .html("<p>Glad you are here.</p>")
        .build(), RequestOptions.idempotencyKey("9f8c2b1e-4a6d-4f1e-8c3a-2b1e4a6d4f1e"));
```

```csharp
await client.Email.SendAsync(
    new SendEmailRequest
    {
        From = "Acme <hello@example.com>",
        To = ["alex@customer.com"],
        Subject = "Welcome to Acme",
        Html = "<p>Glad you are here.</p>",
    },
    new RequestOptions { IdempotencyKey = "9f8c2b1e-4a6d-4f1e-8c3a-2b1e4a6d4f1e" });
```

The SDK generates a key for any send when you omit one, so its built-in
retries cannot send twice; pass `idempotencyKey` to set your own.

A stored response is kept for 24 hours. Reusing a key with a different body
is rejected with `422` `idempotency_mismatch`. See
[**API conventions**](/docs/api-conventions) for the full key rules.

## Going further

A send can carry much more than a subject and body:

- **[Sending with templates](/docs/templates):** reuse stored content with `template_id`.
- **[Variables & personalization](/docs/variables):** render per-recipient values into the body.
- **[Attachments & inline images](/docs/attachments):** attach files or embed inline images.
- **[Headers & custom headers](/docs/headers):** attach application-specific headers.
- **[Tags, topics & campaigns](/docs/tags-topics-campaigns):** label a message so its events can be filtered.
- **[Open & click tracking](/docs/tracking):** measure engagement.
- **[Unsubscribe handling](/docs/unsubscribe):** add one-click unsubscribe headers.
- **[Batch sending](/docs/batch-sending):** send many independent messages in one request.
