---
title: "Batch sending"
description: "Send up to 100 distinct messages — schedule and cancel as a unit."
url: https://www.unitpost.com/docs/batch
section: Docs
updated: 2026-07-23
---
# Batch sending

## Batch sending

> Send up to 100 distinct messages — schedule and cancel as a unit.

POST to /api/v1/emails/batch to send many distinct messages in one request. Each entry is its own message with its own recipient, subject, and data. This is not one message to many people — for that, use a campaign.

The body is a JSON array of message objects, or an object { emails: [...], scheduled_at: "<ISO>" } to schedule the batch. Validation is all-or-nothing: if any item is invalid, nothing is queued.

### Group, inspect, cancel

Read a live rollup with GET /api/v1/emails/batches/{id}, and stop every still-scheduled message with POST /api/v1/emails/batches/{id}/cancel. In the dashboard, batches appear under Emails → Batches (/dashboard/emails?status=batches).

**cURL**

```bash
# Schedule the whole batch
curl https://www.unitpost.com/api/v1/emails/batch \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "scheduled_at": "2026-07-01T15:00:00Z",
    "emails": [
      { "from": "you@yourdomain.com", "to": "a@example.com", "subject": "Hi", "html": "<p>…</p>" },
      { "from": "you@yourdomain.com", "to": "b@example.com", "subject": "Hi", "html": "<p>…</p>" }
    ]
  }'

# Cancel the whole batch before it sends
curl -X POST https://www.unitpost.com/api/v1/emails/batches/$BATCH_ID/cancel \
  -H "Authorization: Bearer $API_KEY"
```

**Node.js**

```ts
// Scheduled batch — fires as a unit, cancelable as a unit
const res = await fetch("https://www.unitpost.com/api/v1/emails/batch", {
  method: "POST",
  headers: { Authorization: "Bearer <API_KEY>", "Content-Type": "application/json" },
  body: JSON.stringify({
    scheduled_at: "2026-07-01T15:00:00Z",
    emails: [
      { from: "you@yourdomain.com", to: "a@example.com", subject: "Hi", html: "<p>…</p>" },
      { from: "you@yourdomain.com", to: "b@example.com", subject: "Hi", html: "<p>…</p>" },
    ],
  }),
});
const { batch_id } = await res.json();

// Cancel the whole batch before it sends
await fetch(`https://www.unitpost.com/api/v1/emails/batches/${batch_id}/cancel`, {
  method: "POST",
  headers: { Authorization: "Bearer <API_KEY>" },
});
```

**Python**

```python
# Scheduled batch — fires as a unit, cancelable as a unit
res = requests.post(
    "https://www.unitpost.com/api/v1/emails/batch",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "scheduled_at": "2026-07-01T15:00:00Z",
        "emails": [
            {"from": "you@yourdomain.com", "to": "a@example.com", "subject": "Hi", "html": "<p>…</p>"},
            {"from": "you@yourdomain.com", "to": "b@example.com", "subject": "Hi", "html": "<p>…</p>"},
        ],
    },
)
batch_id = res.json()["batch_id"]

# Cancel the whole batch before it sends
requests.post(
    f"https://www.unitpost.com/api/v1/emails/batches/{batch_id}/cancel",
    headers={"Authorization": f"Bearer {API_KEY}"},
)
```

> **Batch limitations:** Per-item scheduled_at and attachments are not supported in batch — schedule the batch as a unit, or send individually if you need per-message attachments.

## Related

- [Scheduling & canceling sends](https://www.unitpost.com/docs/canceling): Schedule for later and recall a send before it leaves.
- [Idempotency & retries](https://www.unitpost.com/docs/idempotency): Safely retry sends without duplicating mail.
- [Bounces, complaints & suppression](https://www.unitpost.com/docs/deliverability): How bad addresses are handled and where to review them.
