Skip to content

Getting Started

Outbound is a SaaS email delivery platform that lets you send transactional and bulk emails at scale using AWS SES under the hood. As a tenant, you get:

  • A dedicated API key with configurable rate limits and quotas
  • Verified sender domains assigned to your account
  • Reusable email templates with variable substitution
  • Real-time webhook notifications for delivery events
  • Automatic suppression list management (bounces, complaints, unsubscribes)
  • A dashboard with analytics and quota tracking

This SDK wraps the entire Outbound REST API into a clean, typed Node.js interface.

Installation

bash
npm install @masters-union/outbound-sdk
bash
yarn add @masters-union/outbound-sdk
bash
pnpm add @masters-union/outbound-sdk

Requirements: Node.js 18+ (uses native fetch)

Quick Setup

1. Get your API key

Your Outbound admin will provide you with an API key. It looks like:

mu_outbound_a1b2c3d4e5f6...

2. Initialize the client

ts
import { Outbound } from '@masters-union/outbound-sdk';

const outbound = new Outbound({ apiKey: 'mu_outbound_...' });
js
const { Outbound } = require('@masters-union/outbound-sdk');

const outbound = new Outbound({ apiKey: 'mu_outbound_...' });

Once you set the API key in the constructor, every method uses it automatically. No need to pass it on every call.

3. Send your first email

ts
const { jobId, messageId } = await outbound.email.send({
  toEmail: 'user@example.com',
  fromEmail: 'noreply@yourcompany.com', // must be a verified domain
  emailSubject: 'Welcome!',
  htmlBody: '<h1>Hello World</h1>',
});

console.log(`Email queued: ${jobId}`);

Verified Domains Only

The fromEmail must use a domain that has been verified and assigned to your tenant account by the admin. Sending from an unverified domain will return a 403 Forbidden error.

4. Check delivery status

ts
const status = await outbound.email.status(jobId);

for (const recipient of status.recipients) {
  console.log(`${recipient.recipient_email}: ${recipient.status}`);
  // "sent" → "delivered" → "opened" → "clicked"
}

5. Send with a template

ts
// Create a reusable template
const { template } = await outbound.templates.create({
  name: 'welcome-email',
  subject: 'Welcome {{firstName}}!',
  htmlBody: '<h1>Hello {{firstName}}</h1><p>Welcome to {{company}}.</p>',
  variables: ['firstName', 'company'],
});

// Send to one person
await outbound.templates.send({
  templateId: template.id,
  toEmail: 'user@example.com',
  fromEmail: 'noreply@yourcompany.com',
  variables: { firstName: 'John', company: 'Acme' },
});

// Send to many people
await outbound.templates.bulkSend({
  templateId: template.id,
  fromEmail: 'noreply@yourcompany.com',
  recipients: [
    { toEmail: 'alice@example.com', variables: { firstName: 'Alice', company: 'Acme' } },
    { toEmail: 'bob@example.com', variables: { firstName: 'Bob', company: 'Acme' } },
  ],
});

6. Multi-tenant usage

The SDK supports multi-tenant applications. You can override the API key on any individual call using the optional last argument:

ts
const outbound = new Outbound(); // no default apiKey

const tenantAKey = 'mu_outbound_tenant_a_...';
const tenantBKey = 'mu_outbound_tenant_b_...';

// Pass { apiKey } as the last argument to override per call
await outbound.email.send({ /* ... */ }, { apiKey: tenantAKey });
await outbound.email.send({ /* ... */ }, { apiKey: tenantBKey });

You can also set a default in the constructor and override only when needed:

ts
const outbound = new Outbound({ apiKey: tenantAKey }); // default

await outbound.email.send({ /* ... */ });                        // uses tenantAKey
await outbound.email.send({ /* ... */ }, { apiKey: tenantBKey }); // uses tenantBKey

Key Concepts

Email Lifecycle

Every email goes through these statuses:

queued → processing → sent → delivered
                         ↘ bounced
                         ↘ complained
                      delivered → opened → clicked
StatusMeaning
queuedEmail is in the queue, waiting to be processed
processingEmail is being sent to AWS SES
sentSES accepted the email
deliveredEmail landed in recipient's inbox
bouncedEmail bounced (bad address or mailbox full)
complainedRecipient marked it as spam
openedRecipient opened the email (requires tracking)
clickedRecipient clicked a link (requires tracking)
failedFailed to send (SES rejection or error)
cancelledCancelled before sending via email.cancel()
droppedRecipient was on the suppression list at submit time — never attempted

Suppression List

The platform automatically suppresses emails that bounce or receive complaints. You can also manually suppress emails. Any future send to a suppressed address is silently filtered out — it won't count against your quota.

Quotas

Your tenant account has:

  • Daily limit — Max emails per day (tracked for reporting/billing)
  • Monthly limit — Max emails per month (tracked for reporting/billing)
  • Rate limit — Max requests per second (enforced — returns 429)
  • Template limit — Max number of templates (enforced — returns 403)

Check your quota anytime with outbound.dashboard.quota().

Daily & monthly quotas do not block sends

Daily and monthly tenant quotas are tracked for reporting and billing but do not block sends — exceeding them does not return 429. The only request-time quota that can cause a 429 from /send or /bulk endpoints is the global AWS SES account 24-hour sending quota.

What's Next?

Released under the MIT License.