Send a batch of emails
Queues up to 100 emails in one request. Each email is handled exactly as by POST /v1/emails (sender checks, suppressions, scheduling, attachments, tracking), but the batch is all or nothing: if any email is invalid, or any from is not a verified domain (live keys), nothing is stored and the error names the email (e.g. emails.3.to). One Idempotency-Key covers the whole batch. The emails' recipients are charged against the send quota together, so a batch with more recipients than the quota allows at once is refused (quota_exceeded without Retry-After): split it. The request body shares the 40 MB limit of a single send.
bearerAuthAuthorizationBearer <token>A secret API key from the dashboard: coss_live_… for production environments, coss_test_… for sandbox environments.
Idempotency-Key?stringMakes retries safe: a repeated request with the same key and body returns the original email (with its current status) instead of sending again, for 24 hours. 1-256 characters.
1 <= length <= 256Coss-Version?"2026-10-10"The API version (a date) to use for this request. Defaults to your organization's version, pinned to the latest one when it first used the API and upgraded from the dashboard. The SDK always sends the version it was built for.
"2026-10-10"application/json- body
emails*array<>Up to 100 emails, each accepted by POST /v1/emails. The batch is accepted or rejected as a whole.
1 <= items <= 100The batch, accepted for delivery, with its emails in request order. A replay returns the original batch with the emails' current statuses.
application/json- response
object*"email_batch""email_batch"id*stringdata*array<>The batch's emails, in the order of the request.
created_at*stringdate-timeimport { Coss } from "coss";const coss = new Coss({ apiKey: process.env.COSS_API_KEY, baseUrl: "https://api.coss.com",});const { data, error } = await coss.email.sendBatch([ { from: "Acme <notifications@acme.com>", to: "ada@example.com", subject: "Your weekly summary", html: "<p>Hi Ada, here is your week.</p>", category: "digest", }, { from: "Acme <notifications@acme.com>", to: "grace@example.com", subject: "Your weekly summary", html: "<p>Hi Grace, here is your week.</p>", category: "digest", },]);{ "object": "email_batch", "id": "batch_01k8d0n6x5f3w2e1r9t7y4u6i8", "data": [ { "object": "email", "id": "email_01k7c8m4q2f3e9v6t5r1n0p8yz", "from": "Acme <notifications@acme.com>", "to": [ "ada@example.com" ], "cc": [], "bcc": [], "reply_to": [], "subject": "Your weekly summary", "html": "<p>Hi Ada, here is your week.</p>", "text": null, "headers": {}, "tags": [], "category": "digest", "status": "queued", "recipients": [ { "address": "ada@example.com", "type": "to", "status": "queued", "last_event_at": null } ], "sandbox": false, "tracking": { "opens": false, "clicks": false, "open_count": 0, "first_opened_at": null, "last_opened_at": null, "click_count": 0, "first_clicked_at": null, "last_clicked_at": null }, "attachments": [], "created_at": "2026-10-10T12:00:00.000Z", "sent_at": null, "scheduled_at": null, "batch_id": "batch_01k8d0n6x5f3w2e1r9t7y4u6i8" } ], "created_at": "2026-10-10T12:00:00.000Z"}Reschedule a scheduled email POST
Moves an email sent with a future `scheduled_at` to a new time, at most 30 days from now, and records an `email.rescheduled` event. A time that is not in the future sends it within seconds. Rescheduling to the time it already has returns it unchanged. The domain and the suppression list are still checked when it is sent.
Send an email POST
Queues an email from the API key's environment and returns it with `status: "queued"`; it is handed to the delivery provider moments later. Follow it with `GET /v1/emails/{id}` or the `email.sent` / `email.failed` webhooks. Live (`coss_live_…`) keys must send from a verified domain of the organization. Sandbox (`coss_test_…`) keys accept any `from` and never deliver anything; the response has `sandbox: true`. Recipients on the environment's suppression list (for every email, or for the email's `category`) are skipped and get the status `suppressed`. With a future `scheduled_at` the email is stored with the status `scheduled` and sent at that time; the domain and the suppression list are checked again then. Attachments are base64-encoded; only metadata is kept after sending. Recipients count against the organization's send quota (per second and per day; sandbox environments have their own daily quota). With open or click tracking on (the environment's settings, or `tracking`), the HTML body is delivered with a tracking pixel and/or links rewritten to COSS redirects; the stored `html` stays as sent.