@masters-union/outbound-sdk 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +113 -118
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -2,183 +2,178 @@
2
2
 
3
3
  Official Node.js SDK for the [Outbound](https://github.com/AdarshChakrworty/outbound) email platform.
4
4
 
5
- ## Install
6
5
 
7
- ```bash
8
- npm install outbound-sdk
6
+ ## Installation
7
+
8
+ ::: code-group
9
+ ```bash [npm]
10
+ npm install @masters-union/outbound-sdk
11
+ ```
12
+ ```bash [yarn]
13
+ yarn add @masters-union/outbound-sdk
14
+ ```
15
+ ```bash [pnpm]
16
+ pnpm add @masters-union/outbound-sdk
9
17
  ```
18
+ :::
10
19
 
11
- ## Quick Start
20
+ **Requirements:** Node.js 18+ (uses native `fetch`)
12
21
 
13
- ```ts
14
- import { Outbound } from 'outbound-sdk';
22
+ ## Quick Setup
15
23
 
16
- // Single tenant set API key once
17
- const outbound = new Outbound({ apiKey: 'mu_outbound_...' });
24
+ ### 1. Get your API key
18
25
 
19
- const { jobId } = await outbound.email.send({
20
- toEmail: 'user@example.com',
21
- fromEmail: 'noreply@company.com',
22
- emailSubject: 'Welcome!',
23
- htmlBody: '<h1>Hello World</h1>',
24
- });
25
- ```
26
+ Your Outbound admin will provide you with an API key. It looks like:
26
27
 
27
- ### Multi-Tenant Usage
28
+ ```
29
+ mu_outbound_a1b2c3d4e5f6...
30
+ ```
28
31
 
29
- For applications that manage multiple tenants, create one client and pass the API key per call:
32
+ ### 2. Initialize the client
30
33
 
31
- ```ts
32
- const outbound = new Outbound(); // no default apiKey
34
+ ::: code-group
35
+ ```ts [ESM]
36
+ import { Outbound } from '@masters-union/outbound-sdk';
33
37
 
34
- const tenantAKey = 'mu_outbound_tenant_a_...';
35
- const tenantBKey = 'mu_outbound_tenant_b_...';
38
+ const outbound = new Outbound({ apiKey: 'mu_outbound_...' });
39
+ ```
40
+ ```js [CommonJS]
41
+ const { Outbound } = require('@masters-union/outbound-sdk');
36
42
 
37
- await outbound.email.send({ toEmail: '...', ... }, { apiKey: tenantAKey });
38
- await outbound.email.send({ toEmail: '...', ... }, { apiKey: tenantBKey });
43
+ const outbound = new Outbound({ apiKey: 'mu_outbound_...' });
39
44
  ```
45
+ :::
40
46
 
41
- A per-call `apiKey` always takes priority over the constructor default.
47
+ Once you set the API key in the constructor, every method uses it automatically. No need to pass it on every call.
42
48
 
43
- ### Send Bulk Emails
49
+ ### 3. Send your first email
44
50
 
45
51
  ```ts
46
- const result = await outbound.email.bulk({
47
- fromEmail: 'noreply@company.com',
48
- emailSubject: 'Newsletter',
49
- emails: [
50
- { toEmail: 'alice@example.com', htmlBody: '<h1>Hi Alice</h1>' },
51
- { toEmail: 'bob@example.com', htmlBody: '<h1>Hi Bob</h1>' },
52
- ],
52
+ const { jobId, messageId } = await outbound.email.send({
53
+ toEmail: 'user@example.com',
54
+ fromEmail: 'noreply@yourcompany.com', // must be a verified domain
55
+ emailSubject: 'Welcome!',
56
+ htmlBody: '<h1>Hello World</h1>',
53
57
  });
54
- // result.recipientCount, result.jobId
58
+
59
+ console.log(`Email queued: ${jobId}`);
55
60
  ```
56
61
 
57
- ### Check Job Status
62
+ ::: warning Verified Domains Only
63
+ 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.
64
+ :::
65
+
66
+ ### 4. Check delivery status
58
67
 
59
68
  ```ts
60
- const status = await outbound.email.status('job-uuid');
61
- // status.job, status.recipients
69
+ const status = await outbound.email.status(jobId);
70
+
71
+ for (const recipient of status.recipients) {
72
+ console.log(`${recipient.recipient_email}: ${recipient.status}`);
73
+ // "sent" → "delivered" → "opened" → "clicked"
74
+ }
62
75
  ```
63
76
 
64
- ### Templates
77
+ ### 5. Send with a template
65
78
 
66
79
  ```ts
67
- // Create
80
+ // Create a reusable template
68
81
  const { template } = await outbound.templates.create({
69
- name: 'welcome',
82
+ name: 'welcome-email',
70
83
  subject: 'Welcome {{firstName}}!',
71
- htmlBody: '<h1>Hello {{firstName}}</h1>',
72
- variables: ['firstName'],
84
+ htmlBody: '<h1>Hello {{firstName}}</h1><p>Welcome to {{company}}.</p>',
85
+ variables: ['firstName', 'company'],
73
86
  });
74
87
 
75
- // List
76
- const { templates, total } = await outbound.templates.list({ status: 'active' });
77
-
78
- // Send using template
79
- const { jobId } = await outbound.templates.send({
88
+ // Send to one person
89
+ await outbound.templates.send({
80
90
  templateId: template.id,
81
91
  toEmail: 'user@example.com',
82
- fromEmail: 'noreply@company.com',
83
- variables: { firstName: 'John' },
92
+ fromEmail: 'noreply@yourcompany.com',
93
+ variables: { firstName: 'John', company: 'Acme' },
84
94
  });
85
95
 
86
- // Bulk send using template
87
- const bulk = await outbound.templates.bulkSend({
96
+ // Send to many people
97
+ await outbound.templates.bulkSend({
88
98
  templateId: template.id,
89
- fromEmail: 'noreply@company.com',
99
+ fromEmail: 'noreply@yourcompany.com',
90
100
  recipients: [
91
- { toEmail: 'alice@example.com', variables: { firstName: 'Alice' } },
92
- { toEmail: 'bob@example.com', variables: { firstName: 'Bob' } },
101
+ { toEmail: 'alice@example.com', variables: { firstName: 'Alice', company: 'Acme' } },
102
+ { toEmail: 'bob@example.com', variables: { firstName: 'Bob', company: 'Acme' } },
93
103
  ],
94
104
  });
95
-
96
- // Preview
97
- const preview = await outbound.templates.preview(template.id, {
98
- variables: { firstName: 'John' },
99
- });
100
105
  ```
101
106
 
102
- ### Suppressions
107
+ ### 6. Multi-tenant usage
108
+
109
+ The SDK supports multi-tenant applications. You can override the API key on any individual call using the optional last argument:
103
110
 
104
111
  ```ts
105
- // Add
106
- await outbound.suppressions.add({ email: 'bad@example.com', reason: 'manual' });
112
+ const outbound = new Outbound(); // no default apiKey
107
113
 
108
- // List
109
- const { suppressions } = await outbound.suppressions.list({ reason: 'bounce' });
114
+ const tenantAKey = 'mu_outbound_tenant_a_...';
115
+ const tenantBKey = 'mu_outbound_tenant_b_...';
110
116
 
111
- // Remove
112
- await outbound.suppressions.remove('bad@example.com');
117
+ // Pass { apiKey } as the last argument to override per call
118
+ await outbound.email.send({ /* ... */ }, { apiKey: tenantAKey });
119
+ await outbound.email.send({ /* ... */ }, { apiKey: tenantBKey });
113
120
  ```
114
121
 
115
- ### Webhooks
122
+ You can also set a default in the constructor and override only when needed:
116
123
 
117
124
  ```ts
118
- // Create
119
- const { webhook, secret } = await outbound.webhooks.create({
120
- url: 'https://myapp.com/webhooks/outbound',
121
- events: ['delivery', 'bounce', 'complaint'],
122
- });
123
- // Store `secret` securely for signature verification
125
+ const outbound = new Outbound({ apiKey: tenantAKey }); // default
124
126
 
125
- // Verify incoming webhook
126
- const isValid = Outbound.verifyWebhookSignature(rawBody, signatureHeader, secret);
127
+ await outbound.email.send({ /* ... */ }); // uses tenantAKey
128
+ await outbound.email.send({ /* ... */ }, { apiKey: tenantBKey }); // uses tenantBKey
127
129
  ```
128
130
 
129
- ### Dashboard
131
+ ## Key Concepts
130
132
 
131
- ```ts
132
- const dashboard = await outbound.dashboard.get();
133
- // dashboard.last30Days.sent, dashboard.quota, etc.
133
+ ### Email Lifecycle
134
134
 
135
- const quota = await outbound.dashboard.quota();
136
- // quota.dailyUsed, quota.monthlyUsed, quota.remaining
135
+ Every email goes through these statuses:
136
+
137
+ ```
138
+ queued → processing → sent → delivered
139
+ ↘ bounced
140
+ ↘ complained
141
+ delivered → opened → clicked
137
142
  ```
138
143
 
139
- ## Configuration
144
+ | Status | Meaning |
145
+ |--------|---------|
146
+ | `queued` | Email is in the queue, waiting to be processed |
147
+ | `processing` | Email is being sent to AWS SES |
148
+ | `sent` | SES accepted the email |
149
+ | `delivered` | Email landed in recipient's inbox |
150
+ | `bounced` | Email bounced (bad address or mailbox full) |
151
+ | `complained` | Recipient marked it as spam |
152
+ | `opened` | Recipient opened the email (requires tracking) |
153
+ | `clicked` | Recipient clicked a link (requires tracking) |
154
+ | `failed` | Failed to send (SES rejection or error) |
140
155
 
141
- | Option | Default | Description |
142
- |--------|---------|-------------|
143
- | `apiKey` | — | Default API key (optional if provided per call) |
144
- | `baseUrl` | `https://outbound-api.mastersunion.org` | API base URL |
145
- | `timeout` | `30000` | Request timeout in ms |
146
- | `maxRetries` | `3` | Max retries on 429/5xx |
147
- | `retryDelay` | `1000` | Initial retry delay in ms (exponential backoff) |
156
+ ### Suppression List
148
157
 
149
- ## Error Handling
158
+ 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.
150
159
 
151
- All errors extend `OutboundError` with `statusCode`, `message`, and `details`:
160
+ ### Quotas
152
161
 
153
- ```ts
154
- import { Outbound, RateLimitError, NotFoundError } from 'outbound-sdk';
155
-
156
- try {
157
- await outbound.email.send({ ... });
158
- } catch (err) {
159
- if (err instanceof RateLimitError) {
160
- console.log(`Rate limited. Retry after ${err.retryAfter}s`);
161
- } else if (err instanceof NotFoundError) {
162
- console.log('Resource not found');
163
- }
164
- }
165
- ```
162
+ Your tenant account has:
163
+ - **Daily limit** Max emails per day
164
+ - **Monthly limit** — Max emails per month
165
+ - **Rate limit** — Max emails per second
166
+ - **Template limit** — Max number of templates
167
+
168
+ Check your quota anytime with `outbound.dashboard.quota()`.
169
+
170
+ ## What's Next?
166
171
 
167
- | Error Class | Status Code |
168
- |------------|-------------|
169
- | `BadRequestError` | 400 |
170
- | `AuthenticationError` | 401 |
171
- | `ForbiddenError` | 403 |
172
- | `NotFoundError` | 404 |
173
- | `ConflictError` | 409 |
174
- | `RateLimitError` | 429 |
175
- | `ServerError` | 5xx |
176
- | `TimeoutError` | - |
177
- | `NetworkError` | - |
178
-
179
- ## Requirements
180
-
181
- - Node.js 18+ (uses native `fetch`)
172
+ - [Configuration](/guide/configuration) Customize timeouts, retries, and more
173
+ - [Error Handling](/guide/error-handling) — Handle every error type
174
+ - [Email API](/api/email) Single and bulk sending reference
175
+ - [Templates API](/api/templates) Full template lifecycle
176
+ - [Webhooks API](/api/webhooks) Real-time event notifications
182
177
 
183
178
  ## License
184
179
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@masters-union/outbound-sdk",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Official Node.js SDK for the Outbound Email SaaS platform",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",