Package Exports
- @swiftmails/sdk
- @swiftmails/sdk/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@swiftmails/sdk) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
SwiftMail Node.js SDK
Official Node.js SDK for SwiftMail - A high-performance transactional email service.
Features
- ✅ Enterprise-Grade - Production-ready with advanced features
- ✅ TypeScript Support - Full type definitions included
- ✅ Idempotency - Prevent duplicate sends with automatic key generation
- ✅ Circuit Breaker - Fault tolerance and graceful degradation
- ✅ Rate Limiting - Client-side concurrency control
- ✅ Observability Hooks - Monitor requests, responses, and errors
- ✅ Sandbox Mode - Test without sending real emails
- ✅ Automatic Retry - Exponential backoff with configurable limits
- ✅ Advanced Validation - Email format, attachment size, payload limits
- ✅ Webhook Verification - HMAC-SHA256 signature validation
Installation
npm install @swiftmails/sdkQuick Start
const SwiftMail = require('@swiftmails/sdk');
const client = new SwiftMail('your-api-key');
// Send an email
await client.send({
from: 'sender@yourdomain.com',
to: 'recipient@example.com',
subject: 'Hello from SwiftMail',
html: '<h1>Welcome!</h1><p>This is a test email.</p>',
text: 'Welcome! This is a test email.'
});Configuration
const client = new SwiftMail('your-api-key', {
// Basic config
baseURL: 'https://api.swiftmail.com',
timeout: 30000,
maxRetries: 3,
apiVersion: 'v1',
// Enterprise features
sandbox: false, // Enable sandbox mode
debug: true, // Enable debug logging
structuredLogs: true, // JSON format logs
// Observability hooks
onRequest: (request) => {
console.log('Request:', request);
},
onResponse: (response) => {
console.log('Response:', response);
},
onError: (error) => {
console.error('Error:', error);
},
// Circuit breaker
failureThreshold: 0.5, // Open circuit at 50% failure rate
windowSize: 10, // Track last 10 requests
cooldownTime: 30000, // 30 seconds cooldown
// Rate limiting
maxConcurrentRequests: 5, // Max 5 concurrent requests
// Validation limits
maxAttachmentSize: 10 * 1024 * 1024, // 10MB per attachment
maxPayloadSize: 20 * 1024 * 1024, // 20MB total
maxSubjectLength: 998, // RFC 2822 limit
});API Reference
Send Email
const result = await client.send({
from: 'sender@yourdomain.com',
to: 'recipient@example.com',
subject: 'Email Subject',
html: '<p>HTML content</p>',
text: 'Plain text content',
replyTo: 'reply@yourdomain.com', // Optional
headers: { 'X-Custom': 'value' }, // Optional
tags: ['welcome', 'onboarding'], // Optional
attachments: [{ // Optional
filename: 'document.pdf',
content: 'base64-encoded-content',
contentType: 'application/pdf'
}],
idempotencyKey: 'unique-key-123' // Optional (auto-generated if not provided)
});
console.log(result.id); // Email ID
console.log(result.status); // queued, processing, sent, failedSend with Template
await client.sendTemplate({
template: 'welcome-email',
to: 'newuser@example.com',
from: 'welcome@yourdomain.com',
data: {
name: 'John Doe',
activationLink: 'https://app.example.com/activate/abc123'
}
});Send Bulk Emails
const emails = [
{
from: 'sender@yourdomain.com',
to: 'user1@example.com',
subject: 'Welcome',
html: '<p>Welcome user 1!</p>'
},
{
from: 'sender@yourdomain.com',
to: 'user2@example.com',
subject: 'Welcome',
html: '<p>Welcome user 2!</p>'
}
];
const result = await client.sendBulk(emails);
console.log(result.batchId);Get Email Log
const email = await client.getEmail('email-log-id');
console.log(email.status); // queued, processing, sent, failed
console.log(email.from);
console.log(email.to);
console.log(email.subject);
console.log(email.createdAt);
console.log(email.sentAt);
console.log(email.smtpResponse);List Emails
const results = await client.listEmails({
status: 'sent',
to: 'recipient@example.com',
page: 1,
limit: 50
});
console.log(results.total);
results.emails.forEach(email => {
console.log(`${email.to}: ${email.status}`);
});Auto-Pagination
// Fetches all pages automatically
const allEmails = await client.listAllEmails({
status: 'sent'
});
console.log(`Total: ${allEmails.length}`);Domain Management
// Add domain
const domain = await client.addDomain({ domain: 'yourdomain.com' });
console.log('Add these DNS records:');
domain.dnsRecords.forEach(record => {
console.log(`${record.type} ${record.name} ${record.value}`);
});
// Verify domain
const verification = await client.verifyDomain(domain.id);
console.log('Verified:', verification.verified);
// List domains
const domains = await client.listDomains();Suppression List
// Add to suppression list
await client.suppressEmail('bounced@example.com', 'hard_bounce');
// List suppressions
const suppressions = await client.listSuppressions({ page: 1, limit: 50 });
// Remove from suppression list
await client.unsuppressEmail('bounced@example.com');Webhook Verification
// In your webhook handler
app.post('/webhook', (req, res) => {
const signature = req.headers['x-swiftmail-signature'];
const payload = req.body;
const secret = 'your-webhook-secret';
if (client.verifyWebhook(signature, payload, secret)) {
// Webhook is authentic
console.log('Event:', payload.event);
res.sendStatus(200);
} else {
// Invalid signature
res.sendStatus(401);
}
});Enterprise Features
Idempotency
Prevent duplicate sends with idempotency keys:
// Auto-generated key (recommended)
await client.send({
from: 'orders@shop.com',
to: 'customer@example.com',
subject: 'Order Confirmation',
html: '<p>Your order has been confirmed</p>'
});
// Custom key (for critical operations)
await client.send({
from: 'orders@shop.com',
to: 'customer@example.com',
subject: 'Order Confirmation',
html: '<p>Your order has been confirmed</p>',
idempotencyKey: `order-${orderId}-confirmation`
});Circuit Breaker
Automatic fault tolerance:
// Check circuit state
console.log(client.getCircuitState()); // CLOSED, OPEN, or HALF_OPEN
// Circuit opens automatically when failure rate exceeds threshold
// Prevents cascading failures
// Auto-recovers after cooldown periodRate Limiting
Control concurrent requests:
// Monitor queue
console.log('Queue size:', client.getQueueSize());
console.log('Running requests:', client.getRunningRequests());
// Requests are automatically queued when limit is reached
const promises = emails.map(email => client.send(email));
await Promise.all(promises); // Only 5 run concurrently (configurable)Observability Hooks
Integrate with monitoring services:
const client = new SwiftMail('api-key', {
onRequest: (request) => {
// Send to DataDog, New Relic, etc.
datadog.increment('swiftmail.request');
},
onResponse: (response) => {
// Track successful requests
datadog.increment('swiftmail.success');
},
onError: (error) => {
// Send to Sentry, Rollbar, etc.
sentry.captureException(error);
}
});Sandbox Mode
Test without sending real emails:
const testClient = new SwiftMail('api-key', {
sandbox: true
});
const result = await testClient.send({
from: 'test@example.com',
to: 'user@example.com',
subject: 'Test',
html: '<p>This will NOT be sent</p>'
});
console.log(result);
// { id: 'mock_uuid', status: 'queued', sandbox: true }Error Handling
try {
await client.send({
from: 'invalid-email',
to: 'user@example.com',
subject: 'Test',
html: '<p>Test</p>'
});
} catch (error) {
console.log('Message:', error.message);
console.log('Code:', error.code); // INVALID_EMAIL, MISSING_FIELD, etc.
console.log('Status:', error.status); // HTTP status code
console.log('Request ID:', error.requestId); // For support
console.log('Retryable:', error.retryable); // true/false
if (error.retryable) {
// Can retry manually if needed
}
}Error Codes
| Code | Description | Retryable |
|---|---|---|
MISSING_API_KEY |
API key not provided | No |
MISSING_FIELD |
Required field missing | No |
INVALID_EMAIL |
Invalid email format | No |
INVALID_DOMAIN |
Invalid domain format | No |
MISSING_CONTENT |
No HTML/text/template | No |
SUBJECT_TOO_LONG |
Subject exceeds limit | No |
ATTACHMENT_TOO_LARGE |
Attachment too big | No |
PAYLOAD_TOO_LARGE |
Total payload too big | No |
CIRCUIT_OPEN |
Circuit breaker open | Yes |
TIMEOUT |
Request timeout | Yes |
NETWORK_ERROR |
Network connection error | Yes |
HTTP_5XX |
Server error | Yes |
HTTP_429 |
Rate limit exceeded | Yes |
TypeScript Support
Full TypeScript definitions included:
import SwiftMail, { SendEmailParams, SwiftMailOptions } from '@swiftmails/sdk';
const options: SwiftMailOptions = {
debug: true,
maxRetries: 3,
onRequest: (request) => {
console.log(request.method, request.url);
}
};
const client = new SwiftMail('api-key', options);
const params: SendEmailParams = {
from: 'sender@example.com',
to: 'recipient@example.com',
subject: 'Hello',
html: '<p>Test</p>'
};
await client.send(params);Best Practices
1. Use Idempotency for Critical Emails
// Order confirmations, payment receipts, etc.
await client.send({
from: 'orders@shop.com',
to: customer.email,
subject: 'Order Confirmation',
html: orderTemplate,
idempotencyKey: `order-${orderId}`
});2. Monitor with Observability Hooks
const client = new SwiftMail('api-key', {
onError: (error) => {
if (!error.retryable) {
// Alert on non-retryable errors
alerting.notify('SwiftMail error', error);
}
}
});3. Use Circuit Breaker State
if (client.getCircuitState() === 'OPEN') {
// Fallback: queue for later or use backup service
await queueForLater(email);
} else {
await client.send(email);
}4. Validate Before Sending
// SDK validates automatically, but you can pre-validate
if (!email.match(/^[^\s@]+@[^\s@]+\.[^\s@]+$/)) {
throw new Error('Invalid email');
}5. Use Sandbox for Testing
const client = new SwiftMail(
process.env.SWIFTMAIL_API_KEY,
{
sandbox: process.env.NODE_ENV !== 'production'
}
);Support
- Documentation: https://docs.swiftmail.com
- Issues: https://github.com/Mark-0731/SwiftMail/issues
- Email: support@swiftmail.com
License
MIT License - see LICENSE file for details.
Changelog
See CHANGELOG.md for version history.