TypeScript
Complete guide to using the Unsent TypeScript SDK for sending emails and managing your email infrastructure
The Unsent TypeScript SDK provides a type-safe, developer-friendly way to integrate email sending capabilities into your TypeScript and JavaScript applications. This comprehensive guide covers everything from installation to advanced features.
Prerequisites
Before you begin, ensure you have:
Node.js 16+: The SDK requires Node.js version 16 or higher
Unsent API Key: Generate one in your Unsent dashboard
Verified Domain: Set up and verify a domain in the Domains section to send emails
Installation
Install the @unsent/sdk package using your preferred package manager:
npm install @unsent/sdkpnpm add @unsent/sdkyarn add @unsent/sdkbun add @unsent/sdkQuick Start
Initialize the SDK
Import and initialize the Unsent client with your API key:
import { unsent } from "@unsent/sdk";
// Option 1: Pass API key directly
const client = new unsent("un_xxxx");
// Option 2: Use environment variable UNSENT_API_KEY
const client = new unsent();
// Option 3: Custom base URL (for testing or self-hosted)
const client = new unsent("un_xxxx", "https://custom-api.example.com");The SDK automatically reads the UNSENT_API_KEY environment variable if no key is provided to the constructor.
Send Your First Email
const { data, error } = await client.emails.send({
to: "recipient@example.com",
from: "sender@yourdomain.com",
subject: "Welcome to Unsent!",
html: "<h1>Hello!</h1><p>Welcome to the best email platform.</p>",
text: "Hello! Welcome to the best email platform."
});
if (error) {
console.error("Failed to send email:", error);
return;
}
console.log("Email sent successfully! ID:", data.emailId);Email Operations
Sending Emails
Basic Email
Send a simple email with HTML and text content:
const { data, error } = await client.emails.send({
to: "user@example.com",
from: "noreply@yourdomain.com",
subject: "Your monthly newsletter",
html: "<h2>Latest Updates</h2><p>Here's what's new this month...</p>",
text: "Latest Updates\n\nHere's what's new this month..."
});Email with Attachments
Attach files to your emails using base64-encoded content:
const { data, error } = await client.emails.send({
to: "customer@example.com",
from: "support@yourdomain.com",
subject: "Your invoice",
html: "<p>Please find your invoice attached.</p>",
attachments: [
{
filename: "invoice-2024-01.pdf",
content: "base64-encoded-content-here",
contentType: "application/pdf"
}
]
});Email with React Components
Use React components for your email templates with @react-email/render:
import { MyEmailTemplate } from "./templates/MyEmailTemplate";
const { data, error } = await client.emails.send({
to: "user@example.com",
from: "hello@yourdomain.com",
subject: "Welcome aboard!",
react: <MyEmailTemplate name="John" company="Acme Inc" />
});React Email components are automatically rendered to HTML. You don't need to provide the html field when using react.
Scheduled Emails
Schedule emails for future delivery:
const scheduledTime = new Date();
scheduledTime.setHours(scheduledTime.getHours() + 24); // Send in 24 hours
const { data, error } = await client.emails.send({
to: "user@example.com",
from: "reminders@yourdomain.com",
subject: "Reminder: Meeting tomorrow",
html: "<p>Don't forget about our meeting tomorrow at 10 AM!</p>",
scheduledAt: scheduledTime.toISOString()
});Custom Headers
Add custom headers to your emails for tracking or integration purposes:
const { data, error } = await client.emails.send({
to: "user@example.com",
from: "marketing@yourdomain.com",
subject: "Campaign email",
html: "<p>Your campaign content here</p>",
headers: {
"X-Campaign-ID": "summer-2024",
"X-Marketing-Source": "newsletter",
"X-Custom-Metadata": "any-value-you-need"
}
});Custom headers are forwarded as-is. Unsent automatically manages X-Unsent-Email-ID and References headers for email threading.
Idempotency Keys
Prevent duplicate sends by using idempotency keys. This is crucial for critical emails like signup confirmations or password resets:
const { data, error } = await client.emails.send(
{
to: "newuser@example.com",
from: "onboarding@yourdomain.com",
subject: "Confirm your email",
html: "<p>Click here to confirm: ...</p>"
},
{
idempotencyKey: `signup-${userId}-${timestamp}`
}
);Reusing the same idempotency key with different payload will return HTTP 409 (Conflict). This ensures retries are safe and prevents accidental duplicate sends with modified content.
Batch Sending
Send up to 100 emails in a single API call for better performance:
const emails = [
{
to: "user1@example.com",
from: "hello@yourdomain.com",
subject: "Welcome User 1",
html: "<p>Welcome User 1!</p>"
},
{
to: "user2@example.com",
from: "hello@yourdomain.com",
subject: "Welcome User 2",
html: "<p>Welcome User 2!</p>"
},
// ... up to 100 emails
];
const { data, error } = await client.emails.batch(emails, {
idempotencyKey: "onboarding-batch-2024-01"
});
if (error) {
console.error("Batch send failed:", error);
} else {
console.log(`Successfully sent ${data.length} emails`);
data.forEach(email => console.log(`Email ID: ${email.id}`));
}Managing Emails
List Emails
Retrieve a paginated list of sent emails with optional filters:
const { data, count, error } = await client.emails.list({
page: 1,
limit: 50,
startDate: "2024-01-01",
endDate: "2024-01-31",
domainId: ["domain_123", "domain_456"] // Filter by specific domains
});
if (error) {
console.error("Failed to fetch emails:", error);
} else {
console.log(`Total emails: ${count}`);
data.forEach(email => {
console.log(`${email.id}: ${email.subject} - ${email.status}`);
});
}Get Email Details
Fetch the status and full details of a specific email:
const { data, error } = await client.emails.get("email_abc123");
if (error) {
console.error("Failed to get email:", error);
} else {
console.log("Email status:", data.status);
console.log("Delivered at:", data.deliveredAt);
console.log("Opened:", data.opened);
console.log("Clicked:", data.clicked);
}Get Email Events
Retrieve the event history for a specific email:
const { data, error } = await client.emails.getEvents("email_abc123");
if (data) {
data.forEach(event => {
console.log(`${event.createdAt}: ${event.type}`);
});
}Update Scheduled Email
Modify a scheduled email before it's sent:
const { data, error } = await client.emails.update("email_abc123", {
subject: "Updated subject",
html: "<p>Updated content</p>",
scheduledAt: new Date(Date.now() + 7200000).toISOString() // Reschedule to 2 hours later
});You can only update emails with status SCHEDULED. Once an email is SENT, it cannot be modified.
Cancel Scheduled Email
Cancel a scheduled email to prevent it from being sent:
const { data, error } = await client.emails.cancel("email_abc123");
if (error) {
console.error("Failed to cancel email:", error);
} else {
console.log("Email cancelled successfully");
}Email Statistics
Get Complaints
Retrieve emails marked as spam:
const { data, count, error } = await client.emails.getComplaints({
page: 1,
limit: 20
});
if (data) {
console.log(`Total complaints: ${count}`);
data.forEach(complaint => {
console.log(`Email: ${complaint.email}, Date: ${complaint.createdAt}`);
});
}Get Bounces
Retrieve bounced emails:
const { data, count, error } = await client.emails.getBounces({
page: 1,
limit: 20
});
if (data) {
console.log(`Total bounces: ${count}`);
data.forEach(bounce => {
console.log(`Email: ${bounce.email}, Reason: ${bounce.bounceType}`);
});
}Get Unsubscribes
Retrieve unsubscribed email addresses:
const { data, count, error } = await client.emails.getUnsubscribes({
page: 1,
limit: 20
});
if (data) {
console.log(`Total unsubscribes: ${count}`);
data.forEach(unsub => {
console.log(`Email: ${unsub.email}, Date: ${unsub.unsubscribedAt}`);
});
}Contact Management
Contact Books
List Contact Books
Get all your contact books:
const { data, error } = await client.contactBooks.list();
if (data) {
data.forEach(book => {
console.log(`${book.emoji} ${book.name} - ${book.contactCount} contacts`);
});
}Create Contact Book
Create a new contact book:
const { data, error } = await client.contactBooks.create({
name: "Newsletter Subscribers",
emoji: "📰"
});
if (data) {
console.log("Contact book created:", data.id);
}Get Contact Book
Retrieve details of a specific contact book:
const { data, error } = await client.contactBooks.get("book_abc123");
if (data) {
console.log(`${data.name}: ${data.contactCount} contacts`);
}Update Contact Book
Update contact book details:
const { data, error } = await client.contactBooks.update("book_abc123", {
name: "Premium Newsletter Subscribers",
emoji: "⭐"
});Delete Contact Book
Delete a contact book and all its contacts:
const { data, error } = await client.contactBooks.delete("book_abc123");
if (data?.success) {
console.log("Contact book deleted successfully");
}Contacts
List Contacts
Get all contacts in a contact book:
const { data, error } = await client.contacts.list("book_abc123");
if (data) {
data.forEach(contact => {
console.log(`${contact.firstName} ${contact.lastName} <${contact.email}>`);
});
}Create Contact
Add a new contact to a contact book:
const { data, error } = await client.contacts.create("book_abc123", {
email: "john.doe@example.com",
firstName: "John",
lastName: "Doe",
subscribed: true,
metadata: {
company: "Acme Inc",
role: "Developer",
plan: "premium"
}
});
if (data) {
console.log("Contact created:", data.id);
}Get Contact
Retrieve a specific contact:
const { data, error } = await client.contacts.get(
"book_abc123",
"contact_xyz789"
);
if (data) {
console.log(`${data.firstName} ${data.lastName}`);
console.log(`Subscribed: ${data.subscribed}`);
console.log(`Metadata:`, data.metadata);
}Update Contact
Update contact information:
const { data, error } = await client.contacts.update(
"book_abc123",
"contact_xyz789",
{
firstName: "Jane",
subscribed: false,
metadata: {
plan: "enterprise",
lastInteraction: new Date().toISOString()
}
}
);Upsert Contact
Create a contact if it doesn't exist, or update if it does:
const { data, error } = await client.contacts.upsert(
"book_abc123",
"contact_xyz789",
{
email: "john.doe@example.com",
firstName: "John",
lastName: "Doe",
subscribed: true
}
);Use upsert when you're not sure if a contact exists. This is perfect for signup flows and contact syncing.
Delete Contact
Remove a contact from a contact book:
const { data, error } = await client.contacts.delete(
"book_abc123",
"contact_xyz789"
);
if (data?.success) {
console.log("Contact deleted successfully");
}Campaign Management
Campaigns allow you to send bulk emails to all contacts in a contact book.
List Campaigns
Get all your campaigns:
const { data, error } = await client.campaigns.list();
if (data) {
data.forEach(campaign => {
console.log(`${campaign.name}: ${campaign.status} - ${campaign.sent}/${campaign.total} sent`);
});
}Create Campaign
Create a new email campaign:
const { data, error } = await client.campaigns.create({
name: "Welcome Series Q1 2024",
subject: "Welcome to our platform!",
html: "<h1>Welcome!</h1><p>Thanks for joining us. Here's what to expect...</p>",
from: "onboarding@yourdomain.com",
contactBookId: "book_abc123",
replyTo: "support@yourdomain.com"
});
if (data) {
console.log("Campaign created:", data.id);
}Campaign emails must include an unsubscribe link for compliance. Unsent automatically adds this if not present.
Get Campaign
Retrieve campaign details and statistics:
const { data, error } = await client.campaigns.get("campaign_123");
if (data) {
console.log(`Campaign: ${data.name}`);
console.log(`Status: ${data.status}`);
console.log(`Progress: ${data.sent}/${data.total} sent`);
console.log(`Opens: ${data.opens}, Clicks: ${data.clicks}`);
}Schedule Campaign
Schedule a campaign to start sending at a specific time:
const { data, error } = await client.campaigns.schedule("campaign_123", {
scheduledAt: "2024-06-01T09:00:00Z",
batchSize: 1000, // Send 1000 emails at a time
batchInterval: 60 // Wait 60 seconds between batches
});
if (data) {
console.log("Campaign scheduled successfully");
}Pause Campaign
Temporarily stop a running campaign:
const { data, error } = await client.campaigns.pause("campaign_123");
if (data) {
console.log("Campaign paused");
}Resume Campaign
Resume a paused campaign:
const { data, error } = await client.campaigns.resume("campaign_123");
if (data) {
console.log("Campaign resumed");
}Domain Management
Manage your sending domains programmatically.
List Domains
Get all your domains and their verification status:
const { data, error } = await client.domains.list();
if (data) {
data.forEach(domain => {
console.log(`${domain.name}: ${domain.verified ? '✓ Verified' : '✗ Not Verified'}`);
});
}Create Domain
Add a new domain for sending:
const { data, error } = await client.domains.create({
name: "yourdomain.com",
region: "us-east-1"
});
if (data) {
console.log("Domain created:", data.id);
console.log("Add these DNS records to verify:");
console.log("DKIM:", data.dkimRecord);
console.log("SPF:", data.spfRecord);
}Get Domain
Retrieve domain details:
const { data, error } = await client.domains.get("123");
if (data) {
console.log(`Domain: ${data.name}`);
console.log(`Verified: ${data.verified}`);
console.log(`Region: ${data.region}`);
}Verify Domain
Check and update domain verification status:
const { data, error } = await client.domains.verify("123");
if (data?.verified) {
console.log("Domain is verified!");
} else {
console.log("Domain verification pending");
console.log("Missing records:", data.missingRecords);
}Delete Domain
Remove a domain:
const { data, error } = await client.domains.delete("123");
if (data?.success) {
console.log("Domain deleted successfully");
}Templates
Create and manage reusable email templates.
List Templates
Get all your templates:
const { data, error } = await client.templates.list();
if (data) {
data.forEach(template => {
console.log(`${template.name}: ${template.subject}`);
});
}Create Template
Create a new email template:
const { data, error } = await client.templates.create({
name: "Welcome Email",
subject: "Welcome to {{company}}!",
html: "<h1>Hello {{firstName}}!</h1><p>Welcome to {{company}}.</p>",
content: "Hello {{firstName}}! Welcome to {{company}}."
});
if (data) {
console.log("Template created:", data.id);
}Use double curly braces {{variable}} for template variables that can be replaced when sending emails.
Get Template
Retrieve a specific template:
const { data, error } = await client.templates.get("template_abc123");
if (data) {
console.log(`Template: ${data.name}`);
console.log(`Subject: ${data.subject}`);
}Update Template
Modify an existing template:
const { data, error } = await client.templates.update("template_abc123", {
subject: "Welcome to our amazing platform!",
html: "<h1>Hello {{firstName}}!</h1><p>We're excited to have you.</p>"
});Delete Template
Remove a template:
const { data, error } = await client.templates.delete("template_abc123");
if (data?.success) {
console.log("Template deleted successfully");
}Send Email with Template
Use a template when sending an email:
const { data, error } = await client.emails.send({
to: "user@example.com",
from: "hello@yourdomain.com",
templateId: "template_abc123",
// Variables for template substitution
variables: {
firstName: "John",
company: "Acme Inc"
}
});Analytics
Retrieve usage statistics and reputation metrics for your account.
Get Usage Statistics
Get overall account usage stats:
const { data, error } = await client.analytics.get();
if (data) {
console.log("Emails sent:", data.emailsSent);
console.log("Bounce rate:", data.bounceRate);
console.log("Complaint rate:", data.complaintRate);
console.log("Open rate:", data.openRate);
}Get Time-Series Data
Retrieve historical analytics data:
const { data, error } = await client.analytics.getTimeSeries({
days: 30 // Last 30 days
});
if (data) {
data.forEach(point => {
console.log(`${point.date}: ${point.sent} sent, ${point.delivered} delivered`);
});
}Get Reputation Score
Check your sending reputation:
const { data, error } = await client.analytics.getReputation();
if (data) {
console.log("Reputation score:", data.score);
console.log("Status:", data.status); // excellent, good, fair, poor
console.log("Recommendations:", data.recommendations);
}API Key Management
Programmatically manage your API keys.
List API Keys
Get all your API keys:
const { data, error } = await client.apiKeys.list();
if (data) {
data.forEach(key => {
console.log(`${key.name}: ${key.permission} (Created: ${key.createdAt})`);
});
}Create API Key
Generate a new API key:
const { data, error } = await client.apiKeys.create({
name: "Production API Key",
permission: "SENDING" // Options: "FULL", "SENDING", "READONLY"
});
if (data) {
console.log("API Key created:", data.key);
console.log("Store this key securely - it won't be shown again!");
}API keys are only shown once upon creation. Make sure to store them securely immediately.
Delete API Key
Revoke an API key:
const { data, error } = await client.apiKeys.delete("key_abc123");
if (data?.success) {
console.log("API key revoked successfully");
}Suppression List
Manage your suppression list to prevent sending to specific email addresses.
List Suppressions
Get all suppressed email addresses:
const { data, error } = await client.suppressions.list({
page: 1,
limit: 50
});
if (data) {
data.forEach(suppression => {
console.log(`${suppression.email}: ${suppression.reason}`);
});
}Add Suppression
Add an email address to the suppression list:
const { data, error } = await client.suppressions.add({
email: "unwanted@example.com",
reason: "MANUAL"
});
if (data) {
console.log("Email suppressed successfully");
}Remove Suppression
Remove an email from the suppression list:
const { data, error } = await client.suppressions.delete("unwanted@example.com");
if (data?.success) {
console.log("Email unsuppressed successfully");
}Suppressed emails will automatically be skipped when sending emails or campaigns.
Webhooks
Coming Soon: Webhooks are currently under development and will be available soon. The SDK methods are already implemented and ready to use once the webhook infrastructure is deployed.
Webhooks will allow you to receive real-time notifications about email events such as deliveries, bounces, opens, and clicks.
List Webhooks
Get all configured webhooks:
const { data, error } = await client.webhooks.list();
if (data) {
data.forEach(webhook => {
console.log(`${webhook.url}: ${webhook.events.join(', ')}`);
});
}Create Webhook
Register a new webhook endpoint:
const { data, error } = await client.webhooks.create({
url: "https://yourdomain.com/webhooks/unsent",
events: [
"email.sent",
"email.delivered",
"email.bounced",
"email.complained",
"email.opened",
"email.clicked"
]
});
if (data) {
console.log("Webhook created:", data.id);
}Update Webhook
Modify an existing webhook:
const { data, error } = await client.webhooks.update("webhook_abc123", {
url: "https://yourdomain.com/webhooks/unsent-v2",
events: ["email.delivered", "email.bounced"]
});Delete Webhook
Remove a webhook:
const { data, error } = await client.webhooks.delete("webhook_abc123");
if (data?.success) {
console.log("Webhook deleted successfully");
}Activity
Retrieve activity logs for your account.
Get Activity
const { data, error } = await client.activity.get({
page: 1,
limit: 20
});
if (data) {
// Process activity logs
}Metrics
Retrieve email metrics.
Get Metrics
const { data, error } = await client.metrics.get();
if (data) {
// Process metrics
}Stats
Get statistical data about your sending.
Get Stats
const { data, error } = await client.stats.get({
startDate: "2024-01-01",
endDate: "2024-01-31"
});
if (data) {
// Process stats
}System
Check system status and version.
Health Check
const { data, error } = await client.system.health();
if (data) {
console.log("System status:", data.status);
}Get Version
const { data, error } = await client.system.version();
if (data) {
console.log("SDK Version:", data.version);
}Teams
Manage team information.
Get Current Team
const { data, error } = await client.teams.get();
if (data) {
console.log("Current Team:", data.name);
}List Teams
const { data, error } = await client.teams.list();
if (data) {
data.forEach(team => console.log(team.name));
}Events
List and filter all email events.
List Events
const { data, error } = await client.events.list({
limit: 50,
page: 1,
status: "DELIVERED"
});
if (data) {
data.forEach(event => {
console.log(`${event.type} - ${event.emailId}`);
});
}Settings
Retrieve your team settings and plan limits.
const { data, error } = await client.settings.get();
if (data) {
console.log("Team name:", data.teamName);
console.log("Plan:", data.plan);
console.log("Daily email limit:", data.dailyEmailLimit);
console.log("Monthly email limit:", data.monthlyEmailLimit);
console.log("Emails sent today:", data.emailsSentToday);
console.log("Emails sent this month:", data.emailsSentThisMonth);
}Error Handling
The SDK uses a consistent error handling pattern. All methods return an object with data and error properties.
Basic Error Handling
const { data, error } = await client.emails.send({
to: "invalid-email",
from: "hello@yourdomain.com",
subject: "Test",
html: "<p>Test email</p>"
});
if (error) {
console.error(`Error ${error.code}: ${error.message}`);
return;
}
// Safe to use data here
console.log("Email sent:", data.emailId);Typed Error Codes
The SDK provides typed error codes for better error handling:
const { data, error } = await client.emails.send(emailPayload);
if (error) {
switch (error.code) {
case "VALIDATION_ERROR":
console.error("Invalid email data:", error.message);
break;
case "RATE_LIMIT_EXCEEDED":
console.error("Rate limit hit, retry after:", error.retryAfter);
break;
case "INSUFFICIENT_CREDITS":
console.error("Out of email credits");
break;
case "DOMAIN_NOT_VERIFIED":
console.error("Sender domain not verified");
break;
default:
console.error("Unexpected error:", error.message);
}
return;
}
console.log("Success:", data.emailId);Handling Network Errors
try {
const { data, error } = await client.emails.send(emailPayload);
if (error) {
console.error("API Error:", error);
return;
}
console.log("Success:", data);
} catch (networkError) {
console.error("Network or unexpected error:", networkError);
}TypeScript Support
The SDK is fully typed with TypeScript, providing excellent IntelliSense and type safety.
Type Inference
// Full type inference
const result = await client.emails.send({
to: "user@example.com",
from: "hello@yourdomain.com",
subject: "Hello",
html: "<p>Test</p>"
});
// TypeScript knows the shape of 'data'
if (result.data) {
const emailId: string = result.data.emailId;
const status: string = result.data.status;
}Type Imports
Import types for better type safety:
import { unsent } from "@unsent/sdk";
import type {
SendEmailPayload,
CreateContactPayload,
Campaign
} from "@unsent/sdk";
const emailPayload: SendEmailPayload = {
to: "user@example.com",
from: "hello@yourdomain.com",
subject: "Typed email",
html: "<p>This is type-safe!</p>"
};
const { data, error } = await client.emails.send(emailPayload);Best Practices
Use Environment Variables
Never hardcode API keys in your source code:
// ✅ Good
const client = new unsent(process.env.UNSENT_API_KEY);
// ❌ Bad
const client = new unsent("un_1234567890abcdef");Implement Retry Logic
For critical emails, implement exponential backoff:
async function sendEmailWithRetry(payload, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
const { data, error } = await client.emails.send(payload);
if (!error) return data;
if (error.code === "RATE_LIMIT_EXCEEDED") {
const delay = Math.pow(2, i) * 1000; // Exponential backoff
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
throw error; // Non-retryable error
}
throw new Error("Max retries exceeded");
}Use Idempotency Keys
Always use idempotency keys for critical emails:
// Good: Prevents duplicate signup emails on retry
await client.emails.send(
signupEmailPayload,
{ idempotencyKey: `signup-${userId}` }
);Batch Operations When Possible
Use batch sending for multiple emails:
// ✅ Efficient: Single API call
await client.emails.batch(emails);
// ❌ Inefficient: Multiple API calls
for (const email of emails) {
await client.emails.send(email);
}Monitor Your Reputation
Regularly check your reputation score and address issues:
const { data } = await client.analytics.getReputation();
if (data.score < 80) {
console.warn("Low reputation score:", data.score);
console.log("Recommendations:", data.recommendations);
// Take action: reduce sending rate, clean contact list, etc.
}Advanced Usage
Custom Base URL
Use a custom API endpoint for testing or self-hosted instances:
const client = new unsent(
"un_xxxx",
"https://custom-api.example.com"
);Concurrent Requests
The SDK is designed to handle concurrent requests efficiently:
const results = await Promise.all([
client.emails.send(email1),
client.emails.send(email2),
client.emails.send(email3)
]);
results.forEach((result, index) => {
if (result.error) {
console.error(`Email ${index + 1} failed:`, result.error);
} else {
console.log(`Email ${index + 1} sent:`, result.data.emailId);
}
});Rate Limiting
Implement client-side rate limiting for high-volume sending:
import pLimit from 'p-limit';
const limit = pLimit(10); // Max 10 concurrent requests
const emailPromises = emails.map(email =>
limit(() => client.emails.send(email))
);
const results = await Promise.all(emailPromises);Migration Guide
From Other Providers
Migrating from other email providers? Here's how common operations map:
// SendGrid equivalent
// sendgrid: sgMail.send({ to, from, subject, html })
const { data, error } = await client.emails.send({ to, from, subject, html });
// Mailgun equivalent
// mailgun: mg.messages.create(domain, { to, from, subject, html })
const { data, error } = await client.emails.send({ to, from, subject, html });
// Postmark equivalent
// postmark: client.sendEmail({ To, From, Subject, HtmlBody })
const { data, error } = await client.emails.send({
to: To,
from: From,
subject: Subject,
html: HtmlBody
});Troubleshooting
Common Issues
Issue: Missing API key error
// Solution: Ensure UNSENT_API_KEY is set or pass key to constructor
const client = new unsent(process.env.UNSENT_API_KEY);Issue: Domain not verified error
// Solution: Verify your domain in the Unsent dashboard
// Add the required DNS records and wait for verificationIssue: Rate limit exceeded
// Solution: Implement retry with backoff or use batch sending
const { error } = await client.emails.send(payload);
if (error?.code === "RATE_LIMIT_EXCEEDED") {
await new Promise(resolve => setTimeout(resolve, error.retryAfter * 1000));
// Retry the request
}Resources
Support
Need help? We're here for you:
- Documentation: docs.unsent.dev
- Email: support@unsent.dev
- Discord: Join our community
- GitHub Issues: Report bugs or request features