@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 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
@@ -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 };