Skip to content
DocumentationAPI reference Build something worth sending.

Sending email

Sending email

Send with the SDK or REST API, use idempotency keys and paginate message history.

Send from your server

Complete the quickstart and domain setup, then submit an email with the SDK or REST API. A successful request returns the message ID and queued status.

bash
curl https://api.sendpanda.email/v1/emails \
  -H "Authorization: Bearer $SENDPANDA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: welcome-account-123" \
  -d '{
    "from": "Your app <hello@your-verified-domain.com>",
    "to": ["your-own-address@example.com"],
    "subject": "Hello from SendPanda",
    "text": "Your integration is working."
  }'

Use html and/or text, or a published template_id with variables. Add cc, bcc, reply_to, tags and string-valued metadata when needed. See the API reference for the request schema.

Prevent duplicate sends

Reuse one idempotency key for retries of the same business event. A timeout can happen after acceptance: retry with the same key and unchanged payload to retrieve the stored message ID. Different content with the same key returns 409.

Keys are project-scoped and retained with message metadata. An idempotency key identifies one event; it is separate from your API key. The SDK retries reads and keyed sends, and never automatically retries an unkeyed send. Read the idempotency guide for examples.

Request limits

  • Maximum 50 total unique To, CC and BCC recipients per message.
  • Maximum 500 KB JSON request payload.
  • Include a nonempty HTML/text body or a published template.
  • Use valid mailboxes and a verified sender domain.
  • Tags use ASCII letters, numbers, underscores and dashes; sendpanda_id is reserved.
  • Unsafe HTML and URL destinations are rejected.
  • Account readiness, quotas, rate limits and suppressions apply to every send, including tests.

Search and pagination

GET /emails supports status, recipient, domain (domain ID), after/before (ISO UTC timestamps), and tag (tag name or value substring). Pages contain up to 50 messages plus next_cursor; pass that opaque value as cursor with the same filters to fetch older messages. Timestamp and message ID ordering preserves messages created together. before is exclusive.

GET /usage returns the organisation's UTC calendar-month recipient usage and a projects breakdown. Definitive failures before submission and queued cancellations release their reservations.

ts
const page = await panda.emails.list({ status: "delivered" });
if (page.next_cursor) {
  const next = await panda.emails.list({
    status: "delivered",
    cursor: page.next_cursor,
  });
}

Cancel a queued email

Use panda.emails.cancel(id) or POST /v1/emails/{id}/cancel. Cancellation is possible only before the worker claims the message. Messages already submitted to a receiving server cannot be recalled.

↑↓ to navigate↵ to openesc to close