cmdsend
v1.1.0
Published
Node.js SDK for sending transactional emails via cmdsend.com
Maintainers
Readme
cmdsend
Node.js SDK for sending transactional emails via cmdsend.com
Installation
npm install cmdsendRequires Node.js 18 or later.
Usage
Node.js / Express (ESM)
import { Cmdsend } from "cmdsend";
const client = new Cmdsend(process.env.CMDSEND_API_KEY);
await client.emails.send({
from: "Acme <[email protected]>",
to: ["[email protected]"],
subject: "Welcome to Acme",
html: "<h1>Hello!</h1><p>Thanks for signing up.</p>",
});Node.js / Express (CommonJS)
const { Cmdsend } = require("cmdsend");
const client = new Cmdsend(process.env.CMDSEND_API_KEY);
await client.emails.send({
from: "Acme <[email protected]>",
to: "[email protected]",
subject: "Welcome",
html: "<p>Hi there!</p>",
});Next.js — App Router (Route Handler or Server Action)
// app/api/send/route.ts
import { Cmdsend } from "cmdsend";
import { NextResponse } from "next/server";
const client = new Cmdsend(process.env.CMDSEND_API_KEY!);
export async function POST(req: Request) {
const { email } = await req.json();
await client.emails.send({
from: "Acme <[email protected]>",
to: email,
subject: "You're in!",
html: "<p>Welcome aboard.</p>",
});
return NextResponse.json({ ok: true });
}Next.js — Pages Router (API Route)
// pages/api/send.ts
import type { NextApiRequest, NextApiResponse } from "next";
import { Cmdsend } from "cmdsend";
const client = new Cmdsend(process.env.CMDSEND_API_KEY!);
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
await client.emails.send({
from: "Acme <[email protected]>",
to: req.body.email,
subject: "Welcome",
html: "<p>Thanks for joining!</p>",
});
res.status(200).json({ ok: true });
}Important: Always use this SDK server-side only. Never import it in browser/client components or expose your API key to the frontend.
API Reference
new Cmdsend(apiKey, options?)
Creates a new client. Get your API key from the cmdsend dashboard.
const client = new Cmdsend("cmd_...", {
timeout: 30000, // request timeout in ms (default: 30000)
maxRetries: 3, // retries on 429/5xx errors (default: 3)
});Retries use exponential backoff (1s → 2s → 4s). On 429 responses the SDK respects the Retry-After header if present.
client.emails.send(payload)
Sends a transactional email.
Payload
| Field | Type | Required | Description |
| ---------- | ------------------------ | -------- | ----------------------------------------- |
| from | string | Yes | Sender address, e.g. Name <[email protected]> |
| to | string \| string[] | Yes | Recipient address(es) |
| subject | string | Yes | Email subject line |
| html | string | One of | HTML body |
| text | string | One of | Plain-text body |
| cc | string \| string[] | No | CC address(es) |
| bcc | string \| string[] | No | BCC address(es) |
| reply_to | string | No | Reply-to address |
| tags | Record<string, string> | No | Custom key/value tags for tracking |
Response
{
"id": "3f2a1b4c-...",
"status": "sent",
"created_at": "2025-06-28T10:00:00.000Z",
"recipients": 1
}client.emails.get(id)
Retrieve the status and full event history of a sent email.
const email = await client.emails.get("3f2a1b4c-...");
console.log(email.status); // "delivered"
console.log(email.events); // [{ event_type: "sent", ... }, { event_type: "delivered", ... }]Response
{
"id": "3f2a1b4c-...",
"from_email": "[email protected]",
"to_email": "[email protected]",
"subject": "Welcome",
"status": "delivered",
"created_at": "2025-06-28T10:00:00.000Z",
"sent_at": "2025-06-28T10:00:01.000Z",
"delivered_at": "2025-06-28T10:00:03.000Z",
"events": [
{ "event_type": "sent", "occurred_at": "2025-06-28T10:00:01.000Z", "metadata": {} },
{ "event_type": "delivered", "occurred_at": "2025-06-28T10:00:03.000Z", "metadata": {} }
]
}Error handling
The SDK throws an error with .status (HTTP status code) and .code (error type) on failure. Retryable errors (429, 5xx) are retried automatically before throwing.
try {
await client.emails.send({ ... });
} catch (err) {
console.error(err.message); // human-readable message
console.error(err.status); // 401, 403, 429, etc.
console.error(err.code); // "Unauthorized", "QuotaExceeded", etc.
}| Code | Status | Meaning |
| ----------------- | ------ | ---------------------------------------------- |
| Unauthorized | 401 | Invalid or missing API key |
| Forbidden | 403 | Domain not verified or access not granted |
| QuotaExceeded | 429 | Monthly send limit reached — upgrade your plan |
| ValidationError | 400 | Invalid payload fields |
TypeScript
Full TypeScript types are included — no @types package needed.
import { Cmdsend, EmailPayload, SendEmailResponse, GetEmailResponse } from "cmdsend";
const client = new Cmdsend(process.env.CMDSEND_API_KEY!);
const payload: EmailPayload = {
from: "[email protected]",
to: ["[email protected]"],
subject: "Hello",
html: "<p>Hi there</p>",
};
const result: SendEmailResponse = await client.emails.send(payload);
const detail: GetEmailResponse = await client.emails.get(result.id);Getting Started on cmdsend.com
- Sign up at cmdsend.com
- Verify your sending domain in the dashboard
- Create an API key under Settings → API Keys
- Set
CMDSEND_API_KEYin your environment and use the SDK
License
MIT © cmdsend.com
