@sendmailos/sdk 1.0.0
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.
- package/LICENSE +21 -0
- package/README.md +204 -0
- package/dist/index.d.mts +480 -0
- package/dist/index.d.ts +480 -0
- package/dist/index.js +538 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +525 -0
- package/dist/index.mjs.map +1 -0
- package/dist/react/index.d.mts +140 -0
- package/dist/react/index.d.ts +140 -0
- package/dist/react/index.js +228 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/index.mjs +223 -0
- package/dist/react/index.mjs.map +1 -0
- package/package.json +68 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 SendMailOS
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# @sendmailos/sdk
|
|
2
|
+
|
|
3
|
+
Official JavaScript/TypeScript SDK for SendMailOS email API.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @sendmailos/sdk
|
|
9
|
+
# or
|
|
10
|
+
yarn add @sendmailos/sdk
|
|
11
|
+
# or
|
|
12
|
+
pnpm add @sendmailos/sdk
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { SendMailOS } from '@sendmailos/sdk';
|
|
19
|
+
|
|
20
|
+
const client = new SendMailOS('sk_live_your_api_key');
|
|
21
|
+
|
|
22
|
+
// Send a transactional email
|
|
23
|
+
await client.emails.send({
|
|
24
|
+
to: 'user@example.com',
|
|
25
|
+
fromName: 'Your Company',
|
|
26
|
+
fromEmail: 'hello@yourcompany.com',
|
|
27
|
+
subject: 'Welcome!',
|
|
28
|
+
html: '<h1>Hello!</h1><p>Welcome to our platform.</p>'
|
|
29
|
+
});
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Features
|
|
33
|
+
|
|
34
|
+
- **Type-safe**: Full TypeScript support with exported types
|
|
35
|
+
- **Lightweight**: Zero dependencies for core SDK
|
|
36
|
+
- **React Components**: Pre-built components for common patterns
|
|
37
|
+
- **Webhook Verification**: Secure signature verification utilities
|
|
38
|
+
- **Error Handling**: Custom error classes for different scenarios
|
|
39
|
+
|
|
40
|
+
## API Reference
|
|
41
|
+
|
|
42
|
+
### Emails
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
// Send transactional email
|
|
46
|
+
await client.emails.send({
|
|
47
|
+
to: 'user@example.com',
|
|
48
|
+
subject: 'Hello!',
|
|
49
|
+
html: '<h1>Welcome!</h1>',
|
|
50
|
+
fromName: 'Acme',
|
|
51
|
+
fromEmail: 'hello@acme.com',
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Send with template
|
|
55
|
+
await client.emails.sendTemplate({
|
|
56
|
+
to: 'user@example.com',
|
|
57
|
+
templateId: 'tmpl_welcome',
|
|
58
|
+
variables: { firstName: 'John' }
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Subscribers
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
// Create subscriber
|
|
66
|
+
const { subscriber } = await client.subscribers.create({
|
|
67
|
+
email: 'user@example.com',
|
|
68
|
+
firstName: 'John',
|
|
69
|
+
tags: ['newsletter', 'premium']
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// List subscribers
|
|
73
|
+
const { subscribers, total } = await client.subscribers.list({
|
|
74
|
+
limit: 50,
|
|
75
|
+
offset: 0
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Campaigns
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
// Send campaign
|
|
83
|
+
await client.campaigns.send({
|
|
84
|
+
name: 'Weekly Newsletter',
|
|
85
|
+
subject: 'What\'s new this week',
|
|
86
|
+
fromName: 'Company Newsletter',
|
|
87
|
+
fromEmail: 'news@company.com',
|
|
88
|
+
html: '<h1>Hello {{first_name}}!</h1>',
|
|
89
|
+
tags: ['newsletter'] // Filter by subscriber tags
|
|
90
|
+
});
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Domains
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
// Add sending domain
|
|
97
|
+
const { domain } = await client.domains.create({
|
|
98
|
+
domain: 'yourcompany.com'
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
console.log('DNS Records to add:', domain.dnsRecords);
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## React Integration
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
import { SendMailOSProvider, SubscribeForm } from '@sendmailos/sdk/react';
|
|
108
|
+
|
|
109
|
+
function App() {
|
|
110
|
+
return (
|
|
111
|
+
<SendMailOSProvider publicKey="pk_live_...">
|
|
112
|
+
<SubscribeForm
|
|
113
|
+
tags={['newsletter']}
|
|
114
|
+
onSuccess={() => console.log('Subscribed!')}
|
|
115
|
+
buttonText="Join Newsletter"
|
|
116
|
+
/>
|
|
117
|
+
</SendMailOSProvider>
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Custom Form with Hook
|
|
123
|
+
|
|
124
|
+
```tsx
|
|
125
|
+
import { useSubscribe } from '@sendmailos/sdk/react';
|
|
126
|
+
|
|
127
|
+
function CustomForm() {
|
|
128
|
+
const { subscribe, isLoading, error, isSuccess } = useSubscribe();
|
|
129
|
+
const [email, setEmail] = useState('');
|
|
130
|
+
|
|
131
|
+
const handleSubmit = async (e) => {
|
|
132
|
+
e.preventDefault();
|
|
133
|
+
await subscribe({ email, tags: ['newsletter'] });
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
if (isSuccess) return <p>Thanks for subscribing!</p>;
|
|
137
|
+
|
|
138
|
+
return (
|
|
139
|
+
<form onSubmit={handleSubmit}>
|
|
140
|
+
<input
|
|
141
|
+
type="email"
|
|
142
|
+
value={email}
|
|
143
|
+
onChange={(e) => setEmail(e.target.value)}
|
|
144
|
+
/>
|
|
145
|
+
<button disabled={isLoading}>
|
|
146
|
+
{isLoading ? 'Subscribing...' : 'Subscribe'}
|
|
147
|
+
</button>
|
|
148
|
+
{error && <p>{error.message}</p>}
|
|
149
|
+
</form>
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Webhook Verification
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
import { verifyWebhookSignature } from '@sendmailos/sdk';
|
|
158
|
+
|
|
159
|
+
app.post('/webhooks', (req, res) => {
|
|
160
|
+
const isValid = verifyWebhookSignature({
|
|
161
|
+
payload: JSON.stringify(req.body),
|
|
162
|
+
signature: req.headers['x-sendmailos-signature'],
|
|
163
|
+
timestamp: req.headers['x-sendmailos-timestamp'],
|
|
164
|
+
secret: process.env.WEBHOOK_SECRET
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
if (!isValid) {
|
|
168
|
+
return res.status(401).json({ error: 'Invalid signature' });
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Process webhook event
|
|
172
|
+
const event = req.body;
|
|
173
|
+
console.log('Event:', event.type);
|
|
174
|
+
|
|
175
|
+
res.status(200).json({ received: true });
|
|
176
|
+
});
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Error Handling
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
import { SendMailOS, SendMailOSError, RateLimitError } from '@sendmailos/sdk';
|
|
183
|
+
|
|
184
|
+
try {
|
|
185
|
+
await client.emails.send({ ... });
|
|
186
|
+
} catch (error) {
|
|
187
|
+
if (error instanceof RateLimitError) {
|
|
188
|
+
console.log(`Rate limited. Retry after ${error.retryAfter}s`);
|
|
189
|
+
} else if (error instanceof SendMailOSError) {
|
|
190
|
+
console.log(`Error: ${error.message} (${error.code})`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Security
|
|
196
|
+
|
|
197
|
+
- **Never expose secret keys** (`sk_*`) in client-side code
|
|
198
|
+
- Use **public keys** (`pk_*`) for React components
|
|
199
|
+
- Verify webhook signatures to prevent spoofing
|
|
200
|
+
- Use environment variables for API keys
|
|
201
|
+
|
|
202
|
+
## License
|
|
203
|
+
|
|
204
|
+
MIT
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SendMailOS SDK Types
|
|
3
|
+
*/
|
|
4
|
+
interface SendMailOSOptions {
|
|
5
|
+
/** Base URL for the API (default: https://api.sendmailos.com) */
|
|
6
|
+
baseUrl?: string;
|
|
7
|
+
/** Request timeout in milliseconds (default: 30000) */
|
|
8
|
+
timeout?: number;
|
|
9
|
+
/** Custom fetch implementation (for testing/Node.js polyfill) */
|
|
10
|
+
fetch?: typeof fetch;
|
|
11
|
+
}
|
|
12
|
+
interface SendEmailRequest {
|
|
13
|
+
/** Recipient email address */
|
|
14
|
+
to: string;
|
|
15
|
+
/** Email subject line (supports Handlebars variables) */
|
|
16
|
+
subject: string;
|
|
17
|
+
/** HTML content (required if no templateId) */
|
|
18
|
+
html?: string;
|
|
19
|
+
/** Template ID to use (required if no html) */
|
|
20
|
+
templateId?: string;
|
|
21
|
+
/** Sender display name (default: "System") */
|
|
22
|
+
fromName?: string;
|
|
23
|
+
/** Sender email address (must be from verified domain) */
|
|
24
|
+
fromEmail?: string;
|
|
25
|
+
/** Template variables for Handlebars interpolation */
|
|
26
|
+
variables?: Record<string, unknown>;
|
|
27
|
+
/** Email type: "transactional" (default) or "marketing" */
|
|
28
|
+
type?: 'transactional' | 'marketing';
|
|
29
|
+
}
|
|
30
|
+
interface SendEmailResponse {
|
|
31
|
+
success: boolean;
|
|
32
|
+
message: string;
|
|
33
|
+
id: string;
|
|
34
|
+
sandbox?: boolean;
|
|
35
|
+
}
|
|
36
|
+
interface Subscriber {
|
|
37
|
+
id: string;
|
|
38
|
+
email: string;
|
|
39
|
+
firstName?: string;
|
|
40
|
+
lastName?: string;
|
|
41
|
+
status: 'subscribed' | 'unsubscribed' | 'bounced' | 'complained';
|
|
42
|
+
tags?: string[];
|
|
43
|
+
source: string;
|
|
44
|
+
createdAt: string;
|
|
45
|
+
primaryDomain?: {
|
|
46
|
+
id: string;
|
|
47
|
+
domainName: string;
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
interface CreateSubscriberRequest {
|
|
51
|
+
/** Subscriber email address */
|
|
52
|
+
email: string;
|
|
53
|
+
/** First name (for personalization) */
|
|
54
|
+
firstName?: string;
|
|
55
|
+
/** Last name (for personalization) */
|
|
56
|
+
lastName?: string;
|
|
57
|
+
/** Tags for segmentation */
|
|
58
|
+
tags?: string[];
|
|
59
|
+
/** Associate with a specific domain */
|
|
60
|
+
domainId?: string;
|
|
61
|
+
}
|
|
62
|
+
interface CreateSubscriberResponse {
|
|
63
|
+
success: boolean;
|
|
64
|
+
subscriber: Subscriber;
|
|
65
|
+
}
|
|
66
|
+
interface ListSubscribersRequest {
|
|
67
|
+
/** Results per page (default: 20, max: 100) */
|
|
68
|
+
limit?: number;
|
|
69
|
+
/** Pagination offset */
|
|
70
|
+
offset?: number;
|
|
71
|
+
}
|
|
72
|
+
interface ListSubscribersResponse {
|
|
73
|
+
success: boolean;
|
|
74
|
+
subscribers: Subscriber[];
|
|
75
|
+
total: number;
|
|
76
|
+
limit: number;
|
|
77
|
+
offset: number;
|
|
78
|
+
}
|
|
79
|
+
interface SendCampaignRequest {
|
|
80
|
+
/** Campaign name (for tracking) */
|
|
81
|
+
name?: string;
|
|
82
|
+
/** Email subject line (supports Handlebars) */
|
|
83
|
+
subject: string;
|
|
84
|
+
/** Sender display name */
|
|
85
|
+
fromName: string;
|
|
86
|
+
/** Sender email (from verified domain) */
|
|
87
|
+
fromEmail: string;
|
|
88
|
+
/** HTML content (required if no templateId) */
|
|
89
|
+
html?: string;
|
|
90
|
+
/** Template ID (required if no html) */
|
|
91
|
+
templateId?: string;
|
|
92
|
+
/** Filter subscribers by tags (AND logic) */
|
|
93
|
+
tags?: string[];
|
|
94
|
+
/** Global template variables */
|
|
95
|
+
variables?: Record<string, unknown>;
|
|
96
|
+
}
|
|
97
|
+
interface SendCampaignResponse {
|
|
98
|
+
success: boolean;
|
|
99
|
+
message: string;
|
|
100
|
+
campaignId: string;
|
|
101
|
+
}
|
|
102
|
+
interface Domain {
|
|
103
|
+
id: string;
|
|
104
|
+
domainName: string;
|
|
105
|
+
status: 'pending' | 'verified' | 'failed';
|
|
106
|
+
dkimTokens: string[];
|
|
107
|
+
createdAt: string;
|
|
108
|
+
verifiedAt?: string;
|
|
109
|
+
dnsRecords?: DnsRecord[];
|
|
110
|
+
}
|
|
111
|
+
interface DnsRecord {
|
|
112
|
+
type: 'CNAME' | 'TXT' | 'MX';
|
|
113
|
+
name: string;
|
|
114
|
+
value: string;
|
|
115
|
+
}
|
|
116
|
+
interface CreateDomainRequest {
|
|
117
|
+
/** Domain name (e.g., "yourcompany.com") */
|
|
118
|
+
domain: string;
|
|
119
|
+
}
|
|
120
|
+
interface CreateDomainResponse {
|
|
121
|
+
success: boolean;
|
|
122
|
+
domain: Domain;
|
|
123
|
+
}
|
|
124
|
+
interface ListDomainsResponse {
|
|
125
|
+
success: boolean;
|
|
126
|
+
domains: Domain[];
|
|
127
|
+
}
|
|
128
|
+
type WebhookEventType = 'email.sent' | 'email.delivered' | 'email.opened' | 'email.clicked' | 'email.bounced' | 'email.complained';
|
|
129
|
+
interface WebhookEvent {
|
|
130
|
+
id: string;
|
|
131
|
+
type: WebhookEventType;
|
|
132
|
+
createdAt: string;
|
|
133
|
+
data: {
|
|
134
|
+
emailId: string;
|
|
135
|
+
messageId: string;
|
|
136
|
+
recipient: string;
|
|
137
|
+
campaignId?: string;
|
|
138
|
+
timestamp: string;
|
|
139
|
+
metadata?: Record<string, unknown>;
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
interface CreateWebhookRequest {
|
|
143
|
+
/** Endpoint URL to receive webhook events */
|
|
144
|
+
url: string;
|
|
145
|
+
/** Events to subscribe to */
|
|
146
|
+
events: WebhookEventType[];
|
|
147
|
+
/** Signing secret for webhook verification */
|
|
148
|
+
secret?: string;
|
|
149
|
+
}
|
|
150
|
+
interface Webhook {
|
|
151
|
+
id: string;
|
|
152
|
+
url: string;
|
|
153
|
+
events: WebhookEventType[];
|
|
154
|
+
active: boolean;
|
|
155
|
+
createdAt: string;
|
|
156
|
+
}
|
|
157
|
+
interface ApiError {
|
|
158
|
+
success: false;
|
|
159
|
+
error: string;
|
|
160
|
+
code: string;
|
|
161
|
+
retryAfter?: number;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Emails resource for sending transactional emails
|
|
166
|
+
*/
|
|
167
|
+
declare class EmailsResource {
|
|
168
|
+
private request;
|
|
169
|
+
constructor(request: <T>(endpoint: string, options?: RequestInit) => Promise<T>);
|
|
170
|
+
/**
|
|
171
|
+
* Send a transactional email
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```ts
|
|
175
|
+
* const result = await client.emails.send({
|
|
176
|
+
* to: 'user@example.com',
|
|
177
|
+
* fromName: 'Your Company',
|
|
178
|
+
* fromEmail: 'hello@yourcompany.com',
|
|
179
|
+
* subject: 'Welcome!',
|
|
180
|
+
* html: '<h1>Hello!</h1>'
|
|
181
|
+
* });
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
send(params: SendEmailRequest): Promise<SendEmailResponse>;
|
|
185
|
+
/**
|
|
186
|
+
* Send email using a template
|
|
187
|
+
*
|
|
188
|
+
* @example
|
|
189
|
+
* ```ts
|
|
190
|
+
* const result = await client.emails.sendTemplate({
|
|
191
|
+
* to: 'user@example.com',
|
|
192
|
+
* templateId: 'tmpl_welcome',
|
|
193
|
+
* variables: { firstName: 'John' }
|
|
194
|
+
* });
|
|
195
|
+
* ```
|
|
196
|
+
*/
|
|
197
|
+
sendTemplate(params: {
|
|
198
|
+
to: string;
|
|
199
|
+
templateId: string;
|
|
200
|
+
fromName?: string;
|
|
201
|
+
fromEmail?: string;
|
|
202
|
+
subject?: string;
|
|
203
|
+
variables?: Record<string, unknown>;
|
|
204
|
+
}): Promise<SendEmailResponse>;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Subscribers resource for managing email contacts
|
|
209
|
+
*/
|
|
210
|
+
declare class SubscribersResource {
|
|
211
|
+
private request;
|
|
212
|
+
constructor(request: <T>(endpoint: string, options?: RequestInit) => Promise<T>);
|
|
213
|
+
/**
|
|
214
|
+
* Create or update a subscriber (upsert)
|
|
215
|
+
*
|
|
216
|
+
* @example
|
|
217
|
+
* ```ts
|
|
218
|
+
* const { subscriber } = await client.subscribers.create({
|
|
219
|
+
* email: 'user@example.com',
|
|
220
|
+
* firstName: 'John',
|
|
221
|
+
* tags: ['newsletter', 'premium']
|
|
222
|
+
* });
|
|
223
|
+
* ```
|
|
224
|
+
*/
|
|
225
|
+
create(params: CreateSubscriberRequest): Promise<CreateSubscriberResponse>;
|
|
226
|
+
/**
|
|
227
|
+
* List all subscribers with pagination
|
|
228
|
+
*
|
|
229
|
+
* @example
|
|
230
|
+
* ```ts
|
|
231
|
+
* const { subscribers, total } = await client.subscribers.list({
|
|
232
|
+
* limit: 50,
|
|
233
|
+
* offset: 0
|
|
234
|
+
* });
|
|
235
|
+
* ```
|
|
236
|
+
*/
|
|
237
|
+
list(params?: ListSubscribersRequest): Promise<ListSubscribersResponse>;
|
|
238
|
+
/**
|
|
239
|
+
* Get a single subscriber by ID
|
|
240
|
+
*/
|
|
241
|
+
get(subscriberId: string): Promise<{
|
|
242
|
+
success: boolean;
|
|
243
|
+
subscriber: Subscriber;
|
|
244
|
+
}>;
|
|
245
|
+
/**
|
|
246
|
+
* Update a subscriber by ID
|
|
247
|
+
*/
|
|
248
|
+
update(subscriberId: string, params: Partial<CreateSubscriberRequest>): Promise<CreateSubscriberResponse>;
|
|
249
|
+
/**
|
|
250
|
+
* Update a subscriber by email address
|
|
251
|
+
*/
|
|
252
|
+
updateByEmail(email: string, params: Partial<Omit<CreateSubscriberRequest, 'email'>>): Promise<CreateSubscriberResponse>;
|
|
253
|
+
/**
|
|
254
|
+
* Delete/unsubscribe a subscriber
|
|
255
|
+
*/
|
|
256
|
+
delete(subscriberId: string): Promise<{
|
|
257
|
+
success: boolean;
|
|
258
|
+
}>;
|
|
259
|
+
/**
|
|
260
|
+
* Add tags to a subscriber
|
|
261
|
+
*/
|
|
262
|
+
addTags(subscriberId: string, tags: string[]): Promise<CreateSubscriberResponse>;
|
|
263
|
+
/**
|
|
264
|
+
* Remove tags from a subscriber
|
|
265
|
+
*/
|
|
266
|
+
removeTags(subscriberId: string, tags: string[]): Promise<CreateSubscriberResponse>;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Campaigns resource for bulk email sending
|
|
271
|
+
*/
|
|
272
|
+
declare class CampaignsResource {
|
|
273
|
+
private request;
|
|
274
|
+
constructor(request: <T>(endpoint: string, options?: RequestInit) => Promise<T>);
|
|
275
|
+
/**
|
|
276
|
+
* Send a campaign to subscribers
|
|
277
|
+
*
|
|
278
|
+
* @example
|
|
279
|
+
* ```ts
|
|
280
|
+
* const result = await client.campaigns.send({
|
|
281
|
+
* name: 'January Newsletter',
|
|
282
|
+
* subject: 'What\'s new this month',
|
|
283
|
+
* fromName: 'Your Company',
|
|
284
|
+
* fromEmail: 'news@yourcompany.com',
|
|
285
|
+
* html: '<h1>Hello {{first_name}}!</h1>',
|
|
286
|
+
* tags: ['newsletter', 'active']
|
|
287
|
+
* });
|
|
288
|
+
* ```
|
|
289
|
+
*/
|
|
290
|
+
send(params: SendCampaignRequest): Promise<SendCampaignResponse>;
|
|
291
|
+
/**
|
|
292
|
+
* Send campaign using a saved template
|
|
293
|
+
*/
|
|
294
|
+
sendTemplate(params: {
|
|
295
|
+
name?: string;
|
|
296
|
+
templateId: string;
|
|
297
|
+
subject: string;
|
|
298
|
+
fromName: string;
|
|
299
|
+
fromEmail: string;
|
|
300
|
+
tags?: string[];
|
|
301
|
+
variables?: Record<string, unknown>;
|
|
302
|
+
}): Promise<SendCampaignResponse>;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Domains resource for managing sending domains
|
|
307
|
+
*/
|
|
308
|
+
declare class DomainsResource {
|
|
309
|
+
private request;
|
|
310
|
+
constructor(request: <T>(endpoint: string, options?: RequestInit) => Promise<T>);
|
|
311
|
+
/**
|
|
312
|
+
* Add a new sending domain
|
|
313
|
+
* Returns DKIM tokens and DNS records for verification
|
|
314
|
+
*
|
|
315
|
+
* @example
|
|
316
|
+
* ```ts
|
|
317
|
+
* const { domain } = await client.domains.create({
|
|
318
|
+
* domain: 'yourcompany.com'
|
|
319
|
+
* });
|
|
320
|
+
*
|
|
321
|
+
* console.log('Add these DNS records:', domain.dnsRecords);
|
|
322
|
+
* ```
|
|
323
|
+
*/
|
|
324
|
+
create(params: CreateDomainRequest): Promise<CreateDomainResponse>;
|
|
325
|
+
/**
|
|
326
|
+
* List all domains for the organization
|
|
327
|
+
*/
|
|
328
|
+
list(): Promise<ListDomainsResponse>;
|
|
329
|
+
/**
|
|
330
|
+
* Get a single domain by ID
|
|
331
|
+
*/
|
|
332
|
+
get(domainId: string): Promise<{
|
|
333
|
+
success: boolean;
|
|
334
|
+
domain: Domain;
|
|
335
|
+
}>;
|
|
336
|
+
/**
|
|
337
|
+
* Verify a domain (trigger DNS check)
|
|
338
|
+
*/
|
|
339
|
+
verify(domainId: string): Promise<{
|
|
340
|
+
success: boolean;
|
|
341
|
+
domain: Domain;
|
|
342
|
+
}>;
|
|
343
|
+
/**
|
|
344
|
+
* Delete a domain
|
|
345
|
+
*/
|
|
346
|
+
delete(domainId: string): Promise<{
|
|
347
|
+
success: boolean;
|
|
348
|
+
}>;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* SendMailOS SDK Client
|
|
353
|
+
*
|
|
354
|
+
* @example
|
|
355
|
+
* ```ts
|
|
356
|
+
* import { SendMailOS } from '@sendmailos/sdk';
|
|
357
|
+
*
|
|
358
|
+
* const client = new SendMailOS('sk_live_your_api_key');
|
|
359
|
+
*
|
|
360
|
+
* // Send an email
|
|
361
|
+
* await client.emails.send({
|
|
362
|
+
* to: 'user@example.com',
|
|
363
|
+
* subject: 'Hello!',
|
|
364
|
+
* html: '<h1>Welcome!</h1>'
|
|
365
|
+
* });
|
|
366
|
+
*
|
|
367
|
+
* // Add a subscriber
|
|
368
|
+
* await client.subscribers.create({
|
|
369
|
+
* email: 'user@example.com',
|
|
370
|
+
* tags: ['newsletter']
|
|
371
|
+
* });
|
|
372
|
+
* ```
|
|
373
|
+
*/
|
|
374
|
+
declare class SendMailOS {
|
|
375
|
+
private readonly apiKey;
|
|
376
|
+
private readonly baseUrl;
|
|
377
|
+
private readonly timeout;
|
|
378
|
+
private readonly fetchFn;
|
|
379
|
+
/** Email sending operations */
|
|
380
|
+
readonly emails: EmailsResource;
|
|
381
|
+
/** Subscriber management */
|
|
382
|
+
readonly subscribers: SubscribersResource;
|
|
383
|
+
/** Campaign operations */
|
|
384
|
+
readonly campaigns: CampaignsResource;
|
|
385
|
+
/** Domain management */
|
|
386
|
+
readonly domains: DomainsResource;
|
|
387
|
+
constructor(apiKey: string, options?: SendMailOSOptions);
|
|
388
|
+
/**
|
|
389
|
+
* Make an authenticated request to the API
|
|
390
|
+
*/
|
|
391
|
+
private request;
|
|
392
|
+
private safeParseJson;
|
|
393
|
+
/**
|
|
394
|
+
* Check if the API key is valid (test mode only)
|
|
395
|
+
*/
|
|
396
|
+
get isTestMode(): boolean;
|
|
397
|
+
/**
|
|
398
|
+
* Get the SDK version
|
|
399
|
+
*/
|
|
400
|
+
static get version(): string;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Custom error classes for SendMailOS SDK
|
|
405
|
+
*/
|
|
406
|
+
declare class SendMailOSError extends Error {
|
|
407
|
+
readonly code: string;
|
|
408
|
+
readonly statusCode: number;
|
|
409
|
+
readonly retryAfter?: number;
|
|
410
|
+
constructor(message: string, code: string, statusCode: number, retryAfter?: number);
|
|
411
|
+
/** Whether this error is retryable (rate limit or server error) */
|
|
412
|
+
get isRetryable(): boolean;
|
|
413
|
+
}
|
|
414
|
+
declare class AuthenticationError extends SendMailOSError {
|
|
415
|
+
constructor(message?: string);
|
|
416
|
+
}
|
|
417
|
+
declare class ValidationError extends SendMailOSError {
|
|
418
|
+
constructor(message: string);
|
|
419
|
+
}
|
|
420
|
+
declare class RateLimitError extends SendMailOSError {
|
|
421
|
+
constructor(message: string, retryAfter: number);
|
|
422
|
+
}
|
|
423
|
+
declare class NotFoundError extends SendMailOSError {
|
|
424
|
+
constructor(message: string);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Webhook signature verification utilities
|
|
429
|
+
*
|
|
430
|
+
* IMPORTANT: This module uses timing-safe comparison to prevent timing attacks.
|
|
431
|
+
*/
|
|
432
|
+
interface VerifyWebhookParams {
|
|
433
|
+
/** Raw request body as string */
|
|
434
|
+
payload: string;
|
|
435
|
+
/** Value of X-SendMailOS-Signature header */
|
|
436
|
+
signature: string;
|
|
437
|
+
/** Value of X-SendMailOS-Timestamp header */
|
|
438
|
+
timestamp: string;
|
|
439
|
+
/** Your webhook signing secret */
|
|
440
|
+
secret: string;
|
|
441
|
+
/** Maximum age in seconds (default: 300 = 5 minutes) */
|
|
442
|
+
tolerance?: number;
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Verify a webhook signature to ensure the request came from SendMailOS
|
|
446
|
+
*
|
|
447
|
+
* @example
|
|
448
|
+
* ```ts
|
|
449
|
+
* import { verifyWebhookSignature } from '@sendmailos/sdk';
|
|
450
|
+
*
|
|
451
|
+
* app.post('/webhooks', (req, res) => {
|
|
452
|
+
* const isValid = verifyWebhookSignature({
|
|
453
|
+
* payload: JSON.stringify(req.body),
|
|
454
|
+
* signature: req.headers['x-sendmailos-signature'],
|
|
455
|
+
* timestamp: req.headers['x-sendmailos-timestamp'],
|
|
456
|
+
* secret: process.env.WEBHOOK_SECRET
|
|
457
|
+
* });
|
|
458
|
+
*
|
|
459
|
+
* if (!isValid) {
|
|
460
|
+
* return res.status(401).json({ error: 'Invalid signature' });
|
|
461
|
+
* }
|
|
462
|
+
*
|
|
463
|
+
* // Process webhook...
|
|
464
|
+
* });
|
|
465
|
+
* ```
|
|
466
|
+
*/
|
|
467
|
+
declare function verifyWebhookSignature(params: VerifyWebhookParams): boolean;
|
|
468
|
+
/**
|
|
469
|
+
* Async version of webhook verification (recommended for edge/browser)
|
|
470
|
+
*/
|
|
471
|
+
declare function verifyWebhookSignatureAsync(params: VerifyWebhookParams): Promise<boolean>;
|
|
472
|
+
/**
|
|
473
|
+
* Construct a webhook event from raw request data
|
|
474
|
+
*/
|
|
475
|
+
declare function constructWebhookEvent<T = unknown>(payload: string, headers: {
|
|
476
|
+
signature: string;
|
|
477
|
+
timestamp: string;
|
|
478
|
+
}, secret: string): T;
|
|
479
|
+
|
|
480
|
+
export { type ApiError, AuthenticationError, type CreateDomainRequest, type CreateDomainResponse, type CreateSubscriberRequest, type CreateSubscriberResponse, type CreateWebhookRequest, type DnsRecord, type Domain, type ListDomainsResponse, type ListSubscribersRequest, type ListSubscribersResponse, NotFoundError, RateLimitError, type SendCampaignRequest, type SendCampaignResponse, type SendEmailRequest, type SendEmailResponse, SendMailOS, SendMailOSError, type SendMailOSOptions, type Subscriber, ValidationError, type VerifyWebhookParams, type Webhook, type WebhookEvent, type WebhookEventType, constructWebhookEvent, SendMailOS as default, verifyWebhookSignature, verifyWebhookSignatureAsync };
|