The shape of a send
POST /emails takes a sender, one or more recipients, a subject, and a body. Everything else is optional: cc, bcc, reply_to, custom headers, attachments, and tags that follow the message through the delivery log and every webhook it fires.
import { Eusend } from '@eusend_dev/sdk'
const client = new Eusend(process.env.EUSEND_API_KEY)
const { data, error } = await client.emails.send({
from: '[email protected]',
to: '[email protected]',
subject: 'Your order is confirmed',
html: '<p>Thanks for your order!</p>',
tags: { category: 'order_confirmation' },
})
if (error) throw error
console.log(data.id) // em_...The SDKs return a { data, error } pair rather than throwing, so a failed send is a value you branch on. Every error carries a stable machine-readable code — DOMAIN_NOT_VERIFIED is a code you can handle, not a string you have to parse.
Retries that don’t double-send
Networks time out mid-request, and the safe thing to do is retry — but a retried send is a duplicate password reset in someone’s inbox. Pass an Idempotency-Key and the second call returns the first response instead of sending again.
// Safe to retry: the second call returns the first response
// instead of sending a second copy.
await client.emails.send(payload, {
idempotencyKey: `order-${order.id}-confirmation`,
})Batch and scheduled sends
- Batch.
POST /emails/batchtakes up to 100 independent messages in one request. Each one succeeds or fails on its own — a bad recipient in slot 40 doesn’t take the other 99 with it. - Scheduled. Pass
scheduled_atto queue a send up to 30 days out, as an ISO timestamp or a phrase like"tomorrow at 9am". Domain, suppression, and limit checks all run at schedule time, and the message can be rescheduled or canceled until it goes.
Test keys, not a sandbox account
Every account gets eu_test_ keys alongside live ones. Sends made with a test key run the full pipeline — accepted, assigned an ID, recorded in your logs, and firing the complete webhook lifecycle — but are never handed to a receiving mail server. You can build and verify the whole integration, including bounce handling, before a single real message leaves.
Three official SDKs
Node, Python, and Go clients wrap the same API under the same names, so switching languages doesn’t mean relearning the surface. All three are fully typed and report their own version in the User-Agent, so a delivery problem can be traced back to a specific client release.
- Node.js —
@eusend_dev/sdk, with React Email rendering built in. - Python —
eusendon PyPI. - Go — a module the proxy serves straight from the tagged repo.
Add a domain, publish the DNS records we generate, create a key, and POST. The quick start walks the whole path.
Create a free account