Menu

SDK Reference

Complete reference for the @mailloop/sdk TypeScript SDK.

7 min read

The official Mailloop SDK for JavaScript and TypeScript. Zero dependencies, full type safety, and dual ESM/CommonJS builds.

Installation

BASH
# npm
npm install @mailloop/sdk

# yarn
yarn add @mailloop/sdk

# pnpm
pnpm add @mailloop/sdk

Requirements: Node.js 18 or later (uses native fetch).

MailloopClient

The main entry point for the SDK.

TYPESCRIPT
import { MailloopClient } from '@mailloop/sdk';

const client = new MailloopClient({
  apiKey: 'ml_live_your_api_key_here'
});

Options

OptionTypeRequiredDefaultDescription
apiKeystringYes--API key from the dashboard
baseUrlstringNohttps://api.mailloop.io/v1API base URL
timeoutnumberNo30000Request timeout in milliseconds

Sandboxes

Manage email testing sandboxes.

client.sandboxes.create(params)

Create a new persistent sandbox.

TYPESCRIPT
const sandbox = await client.sandboxes.create({
  name: 'my-sandbox'
});

Parameters:

ParamTypeRequiredDescription
namestringYesSandbox name (1–100 characters)

Returns: Sandbox

client.sandboxes.createTemporary(params)

Create a sandbox that auto-deletes after the specified duration. Ideal for CI/CD and automated tests.

TYPESCRIPT
const sandbox = await client.sandboxes.createTemporary({
  duration: 30,
  name: 'ci-test'
});

Parameters:

ParamTypeRequiredDescription
durationnumberYesSeconds until auto-deletion (1–60)
namestringNoOptional sandbox name

Returns: Sandbox with isTemporary: true and deleteAfter set.

client.sandboxes.list()

List all sandboxes for your organization.

TYPESCRIPT
const { sandboxes } = await client.sandboxes.list();

Returns: { sandboxes: Sandbox[] }

client.sandboxes.get(id)

Get a sandbox by ID.

TYPESCRIPT
const sandbox = await client.sandboxes.get('sandbox-id');

Returns: Sandbox

client.sandboxes.update(id, params)

Update a sandbox.

TYPESCRIPT
const updated = await client.sandboxes.update('sandbox-id', {
  name: 'renamed-sandbox'
});

Parameters:

ParamTypeRequiredDescription
namestringNoNew sandbox name

Returns: Sandbox

client.sandboxes.delete(id)

Permanently delete a sandbox and all its emails.

TYPESCRIPT
await client.sandboxes.delete('sandbox-id');

Returns: void


Emails

List, retrieve, and wait for emails in a sandbox.

client.emails.list(sandboxId, params?)

List emails in a sandbox, ordered by received time (newest first).

TYPESCRIPT
const { emails, total } = await client.emails.list('sandbox-id', {
  limit: 10,
  offset: 0
});

for (const email of emails) {
  console.log(`${email.from}: ${email.subject}`);
}

Parameters:

ParamTypeRequiredDefaultDescription
limitnumberNo20Max emails to return (1–100)
offsetnumberNo0Number of emails to skip
afterstringNo--Return emails after this email ID

Returns: { emails: EmailSummary[], total: number }

client.emails.get(sandboxId, emailId)

Get the full details of a specific email, including HTML body, headers, and attachments.

TYPESCRIPT
const email = await client.emails.get('sandbox-id', 'email-id');

console.log(email.subject);
console.log(email.html);
console.log(email.headers);
console.log(email.attachments);

Returns: EmailDetail

client.emails.waitFor(sandboxId, params?)

Wait for an email matching the given filters to arrive. The server polls internally and returns when a match is found.

TYPESCRIPT
// Wait for any email
const email = await client.emails.waitFor('sandbox-id');

// Wait for an email from a specific sender
const email = await client.emails.waitFor('sandbox-id', {
  from: '[email protected]',
  timeout: 45000
});

// Wait for an email with a specific subject
const email = await client.emails.waitFor('sandbox-id', {
  subject: 'Password Reset'
});

Parameters:

ParamTypeRequiredDefaultDescription
timeoutnumberNo30000Max wait time in ms (max 60000)
fromstringNo--Filter by sender address
tostringNo--Filter by recipient address
subjectstringNo--Filter by subject (substring match)

Returns: EmailDetail

Throws: TimeoutError if no matching email arrives within the timeout.

TYPESCRIPT
import { TimeoutError } from '@mailloop/sdk';

try {
  const email = await client.emails.waitFor('sandbox-id', {
    subject: 'Welcome',
    timeout: 10000
  });
} catch (error) {
  if (error instanceof TimeoutError) {
    console.log('No matching email arrived within 10 seconds');
  }
}

client.emails.send(params) (Experimental)

Note: This method is experimental and may change without notice.

Send a transactional email with block-based content.

TYPESCRIPT
const result = await client.emails.send({
  from: '[email protected]',
  to: ['[email protected]'],
  subject: 'Your order has shipped',
  blocks: [
    { type: 'heading', content: 'Order Shipped', level: 2 },
    { type: 'paragraph', content: 'Your order #4821 is on its way.' },
    { type: 'button', text: 'Track Package', href: 'https://acme.com/track/4821' }
  ],
  layout: {
    primaryColor: '#4F46E5',
    companyName: 'Acme Inc.'
  }
});

console.log(result.id);     // Email ID
console.log(result.status); // "sent" or "failed"

Block types: paragraph, heading, button, image, spacer, divider, code, list, callout.


Types

Sandbox

TYPESCRIPT
interface Sandbox {
  id: string;
  name: string;
  username: string;
  password: string;
  emailAddress: string;   // [email protected]
  emailCount: number;
  isTemporary: boolean;
  deleteAfter: string | null; // ISO timestamp
  createdAt: string;          // ISO timestamp
  updatedAt: string;          // ISO timestamp
}

EmailSummary

Returned by emails.list(). Contains metadata without the full body.

TYPESCRIPT
interface EmailSummary {
  id: string;
  from: string;
  to: string[];
  subject: string;
  preview: string;          // First 128 characters of plain text
  hasAttachments: boolean;
  receivedAt: string;       // ISO timestamp
}

EmailDetail

Returned by emails.get() and emails.waitFor(). Contains the full email body, headers, and attachment metadata.

TYPESCRIPT
interface EmailDetail {
  id: string;
  messageId: string;
  from: string;
  to: string[];
  cc: string[] | null;
  bcc: string[] | null;
  subject: string;
  text: string | null;
  html: string | null;
  headers: Record<string, string>;
  hasAttachments: boolean;
  attachments: EmailAttachment[];
  receivedAt: string;       // ISO timestamp
}

EmailAttachment

TYPESCRIPT
interface EmailAttachment {
  id: string;
  filename: string;
  contentType: string;
  size: number;             // Size in bytes
  checksum: string;
}

Error Handling

The SDK throws typed errors for different failure modes:

TEXT
MailloopError (base class)
├── AuthenticationError  (401 - invalid or missing API key)
├── PermissionError      (403 - insufficient permissions)
├── NotFoundError        (404 - resource not found)
├── RateLimitError       (429 - too many requests)
├── TimeoutError         (waiting for email timed out)
└── ValidationError      (400 - invalid request data)

All errors extend MailloopError and include these properties:

PropertyTypeDescription
messagestringHuman-readable message
codestringMachine-readable code
statusnumber | undefinedHTTP status code
detailsRecord<string, unknown> | undefinedAdditional context

RateLimitError also includes a retryAfter property (seconds until the limit resets).

Example

TYPESCRIPT
import {
  MailloopClient,
  AuthenticationError,
  NotFoundError,
  RateLimitError,
  TimeoutError,
  ValidationError,
} from '@mailloop/sdk';

const client = new MailloopClient({ apiKey: process.env.MAILLOOP_API_KEY });

try {
  const email = await client.emails.waitFor('sandbox-id', {
    subject: 'Welcome',
    timeout: 15000
  });
} catch (error) {
  if (error instanceof TimeoutError) {
    console.log('No email arrived in time');
  } else if (error instanceof AuthenticationError) {
    console.log('Check your API key');
  } else if (error instanceof NotFoundError) {
    console.log('Sandbox does not exist');
  } else if (error instanceof RateLimitError) {
    console.log(`Rate limited. Retry after ${error.retryAfter}s`);
  } else if (error instanceof ValidationError) {
    console.log('Invalid parameters:', error.details);
  } else {
    throw error;
  }
}

REST API

The full interactive API documentation is available at api.mailloop.io (Swagger UI).

Authentication

All API requests require a Bearer token in the Authorization header:

TEXT
Authorization: Bearer ml_live_your_api_key_here

API keys are created in the Mailloop dashboard under Settings > API Keys.

Base URL

TEXT
https://api.mailloop.io/v1

Rate Limits

Rate limits are applied per API key:

EndpointLimitWindow
General200 req1 minute
Sandbox create30 req1 minute
Email list180 req1 minute
Email wait60 req1 minute
Email send60 req1 minute

Rate limit information is included in response headers:

HeaderDescription
X-RateLimit-LimitRequest limit per window
X-RateLimit-RemainingRemaining requests in current window
X-RateLimit-ResetUnix timestamp when the limit resets
Retry-AfterSeconds until the limit resets (on 429)