SDKs
TypeScript SDK
Official TypeScript/Node.js SDK for the Sendr email API.
Installation
npm install sendr
# or
bun add sendr
# or
pnpm add sendr
The SDK is written in TypeScript and works with Node.js 18+, Bun, Deno, and edge runtimes.
Initialization
import { Sendr } from "sendr";
// Simple initialization with API key string
const sendr = new Sendr("sndr_live_your_api_key");
// Or with configuration options
const sendr = new Sendr({
apiKey: process.env.SENDR_API_KEY!,
baseUrl: "https://api.sendr.dev", // Override base URL
timeout: 30000, // Request timeout in ms (default: 30s)
retries: 2, // Retry count for 5xx errors (default: 2)
headers: { "X-App-Version": "1.0" }, // Extra headers on every request
});
Emails
// Send a single email
const { id, status } = await sendr.emails.send({
from: "Acme <hello@acme.com>",
to: "user@example.com",
subject: "Welcome!",
html: "<h1>Welcome to Acme!</h1>",
});
// Send to multiple recipients
await sendr.emails.send({
from: "hello@acme.com",
to: ["alice@example.com", "bob@example.com"],
subject: "Team announcement",
html: "<p>Big news...</p>",
});
// Send with attachments
await sendr.emails.send({
from: "billing@acme.com",
to: "user@example.com",
subject: "Your invoice",
html: "<p>Please find your invoice attached.</p>",
attachments: [
{
filename: "invoice.pdf",
content: Buffer.from(pdfBytes).toString("base64"),
content_type: "application/pdf",
},
],
});
// Schedule a future send
await sendr.emails.send({
from: "hello@acme.com",
to: "user@example.com",
subject: "Reminder",
html: "<p>Don't forget your appointment tomorrow.</p>",
scheduled_at: "2025-03-15T09:00:00Z",
});
// Send using a template
await sendr.emails.send({
from: "hello@acme.com",
to: "user@example.com",
template_id: "tmpl_abc123",
variables: { name: "Alice", plan: "Pro" },
});
// Send up to 100 emails in one request
const { data } = await sendr.emails.sendBatch({
from: "hello@acme.com",
subject: "Order update",
emails: [
{ to: "alice@example.com", html: "<p>Alice, your order shipped!</p>" },
{ to: "bob@example.com", html: "<p>Bob, your order shipped!</p>" },
],
});
// Send marketing email (includes List-Unsubscribe)
await sendr.emails.sendMarketing({
from: "Newsletter <news@acme.com>",
to: "user@example.com",
subject: "March Update",
html: "<p>Here's what happened this month...</p>",
unsubscribe_url: "https://acme.com/unsubscribe?id=abc123",
});
// Get email status
const email = await sendr.emails.get("em_abc123");
console.log(email.status); // "delivered"
// List emails with filtering
const { data, has_more, next_cursor } = await sendr.emails.list({
limit: 25,
status: "delivered",
});
// Paginate
if (has_more) {
const nextPage = await sendr.emails.list({ cursor: next_cursor! });
}
// Cancel a scheduled/queued email
await sendr.emails.cancel("em_abc123");
Domains
// Add a domain (returns DNS records to configure)
const domain = await sendr.domains.create({ name: "acme.com" });
console.log(domain.dns_records); // Array of DNS records to add
// Verify a domain after DNS propagation
const result = await sendr.domains.verify("dom_abc123");
console.log(result.status); // "verified"
console.log(result.spf_verified, result.dkim_verified, result.dmarc_verified);
// List all domains
const { data } = await sendr.domains.list();
// Delete a domain
await sendr.domains.remove("dom_abc123");
Templates
// Create a template
const template = await sendr.templates.create({
name: "Welcome Email",
subject: "Welcome, {{name}}!",
html: "<h1>Hi {{name}},</h1><p>Welcome to {{company}}!</p>",
});
// Render a preview
const preview = await sendr.templates.render("tmpl_abc123", {
variables: { name: "Alice", company: "Acme" },
});
console.log(preview.subject); // "Welcome, Alice!"
// List, get, update, delete
await sendr.templates.list();
await sendr.templates.get("tmpl_abc123");
await sendr.templates.update("tmpl_abc123", { subject: "New subject" });
await sendr.templates.remove("tmpl_abc123");
API keys
// Create a new API key (raw key only returned once)
const { key, id } = await sendr.apiKeys.create({
name: "Production Sender",
scope: "sending_access",
});
console.log(key); // "sndr_live_..." — save this!
// List all keys (secrets not included)
const { data } = await sendr.apiKeys.list();
// Delete a key
await sendr.apiKeys.remove("ak_abc123");
Webhooks
// Create a webhook
const webhook = await sendr.webhooks.create({
url: "https://yourapp.com/webhooks/sendr",
events: ["email.delivered", "email.bounced"],
});
console.log(webhook.secret); // Save this for verification!
// Manage webhooks
await sendr.webhooks.list();
await sendr.webhooks.get("wh_abc123");
await sendr.webhooks.update("wh_abc123", { active: false });
await sendr.webhooks.remove("wh_abc123");
Analytics
const { summary, timeseries } = await sendr.analytics.stats({
from: "2025-01-01",
to: "2025-01-31",
granularity: "week",
});
const logs = await sendr.analytics.logs({
email_id: "em_abc123",
type: "bounced",
});
Suppression
await sendr.suppression.list();
await sendr.suppression.add({ email: "bad@example.com", reason: "hard_bounce" });
await sendr.suppression.remove("bad@example.com");
Error handling
import { Sendr, ApiError, AuthenticationError, RateLimitError, ValidationError } from "sendr";
try {
await sendr.emails.send({ ... });
} catch (error) {
if (error instanceof AuthenticationError) {
// 401 — invalid or expired API key
console.error("Check your SENDR_API_KEY");
} else if (error instanceof RateLimitError) {
// 429 — back off and retry
const retryAfter = error.retryAfter; // seconds to wait
await sleep(retryAfter * 1000);
} else if (error instanceof ValidationError) {
// 422 — request body failed validation
console.error(error.details);
} else if (error instanceof ApiError) {
// All other API errors
console.error(error.statusCode, error.code, error.message);
}
}
See Error Codes for the full list of error codes.
TypeScript types
All request and response types are exported:
import type {
SendEmailRequest,
BatchEmailRequest,
EmailItem,
DomainItem,
WebhookItem,
AnalyticsStats,
} from "sendr";