TypeScript-first email SDK
The official Mailpipe Node.js SDK provides a type-safe, promise-based interface for sending and receiving email. Built with TypeScript, it works seamlessly in Node.js, Bun, and edge runtimes including Vercel Edge Functions and Cloudflare Workers.
Install the SDK using your preferred package manager:
npm install @mailpipe/sdk
yarn add @mailpipe/sdk
pnpm add @mailpipe/sdk
Requires Node.js 18 or later. The SDK ships with full TypeScript types — no @types package needed.
Initialize the client with your API key. We recommend storing it in an environment variable:
import { MailpipeClient } from '@mailpipe/sdk';
const mailpipe = new MailpipeClient({
apiKey: process.env.MAILPIPE_API_KEY,
});
export default mailpipe;You can also pass additional options when instantiating the client:
import { MailpipeClient } from '@mailpipe/sdk';
const mailpipe = new MailpipeClient({
apiKey: process.env.MAILPIPE_API_KEY,
baseUrl: 'https://api.mailpipe.dev/v1', // default
timeout: 30_000, // 30 seconds
maxRetries: 3, // retry on 5xx errors
headers: {
'X-Custom-Header': 'my-app',
},
});Never expose your API key in client-side code. Use environment variables and server-side rendering.
Send a transactional email with a single method call:
import mailpipe from './client';
const message = await mailpipe.messages.send({
from: 'noreply@yourdomain.com',
to: ['user@example.com'],
subject: 'Welcome to our platform!',
html: '<h1>Welcome!</h1><p>Thanks for signing up.</p>',
text: 'Welcome! Thanks for signing up.',
});
console.log('Sent:', message.id);
// => Sent: msg_01hx7k3p8n2qwertySend to multiple recipients with CC, BCC, reply-to, and custom headers:
const message = await mailpipe.messages.send({
from: {
email: 'invoices@acme.com',
name: 'Acme Billing',
},
to: ['customer@example.com'],
cc: ['accountant@acme.com'],
bcc: ['archive@acme.com'],
replyTo: 'billing@acme.com',
subject: 'Your invoice #INV-2024-001',
html: invoiceHtml,
text: invoiceText,
headers: {
'X-Invoice-Id': 'INV-2024-001',
},
tags: ['invoice', 'billing'],
});Retrieve all mailboxes connected to your account:
const { data: mailboxes } = await mailpipe.mailboxes.list();
for (const mailbox of mailboxes) {
console.log(`${mailbox.email} — ${mailbox.unreadCount} unread`);
}
// => support@acme.com — 12 unread
// => noreply@acme.com — 0 unreadList messages in a specific mailbox with pagination and filters:
const { data: messages, meta } = await mailpipe.messages.list({
mailboxId: 'mbx_01hx7k3abc',
unread: true,
limit: 25,
offset: 0,
});
console.log(`Showing ${messages.length} of ${meta.total} messages`);
// Iterate through all pages
let page = await mailpipe.messages.list({ limit: 50 });
while (page.meta.hasMore) {
for (const msg of page.data) {
await processMessage(msg);
}
page = await mailpipe.messages.list({
limit: 50,
offset: page.meta.offset + page.meta.limit,
});
}Verify and parse incoming webhook events from Mailpipe using the built-in Express middleware:
import express from 'express';
import { MailpipeClient, WebhookEvent } from '@mailpipe/sdk';
const app = express();
const mailpipe = new MailpipeClient({ apiKey: process.env.MAILPIPE_API_KEY });
// Use raw body parser for webhook signature verification
app.post(
'/webhooks/mailpipe',
express.raw({ type: 'application/json' }),
mailpipe.webhooks.middleware({
secret: process.env.MAILPIPE_WEBHOOK_SECRET,
onEvent: async (event: WebhookEvent) => {
switch (event.type) {
case 'message.received':
await handleIncomingEmail(event.data);
break;
case 'message.bounced':
await handleBounce(event.data);
break;
case 'message.opened':
console.log('Email opened by', event.data.recipient);
break;
}
},
})
);
app.listen(3000);For Next.js App Router, use the webhook helper directly:
import { mailpipe } from '@/lib/mailpipe';
import { NextRequest } from 'next/server';
export async function POST(req: NextRequest) {
const body = await req.text();
const signature = req.headers.get('x-mailpipe-signature') ?? '';
const event = await mailpipe.webhooks.constructEvent(body, signature, {
secret: process.env.MAILPIPE_WEBHOOK_SECRET!,
});
if (event.type === 'message.received') {
const { subject, from, html } = event.data;
await db.emails.create({ subject, from, html });
}
return Response.json({ received: true });
}The SDK exports all types you need for a fully type-safe integration:
import type {
// Client configuration
MailpipeClientOptions,
// Sending
SendEmailParams,
SendEmailResponse,
// Messages
EmailMessage,
ListMessagesParams,
ListMessagesResponse,
// Mailboxes
Mailbox,
ListMailboxesResponse,
// Webhooks
WebhookEvent,
MessageReceivedEvent,
MessageBouncedEvent,
MessageOpenedEvent,
MessageClickedEvent,
// Pagination
PaginationMeta,
// Errors
MailpipeError,
RateLimitError,
AuthenticationError,
} from '@mailpipe/sdk';
// Example: strongly-typed event handler
async function handleEvent(event: WebhookEvent) {
if (event.type === 'message.received') {
// event.data is narrowed to MessageReceivedEvent
const { id, from, subject }: MessageReceivedEvent = event.data;
console.log(`New email from ${from}: ${subject}`);
}
}
// Example: build a send params object
const params: SendEmailParams = {
from: 'hello@example.com',
to: ['user@example.com'],
subject: 'Hello',
html: '<p>Hello world</p>',
};All SDK methods throw typed errors that you can catch and inspect:
import {
MailpipeClient,
MailpipeError,
RateLimitError,
AuthenticationError,
} from '@mailpipe/sdk';
const mailpipe = new MailpipeClient({ apiKey: process.env.MAILPIPE_API_KEY });
try {
await mailpipe.messages.send({ /* ... */ });
} catch (err) {
if (err instanceof RateLimitError) {
const retryAfter = err.retryAfter; // seconds until reset
console.error(`Rate limited. Retry after ${retryAfter}s`);
} else if (err instanceof AuthenticationError) {
console.error('Invalid API key — check your credentials');
} else if (err instanceof MailpipeError) {
console.error(`API error ${err.status}: ${err.message}`);
console.error('Request ID:', err.requestId);
} else {
throw err; // re-throw unexpected errors
}
}Explore the full REST API documentation with all available endpoints.
View API Reference