Official Node.js / TypeScript SDK for SendCraft
npm install sendcraft-sdkReact Email support (optional):
npm install @react-email/render react react-domimport { SendCraft } from 'sendcraft-sdk';
const client = new SendCraft({ apiKey: process.env.SENDCRAFT_API_KEY });
// Send a transactional email
await client.emails.send({
to: 'user@example.com',
subject: 'Hello!',
html: '<h1>Welcome aboard</h1>',
});Get your API key from the SendCraft Dashboard.
await client.emails.send({
to: 'user@example.com',
toName: 'Alice',
subject: 'Your order shipped',
html: '<p>Your order is on the way!</p>',
text: 'Your order is on the way!', // optional plain-text fallback
from: 'orders@mystore.com', // optional, defaults to account default
fromName: 'My Store',
replyTo: 'support@mystore.com',
cc: 'manager@mystore.com',
bcc: ['audit@mystore.com'],
idempotencyKey: 'order-123-shipped', // prevent duplicate sends
});Send up to 100 emails in one request.
await client.emails.batch([
{ to: 'alice@example.com', subject: 'Hi Alice', html: '<p>Hello</p>' },
{ to: 'bob@example.com', subject: 'Hi Bob', html: '<p>Hello</p>' },
]);await client.emails.schedule({
to: 'user@example.com',
subject: 'Reminder',
html: '<p>Just a reminder!</p>',
scheduledAt: new Date('2026-04-01T09:00:00Z'),
});await client.emails.cancelSchedule('email_id');
await client.emails.updateSchedule('email_id', new Date('2026-05-01T09:00:00Z'));const email = await client.emails.get('email_id');
const { emails, total } = await client.emails.list({ page: 1, limit: 20, status: 'sent' });
const { stats } = await client.emails.stats();
const csvUrl = await client.emails.export({ days: 30 });import WelcomeEmail from './emails/WelcomeEmail';
const html = await client.emails.render({ react: <WelcomeEmail name="Alice" /> });// Create
const { campaign } = await client.campaigns.create({
name: 'Summer Sale',
subject: 'Big discounts inside',
from: 'deals@mystore.com',
html: '<h1>Up to 50% off!</h1>',
recipients: ['a@example.com', 'b@example.com'],
});
// Send
await client.campaigns.send('campaign_id');
// List / Get / Update / Delete
await client.campaigns.list({ page: 1, limit: 10 });
await client.campaigns.get('campaign_id');
await client.campaigns.update('campaign_id', { subject: 'Updated subject' });
await client.campaigns.delete('campaign_id');
// Analytics
const { analytics } = await client.campaigns.analytics('campaign_id');await client.subscribers.add({
email: 'user@example.com',
listId: 'list_id',
firstName: 'Alice',
customFields: { plan: 'pro' },
});
await client.subscribers.import({
listId: 'list_id',
subscribers: [{ email: 'a@b.com' }, { email: 'c@d.com' }],
});
await client.subscribers.list({ page: 1, limit: 50, status: 'active' });
await client.subscribers.update('subscriber_id', { firstName: 'Alicia' });
await client.subscribers.delete('subscriber_id');const { template } = await client.templates.create({
name: 'Welcome Email',
subject: 'Welcome to {{appName}}',
html: '<p>Hi {{firstName}}, welcome!</p>',
});
await client.templates.list();
await client.templates.get('template_id');
await client.templates.update('template_id', { subject: 'New subject' });
await client.templates.delete('template_id');const { domain, dnsRecords } = await client.domains.add('myapp.com');
dnsRecords.forEach(r => console.log(`${r.type} ${r.name} → ${r.value}`));
await client.domains.verify(domain._id);
await client.domains.list();
await client.domains.get('domain_id');
await client.domains.delete('domain_id');await client.webhooks.create({
url: 'https://myapp.com/hooks/sendcraft',
events: ['email.bounced', 'email.opened', 'email.clicked'],
});
await client.webhooks.list();
await client.webhooks.delete('webhook_id');app.post('/hooks/sendcraft', express.raw({ type: 'application/json' }), (req, res) => {
const valid = client.webhooks.verify(
req.body.toString(),
req.headers['x-sendcraft-signature'] as string,
process.env.SENDCRAFT_WEBHOOK_SECRET!,
);
if (!valid) return res.sendStatus(401);
const event = client.webhooks.parse(req.body.toString());
// event.type: 'email.bounced' | 'email.opened' | 'email.clicked' | ...
res.sendStatus(200);
});await client.analytics.overview();
await client.analytics.daily(30);
await client.analytics.campaign('campaign_id');// Segments
await client.segments.list();
await client.segments.create({ name: 'VIP users', rules: [...] });
// API Keys
await client.apiKeys.list();
await client.apiKeys.create('CI key', { permissions: 'sending_access' });
await client.apiKeys.revoke('key_id');
// SMTP warmup
await client.smtp.warmupStatus();import { SendCraft, AuthenticationError, RateLimitError, NotFoundError, SendCraftError } from 'sendcraft-sdk';
try {
await client.emails.send({ to: '...', subject: '...', html: '...' });
} catch (err) {
if (err instanceof AuthenticationError) console.error('Invalid API key');
else if (err instanceof RateLimitError) console.error('Rate limited — retry later');
else if (err instanceof NotFoundError) console.error('Resource not found');
else if (err instanceof SendCraftError) console.error(`API error ${err.status}: ${err.message}`);
else throw err;
}| Class | HTTP | When |
|---|---|---|
AuthenticationError |
401 | Invalid or missing API key |
ForbiddenError |
403 | Insufficient permissions |
NotFoundError |
404 | Resource not found |
RateLimitError |
429 | Too many requests |
ConflictError |
409 | Duplicate resource |
ValidationError |
422 | Invalid request data |
ServerError |
500 | Server error |
Full TypeScript support — all options and responses are typed.
import type { SendEmailOptions, CreateCampaignOptions } from 'sendcraft-sdk';# GitHub Actions
- name: Send deploy notification
env:
SENDCRAFT_API_KEY: ${{ secrets.SENDCRAFT_API_KEY }}
run: |
npx sendcraft-sdk emails.send \
--to team@myapp.com \
--subject "Deployed ${{ github.sha }}"| Package | Description |
|---|---|
@sendcraft/cli |
Official CLI |
sendcraft-mcp |
MCP server for AI agents |
sendcraft-sdk (PyPI) |
Python SDK |
MIT © SendCraft
