SDKs
TypeScript SDK
Official TypeScript/Node.js SDK for the Sendry email API.
Installation
npm install sendry-sdk
# or
bun add sendry-sdk
# or
pnpm add sendry-sdk
The SDK is written in TypeScript and works with Node.js 18+, Bun, Deno, and edge runtimes.
Initialization
import { Sendry } from "sendry-sdk";
// Simple initialization with API key string
const sendry = new Sendry("sn_live_your_api_key");
// Or with configuration options
const sendry = new Sendry({
apiKey: process.env.SENDRY_API_KEY!,
baseUrl: "https://api.sendry.online", // 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 sendry.emails.send({
from: "Acme <hello@acme.com>",
to: "user@example.com",
subject: "Welcome!",
html: "<h1>Welcome to Acme!</h1>",
});
// Send to multiple recipients
await sendry.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 sendry.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 sendry.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 sendry.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 sendry.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 sendry.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 sendry.emails.get("em_abc123");
console.log(email.status); // "delivered"
// List emails with filtering
const { data, has_more, next_cursor } = await sendry.emails.list({
limit: 25,
status: "delivered",
});
// Paginate
if (has_more) {
const nextPage = await sendry.emails.list({ cursor: next_cursor! });
}
// Cancel a scheduled/queued email
await sendry.emails.cancel("em_abc123");
Domains
// Add a domain (returns DNS records to configure)
const domain = await sendry.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 sendry.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 sendry.domains.list();
// Delete a domain
await sendry.domains.remove("dom_abc123");
Templates
// Create a template
const template = await sendry.templates.create({
name: "Welcome Email",
subject: "Welcome, {{name}}!",
html: "<h1>Hi {{name}},</h1><p>Welcome to {{company}}!</p>",
});
// Render a preview
const preview = await sendry.templates.render("tmpl_abc123", {
variables: { name: "Alice", company: "Acme" },
});
console.log(preview.subject); // "Welcome, Alice!"
// List, get, update, delete
await sendry.templates.list();
await sendry.templates.get("tmpl_abc123");
await sendry.templates.update("tmpl_abc123", { subject: "New subject" });
await sendry.templates.remove("tmpl_abc123");
API keys
// Create a new API key (raw key only returned once)
const { key, id } = await sendry.apiKeys.create({
name: "Production Sender",
scope: "sending_access",
});
console.log(key); // "sn_live_..." — save this!
// List all keys (secrets not included)
const { data } = await sendry.apiKeys.list();
// Delete a key
await sendry.apiKeys.remove("ak_abc123");
Webhooks
// Create a webhook
const webhook = await sendry.webhooks.create({
url: "https://yourapp.com/webhooks/sendry",
events: ["email.delivered", "email.bounced"],
});
console.log(webhook.secret); // Save this for verification!
// Manage webhooks
await sendry.webhooks.list();
await sendry.webhooks.get("wh_abc123");
await sendry.webhooks.update("wh_abc123", { active: false });
await sendry.webhooks.remove("wh_abc123");
Analytics
const { summary, timeseries } = await sendry.analytics.stats({
from: "2025-01-01",
to: "2025-01-31",
granularity: "week",
});
const logs = await sendry.analytics.logs({
email_id: "em_abc123",
type: "bounced",
});
Suppression
await sendry.suppression.list();
await sendry.suppression.add({ email: "bad@example.com", reason: "hard_bounce" });
await sendry.suppression.remove("bad@example.com");
Segments
const seg = await sendry.segments.create({ name: "High-Value Users" });
await sendry.segments.addContacts(seg.id, { contact_ids: ["ct_1", "ct_2"] });
const { data } = await sendry.segments.listContacts(seg.id);
Topics
const topic = await sendry.topics.create({
name: "product-updates",
opt_in_required: true,
});
await sendry.topics.subscribe(topic.id, "user@example.com");
Contact properties
await sendry.contactProperties.create({ name: "plan", label: "Plan", type: "string" });
await sendry.contactProperties.setValues("ct_123", { plan: "pro" });
Deliverability insights
const insights = await sendry.deliverabilityInsights.forEmail("em_abc123");
// insights.score — 0-100; insights.checks — per-rule feedback
Email sharing (48h preview links)
const { url, expires_at } = await sendry.emailSharing.create("em_abc123");
Attachment download
const file = await sendry.attachments.download("em_abc123", 0);
await Bun.write(file.filename ?? "attachment.bin", file.content);
Per-domain tracking toggles
await sendry.tracking.setForDomain("dom_abc123", { opens: true, clicks: false });
Exports (CSV)
const { id } = await sendry.exports.create({ resource: "contacts" });
const csv = await sendry.exports.download(id); // poll exports.get() until ready
Postmaster (Gmail Postmaster Tools)
const { data } = await sendry.postmaster.metrics({ domain_id: "dom_abc" });
await sendry.postmaster.sync();
Dead-letter queue (admin)
const { data } = await sendry.dlq.list({ queue: "email-sender" });
await sendry.dlq.retry(data[0].id);
Error handling
import { Sendry, ApiError, AuthenticationError, RateLimitError, ValidationError } from "sendry-sdk";
try {
await sendry.emails.send({ ... });
} catch (error) {
if (error instanceof AuthenticationError) {
// 401 — invalid or expired API key
console.error("Check your SENDRY_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 "sendry-sdk";
Source
github.com/sendry-dev/sendry-js — MIT licensed. Published as sendry-sdk on npm.