unsent
unsent.dev
Get Started

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/sdk
pnpm add @unsent/sdk
yarn add @unsent/sdk
bun add @unsent/sdk

Quick 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 verification

Issue: 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:

On this page

PrerequisitesInstallationQuick StartInitialize the SDKSend Your First EmailEmail OperationsSending EmailsBasic EmailEmail with AttachmentsEmail with React ComponentsScheduled EmailsCustom HeadersIdempotency KeysBatch SendingManaging EmailsList EmailsGet Email DetailsGet Email EventsUpdate Scheduled EmailCancel Scheduled EmailEmail StatisticsGet ComplaintsGet BouncesGet UnsubscribesContact ManagementContact BooksList Contact BooksCreate Contact BookGet Contact BookUpdate Contact BookDelete Contact BookContactsList ContactsCreate ContactGet ContactUpdate ContactUpsert ContactDelete ContactCampaign ManagementList CampaignsCreate CampaignGet CampaignSchedule CampaignPause CampaignResume CampaignDomain ManagementList DomainsCreate DomainGet DomainVerify DomainDelete DomainTemplatesList TemplatesCreate TemplateGet TemplateUpdate TemplateDelete TemplateSend Email with TemplateAnalyticsGet Usage StatisticsGet Time-Series DataGet Reputation ScoreAPI Key ManagementList API KeysCreate API KeyDelete API KeySuppression ListList SuppressionsAdd SuppressionRemove SuppressionWebhooksList WebhooksCreate WebhookUpdate WebhookDelete WebhookActivityGet ActivityMetricsGet MetricsStatsGet StatsSystemHealth CheckGet VersionTeamsGet Current TeamList TeamsEventsList EventsSettingsError HandlingBasic Error HandlingTyped Error CodesHandling Network ErrorsTypeScript SupportType InferenceType ImportsBest PracticesUse Environment VariablesImplement Retry LogicUse Idempotency KeysBatch Operations When PossibleMonitor Your ReputationAdvanced UsageCustom Base URLConcurrent RequestsRate LimitingMigration GuideFrom Other ProvidersTroubleshootingCommon IssuesResourcesSupport