@wraps.dev/email
v0.5.0
Published
Beautiful email SDK for AWS SES
Maintainers
Readme
@wraps.dev/email
Beautiful email SDK for AWS SES with React.email support.
Features
- Resend-like developer experience but calls your SES directly (BYOC model)
- Full TypeScript support with comprehensive types
- React.email integration for beautiful templates
- Automatic AWS credential chain resolution
- Template management (create, update, delete, list)
- Bulk email sending (up to 50 recipients)
- Zero vendor lock-in - just a thin wrapper around AWS SES
- Dual CJS + ESM builds - works with any bundler or Node.js
Installation
pnpm add @wraps.dev/emailQuick Start
import { WrapsEmail } from '@wraps.dev/email';
const email = new WrapsEmail({ region: 'us-east-1' });
await email.send({
from: '[email protected]',
to: '[email protected]',
subject: 'Welcome!',
html: '<h1>Hello World</h1>',
});Module Format Support
This package supports both CommonJS and ES Modules:
ESM (modern):
import { WrapsEmail } from '@wraps.dev/email';CommonJS (Node.js):
const { WrapsEmail } = require('@wraps.dev/email');Authentication
Wraps Email uses the AWS credential chain in the following order:
- Explicit credentials passed to constructor
- Environment variables (
AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY) - Shared credentials file (
~/.aws/credentials) - IAM role (EC2, ECS, Lambda)
With explicit credentials
const email = new WrapsEmail({
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
sessionToken: process.env.AWS_SESSION_TOKEN, // optional
},
region: 'us-west-2',
});Using environment variables
export AWS_ACCESS_KEY_ID=your_access_key
export AWS_SECRET_ACCESS_KEY=your_secret_key
export AWS_REGION=us-east-1const email = new WrapsEmail(); // Credentials auto-detectedUsage Examples
Send simple email
const result = await email.send({
from: '[email protected]',
to: '[email protected]',
subject: 'Welcome!',
html: '<h1>Hello World</h1>',
text: 'Hello World', // optional
});
console.log('Message ID:', result.messageId);Send to multiple recipients
await email.send({
from: '[email protected]',
to: ['[email protected]', '[email protected]'],
cc: ['[email protected]'],
bcc: ['[email protected]'],
subject: 'Team Update',
html: '<p>Important announcement</p>',
});React.email Support
import { EmailTemplate } from './emails/Welcome';
await email.send({
from: '[email protected]',
to: '[email protected]',
subject: 'Welcome to our platform',
react: <EmailTemplate name="John" orderId="12345" />,
});Send with attachments
Send emails with file attachments (PDFs, images, documents, etc.). The SDK automatically handles MIME encoding and uses AWS SES SendRawEmail under the hood.
// Single attachment
const result = await email.send({
from: '[email protected]',
to: '[email protected]',
subject: 'Your invoice',
html: '<p>Please find your invoice attached.</p>',
attachments: [
{
filename: 'invoice.pdf',
content: Buffer.from('...'), // Buffer or base64 string
contentType: 'application/pdf', // Optional - auto-detected from filename
},
],
});
// Multiple attachments
await email.send({
from: '[email protected]',
to: '[email protected]',
subject: 'Monthly Report',
html: '<h1>Monthly Report</h1><p>Reports attached</p>',
attachments: [
{
filename: 'report.pdf',
content: pdfBuffer,
contentType: 'application/pdf',
},
{
filename: 'chart.png',
content: imageBuffer,
contentType: 'image/png',
},
{
filename: 'data.csv',
content: csvBuffer,
contentType: 'text/csv',
},
],
});
// Attachment with base64 string
await email.send({
from: '[email protected]',
to: '[email protected]',
subject: 'Document',
html: '<p>Document attached</p>',
attachments: [
{
filename: 'document.pdf',
content: 'JVBERi0xLjQKJeLjz9MK...', // base64 string
contentType: 'application/pdf',
},
],
});Supported attachment features:
- Automatic MIME type detection from file extension
- Base64 encoding handled automatically
- Up to 100 attachments per email
- Maximum message size: 10 MB (AWS SES limit)
- Works with both HTML and plain text emails
- Compatible with React.email components
Send with tags (for SES tracking)
await email.send({
from: '[email protected]',
to: '[email protected]',
subject: 'Newsletter',
html: '<p>Content</p>',
tags: {
campaign: 'newsletter-2025-01',
type: 'marketing',
},
});Template Management
SES templates allow you to store reusable email designs with variables in your AWS account.
Create a template
await email.templates.create({
name: 'welcome-email',
subject: 'Welcome to {{companyName}}, {{name}}!',
html: `
<h1>Welcome {{name}}!</h1>
<p>Click to confirm: <a href="{{confirmUrl}}">Confirm Account</a></p>
`,
text: 'Welcome {{name}}! Click to confirm: {{confirmUrl}}',
});Create template from React.email component
await email.templates.createFromReact({
name: 'welcome-email-v2',
subject: 'Welcome to {{companyName}}, {{name}}!',
react: <WelcomeEmailTemplate />,
// React component should use {{variable}} syntax for SES placeholders
});Send using a template
const result = await email.sendTemplate({
from: '[email protected]',
to: '[email protected]',
template: 'welcome-email',
templateData: {
name: 'John',
companyName: 'Acme Corp',
confirmUrl: 'https://app.com/confirm/abc123',
},
});Bulk send with template (up to 50 recipients)
const results = await email.sendBulkTemplate({
from: '[email protected]',
template: 'weekly-digest',
destinations: [
{
to: '[email protected]',
templateData: { name: 'Alice', unreadCount: 5 },
},
{
to: '[email protected]',
templateData: { name: 'Bob', unreadCount: 12 },
},
],
});Update a template
await email.templates.update({
name: 'welcome-email',
subject: 'Welcome aboard, {{name}}!',
html: '<h1>Welcome {{name}}!</h1>...',
});Get template details
const template = await email.templates.get('welcome-email');
console.log(template.name, template.subject);List all templates
const templates = await email.templates.list();
templates.forEach(t => console.log(t.name, t.createdTimestamp));Delete a template
await email.templates.delete('welcome-email');Error Handling
import { WrapsEmailError, ValidationError, SESError } from '@wraps.dev/email';
try {
await email.send({ ... });
} catch (error) {
if (error instanceof ValidationError) {
// Invalid email address, missing required fields, etc.
console.error('Validation error:', error.message);
console.error('Field:', error.field);
} else if (error instanceof SESError) {
// AWS SES error (rate limit, unverified sender, etc.)
console.error('SES error:', error.message);
console.error('Code:', error.code); // 'MessageRejected', 'Throttling', etc.
console.error('Request ID:', error.requestId);
console.error('Retryable:', error.retryable);
} else {
// Other errors (network, auth, etc.)
console.error('Unknown error:', error);
}
}Configuration Options
interface WrapsEmailConfig {
region?: string; // AWS region (defaults to us-east-1)
credentials?: {
accessKeyId: string;
secretAccessKey: string;
sessionToken?: string;
};
endpoint?: string; // Custom SES endpoint (for testing with LocalStack)
}Testing with LocalStack
const email = new WrapsEmail({
region: 'us-east-1',
endpoint: 'http://localhost:4566',
});API Reference
WrapsEmail
Main client class for sending emails via AWS SES.
Methods
send(params: SendEmailParams): Promise<SendEmailResult>- Send an emailsendTemplate(params: SendTemplateParams): Promise<SendEmailResult>- Send using SES templatesendBulkTemplate(params: SendBulkTemplateParams): Promise<SendBulkTemplateResult>- Bulk send with templatetemplates.create(params: CreateTemplateParams): Promise<void>- Create SES templatetemplates.createFromReact(params: CreateTemplateFromReactParams): Promise<void>- Create template from Reacttemplates.update(params: UpdateTemplateParams): Promise<void>- Update templatetemplates.get(name: string): Promise<Template>- Get template detailstemplates.list(): Promise<TemplateMetadata[]>- List all templatestemplates.delete(name: string): Promise<void>- Delete templatedestroy(): void- Close SES client and clean up resources
Requirements
- Node.js 20+ (LTS)
- AWS SES configured in your AWS account
- Verified sender email addresses in SES
License
MIT
