@bernierllc/email-service 2.0.1
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/README.md +578 -0
- package/dist/email-service.d.ts +39 -0
- package/dist/email-service.js +531 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +9 -0
- package/dist/types.d.ts +219 -0
- package/dist/types.js +55 -0
- package/package.json +79 -0
package/README.md
ADDED
|
@@ -0,0 +1,578 @@
|
|
|
1
|
+
# @bernierllc/email-service
|
|
2
|
+
|
|
3
|
+
Comprehensive email service orchestrating template management, multi-provider delivery, tracking, and subscriber management.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Multi-Provider Support** - SendGrid, Mailgun, AWS SES, and SMTP
|
|
8
|
+
- **Template Management** - Create, update, and render email templates with variable substitution
|
|
9
|
+
- **Delivery Tracking** - Track email delivery, opens, clicks, and bounces
|
|
10
|
+
- **Subscriber Management** - Manage subscribers, lists, and preferences
|
|
11
|
+
- **Queue Integration** - Schedule and send emails in background
|
|
12
|
+
- **Webhook Handling** - Process provider webhooks for delivery events
|
|
13
|
+
- **Database Persistence** - Store templates, delivery records, and subscribers
|
|
14
|
+
- **Analytics** - Comprehensive delivery statistics and reporting
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @bernierllc/email-service
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Peer Dependencies
|
|
23
|
+
|
|
24
|
+
Install email provider(s) you need:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# SendGrid
|
|
28
|
+
npm install @sendgrid/mail
|
|
29
|
+
|
|
30
|
+
# SMTP (included)
|
|
31
|
+
npm install nodemailer
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Usage
|
|
35
|
+
|
|
36
|
+
### Quick Start
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
import { EmailService } from '@bernierllc/email-service';
|
|
40
|
+
|
|
41
|
+
const service = new EmailService({
|
|
42
|
+
providers: [
|
|
43
|
+
{
|
|
44
|
+
type: 'smtp',
|
|
45
|
+
smtp: {
|
|
46
|
+
host: 'smtp.gmail.com',
|
|
47
|
+
port: 587,
|
|
48
|
+
secure: false,
|
|
49
|
+
auth: { user: 'you@gmail.com', pass: 'password' }
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
defaultProvider: 'smtp',
|
|
54
|
+
database: {
|
|
55
|
+
type: 'sqlite',
|
|
56
|
+
database: './data/email.db'
|
|
57
|
+
},
|
|
58
|
+
templates: {
|
|
59
|
+
cacheEnabled: true,
|
|
60
|
+
cacheTTL: 3600
|
|
61
|
+
},
|
|
62
|
+
tracking: {
|
|
63
|
+
enabled: true,
|
|
64
|
+
domain: 'yourdomain.com'
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
await service.initialize();
|
|
69
|
+
|
|
70
|
+
// Send an email
|
|
71
|
+
const result = await service.send({
|
|
72
|
+
from: 'noreply@yourdomain.com',
|
|
73
|
+
to: ['user@example.com'],
|
|
74
|
+
subject: 'Welcome!',
|
|
75
|
+
html: '<h1>Hello!</h1><p>Welcome to our service.</p>'
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
console.log(`Email sent: ${result.messageId}`);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Core Concepts
|
|
82
|
+
|
|
83
|
+
### 1. Multi-Provider Email Sending
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
// Configure multiple providers
|
|
87
|
+
const service = new EmailService({
|
|
88
|
+
providers: [
|
|
89
|
+
{
|
|
90
|
+
type: 'sendgrid',
|
|
91
|
+
apiKey: process.env.SENDGRID_API_KEY
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
type: 'mailgun',
|
|
95
|
+
apiKey: process.env.MAILGUN_API_KEY,
|
|
96
|
+
domain: 'mg.yourdomain.com'
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
type: 'ses',
|
|
100
|
+
region: 'us-east-1',
|
|
101
|
+
apiKey: process.env.AWS_ACCESS_KEY,
|
|
102
|
+
secretKey: process.env.AWS_SECRET_KEY
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
type: 'smtp',
|
|
106
|
+
smtp: {
|
|
107
|
+
host: 'smtp.gmail.com',
|
|
108
|
+
port: 587,
|
|
109
|
+
secure: false,
|
|
110
|
+
auth: {
|
|
111
|
+
user: process.env.SMTP_USER,
|
|
112
|
+
pass: process.env.SMTP_PASS
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
],
|
|
117
|
+
defaultProvider: 'sendgrid',
|
|
118
|
+
database: { type: 'sqlite', database: './email.db' }
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// Send via specific provider
|
|
122
|
+
await service.send({
|
|
123
|
+
from: 'noreply@yourdomain.com',
|
|
124
|
+
to: ['user@example.com'],
|
|
125
|
+
subject: 'Test',
|
|
126
|
+
html: '<p>Test</p>',
|
|
127
|
+
provider: 'mailgun' // Override default
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### 2. Template Management
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
// Create template
|
|
135
|
+
const template = await service.createTemplate({
|
|
136
|
+
name: 'welcome-email',
|
|
137
|
+
subject: 'Welcome {{name}}!',
|
|
138
|
+
html: `
|
|
139
|
+
<h1>Hello {{name}}</h1>
|
|
140
|
+
<p>Welcome to {{company}}!</p>
|
|
141
|
+
<p>Your account email is: {{email}}</p>
|
|
142
|
+
`,
|
|
143
|
+
text: 'Hello {{name}}, welcome to {{company}}!'
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// Send using template
|
|
147
|
+
await service.send({
|
|
148
|
+
from: 'noreply@yourdomain.com',
|
|
149
|
+
to: ['user@example.com'],
|
|
150
|
+
templateId: template.id,
|
|
151
|
+
templateData: {
|
|
152
|
+
name: 'John Doe',
|
|
153
|
+
company: 'Acme Corp',
|
|
154
|
+
email: 'john@example.com'
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// Update template
|
|
159
|
+
await service.updateTemplate(template.id, {
|
|
160
|
+
subject: 'Welcome to {{company}}, {{name}}!',
|
|
161
|
+
html: '<h1>Welcome {{name}}!</h1>'
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// Get template
|
|
165
|
+
const retrieved = await service.getTemplate(template.id);
|
|
166
|
+
console.log(retrieved.variables); // ['name', 'company', 'email']
|
|
167
|
+
|
|
168
|
+
// Delete template
|
|
169
|
+
await service.deleteTemplate(template.id);
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### 3. Delivery Tracking
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
// Send email
|
|
176
|
+
const result = await service.send({
|
|
177
|
+
from: 'noreply@yourdomain.com',
|
|
178
|
+
to: ['user@example.com'],
|
|
179
|
+
subject: 'Order Confirmation',
|
|
180
|
+
html: '<h1>Thanks for your order!</h1>'
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// Get delivery record
|
|
184
|
+
const delivery = await service.getDelivery(result.deliveryId);
|
|
185
|
+
console.log(delivery.status); // 'sent', 'delivered', 'opened', 'clicked', etc.
|
|
186
|
+
|
|
187
|
+
// Track opens
|
|
188
|
+
await service.trackOpen(result.deliveryId);
|
|
189
|
+
|
|
190
|
+
// Track clicks
|
|
191
|
+
await service.trackClick(result.deliveryId);
|
|
192
|
+
|
|
193
|
+
// Get statistics
|
|
194
|
+
const stats = await service.getDeliveryStats();
|
|
195
|
+
console.log(`Open rate: ${stats.openRate}%`);
|
|
196
|
+
console.log(`Click rate: ${stats.clickRate}%`);
|
|
197
|
+
console.log(`Bounce rate: ${stats.bounceRate}%`);
|
|
198
|
+
|
|
199
|
+
// Get statistics for date range
|
|
200
|
+
const monthStats = await service.getDeliveryStats(
|
|
201
|
+
new Date('2025-01-01'),
|
|
202
|
+
new Date('2025-01-31')
|
|
203
|
+
);
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### 4. Subscriber Management
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
// Create subscriber
|
|
210
|
+
const subscriber = await service.createSubscriber({
|
|
211
|
+
email: 'user@example.com',
|
|
212
|
+
name: 'John Doe',
|
|
213
|
+
lists: ['newsletter', 'updates'],
|
|
214
|
+
tags: ['premium', 'early-adopter'],
|
|
215
|
+
metadata: {
|
|
216
|
+
source: 'website',
|
|
217
|
+
signupDate: new Date()
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
// Get subscriber
|
|
222
|
+
const found = await service.getSubscriber(subscriber.id);
|
|
223
|
+
|
|
224
|
+
// Update subscriber
|
|
225
|
+
await service.updateSubscriber(subscriber.id, {
|
|
226
|
+
name: 'John Smith',
|
|
227
|
+
tags: ['premium', 'verified']
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
// Unsubscribe
|
|
231
|
+
await service.unsubscribe('user@example.com');
|
|
232
|
+
|
|
233
|
+
// Create subscriber list
|
|
234
|
+
const list = await service.createList(
|
|
235
|
+
'Monthly Newsletter',
|
|
236
|
+
'Our monthly product updates and news'
|
|
237
|
+
);
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### 5. Scheduled Emails
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
// Configure queue
|
|
244
|
+
const service = new EmailService({
|
|
245
|
+
providers: [/* ... */],
|
|
246
|
+
database: { type: 'sqlite', database: './email.db' },
|
|
247
|
+
queue: {
|
|
248
|
+
backend: new MemoryBackend(),
|
|
249
|
+
concurrency: 5,
|
|
250
|
+
retryPolicy: {
|
|
251
|
+
maxAttempts: 3,
|
|
252
|
+
backoff: { type: 'exponential', delay: 1000 }
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
// Schedule for later
|
|
258
|
+
await service.send({
|
|
259
|
+
from: 'noreply@yourdomain.com',
|
|
260
|
+
to: ['user@example.com'],
|
|
261
|
+
subject: 'Reminder',
|
|
262
|
+
html: '<p>This is your reminder</p>',
|
|
263
|
+
scheduledAt: new Date(Date.now() + 24 * 60 * 60 * 1000) // 24 hours
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
// Send with priority
|
|
267
|
+
await service.send({
|
|
268
|
+
from: 'alerts@yourdomain.com',
|
|
269
|
+
to: ['admin@yourdomain.com'],
|
|
270
|
+
subject: 'URGENT: System Alert',
|
|
271
|
+
html: '<p>Critical alert</p>',
|
|
272
|
+
priority: 'high' // high, normal, low
|
|
273
|
+
});
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### 6. Bulk Sending
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
const results = await service.sendBulk([
|
|
280
|
+
{
|
|
281
|
+
from: 'noreply@yourdomain.com',
|
|
282
|
+
to: ['user1@example.com'],
|
|
283
|
+
subject: 'Personalized for User 1',
|
|
284
|
+
html: '<p>Hello User 1</p>'
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
from: 'noreply@yourdomain.com',
|
|
288
|
+
to: ['user2@example.com'],
|
|
289
|
+
subject: 'Personalized for User 2',
|
|
290
|
+
html: '<p>Hello User 2</p>'
|
|
291
|
+
}
|
|
292
|
+
]);
|
|
293
|
+
|
|
294
|
+
results.forEach((result, index) => {
|
|
295
|
+
console.log(`Email ${index + 1}: ${result.success ? 'sent' : 'failed'}`);
|
|
296
|
+
});
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### 7. Webhook Handling
|
|
300
|
+
|
|
301
|
+
```typescript
|
|
302
|
+
// Register webhook handler
|
|
303
|
+
service.registerWebhookHandler('delivered', async (event) => {
|
|
304
|
+
console.log(`Email ${event.messageId} was delivered`);
|
|
305
|
+
// Update your database, trigger workflows, etc.
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
service.registerWebhookHandler('opened', async (event) => {
|
|
309
|
+
console.log(`Email ${event.messageId} was opened`);
|
|
310
|
+
// Track user engagement
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
service.registerWebhookHandler('clicked', async (event) => {
|
|
314
|
+
console.log(`Link clicked in ${event.messageId}`);
|
|
315
|
+
// Track click-through rates
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
service.registerWebhookHandler('bounced', async (event) => {
|
|
319
|
+
console.log(`Email ${event.messageId} bounced`);
|
|
320
|
+
// Update subscriber status
|
|
321
|
+
await service.unsubscribe(event.data.email);
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
// Process webhook from provider
|
|
325
|
+
await service.handleWebhook({
|
|
326
|
+
provider: 'sendgrid',
|
|
327
|
+
event: 'delivered',
|
|
328
|
+
messageId: 'msg_123',
|
|
329
|
+
timestamp: new Date(),
|
|
330
|
+
data: { /* provider-specific data */ }
|
|
331
|
+
});
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
## API Reference
|
|
335
|
+
|
|
336
|
+
### EmailService
|
|
337
|
+
|
|
338
|
+
#### Constructor
|
|
339
|
+
|
|
340
|
+
```typescript
|
|
341
|
+
new EmailService(config: EmailServiceConfig)
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
**Configuration:**
|
|
345
|
+
|
|
346
|
+
```typescript
|
|
347
|
+
interface EmailServiceConfig {
|
|
348
|
+
providers: ProviderConfig[];
|
|
349
|
+
defaultProvider?: EmailProvider;
|
|
350
|
+
database: DatabaseConfig;
|
|
351
|
+
queue?: QueueOptions;
|
|
352
|
+
templates?: {
|
|
353
|
+
cacheEnabled?: boolean;
|
|
354
|
+
cacheTTL?: number;
|
|
355
|
+
};
|
|
356
|
+
tracking?: {
|
|
357
|
+
enabled?: boolean;
|
|
358
|
+
domain?: string;
|
|
359
|
+
};
|
|
360
|
+
compliance?: {
|
|
361
|
+
unsubscribeLink?: boolean;
|
|
362
|
+
footerRequired?: boolean;
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
interface ProviderConfig {
|
|
367
|
+
type: 'sendgrid' | 'mailgun' | 'ses' | 'smtp';
|
|
368
|
+
apiKey?: string;
|
|
369
|
+
domain?: string;
|
|
370
|
+
region?: string;
|
|
371
|
+
smtp?: SMTPConfig;
|
|
372
|
+
rateLimit?: RateLimitConfig;
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
#### Methods
|
|
377
|
+
|
|
378
|
+
##### Email Sending
|
|
379
|
+
|
|
380
|
+
- `send(request: EmailRequest): Promise<SendEmailResult>` - Send email
|
|
381
|
+
- `sendBulk(requests: EmailRequest[]): Promise<SendEmailResult[]>` - Send multiple emails
|
|
382
|
+
|
|
383
|
+
##### Template Management
|
|
384
|
+
|
|
385
|
+
- `createTemplate(request: TemplateCreateRequest): Promise<EmailTemplate>` - Create template
|
|
386
|
+
- `getTemplate(id: string): Promise<EmailTemplate | null>` - Get template
|
|
387
|
+
- `updateTemplate(id: string, update: TemplateUpdateRequest): Promise<EmailTemplate>` - Update template
|
|
388
|
+
- `deleteTemplate(id: string): Promise<boolean>` - Delete template
|
|
389
|
+
|
|
390
|
+
##### Delivery Tracking
|
|
391
|
+
|
|
392
|
+
- `getDelivery(id: string): Promise<DeliveryRecord | null>` - Get delivery record
|
|
393
|
+
- `trackOpen(deliveryId: string): Promise<void>` - Track email open
|
|
394
|
+
- `trackClick(deliveryId: string): Promise<void>` - Track link click
|
|
395
|
+
- `getDeliveryStats(startDate?: Date, endDate?: Date): Promise<DeliveryStats>` - Get statistics
|
|
396
|
+
|
|
397
|
+
##### Subscriber Management
|
|
398
|
+
|
|
399
|
+
- `createSubscriber(request: SubscriberCreateRequest): Promise<Subscriber>` - Create subscriber
|
|
400
|
+
- `getSubscriber(id: string): Promise<Subscriber | null>` - Get subscriber
|
|
401
|
+
- `updateSubscriber(id: string, update: SubscriberUpdateRequest): Promise<Subscriber>` - Update subscriber
|
|
402
|
+
- `unsubscribe(email: string): Promise<boolean>` - Unsubscribe email
|
|
403
|
+
- `createList(name: string, description?: string): Promise<SubscriberList>` - Create list
|
|
404
|
+
|
|
405
|
+
##### Webhook Handling
|
|
406
|
+
|
|
407
|
+
- `registerWebhookHandler(event: string, handler: WebhookHandler): void` - Register handler
|
|
408
|
+
- `handleWebhook(event: WebhookEvent): Promise<void>` - Process webhook
|
|
409
|
+
|
|
410
|
+
##### Lifecycle
|
|
411
|
+
|
|
412
|
+
- `initialize(): Promise<void>` - Initialize service
|
|
413
|
+
- `shutdown(): Promise<void>` - Cleanup and shutdown
|
|
414
|
+
|
|
415
|
+
## Type Definitions
|
|
416
|
+
|
|
417
|
+
```typescript
|
|
418
|
+
interface EmailRequest {
|
|
419
|
+
from: EmailAddress | string;
|
|
420
|
+
to: EmailAddress[] | string[];
|
|
421
|
+
cc?: EmailAddress[] | string[];
|
|
422
|
+
bcc?: EmailAddress[] | string[];
|
|
423
|
+
subject: string;
|
|
424
|
+
html?: string;
|
|
425
|
+
text?: string;
|
|
426
|
+
templateId?: string;
|
|
427
|
+
templateData?: TemplateContext;
|
|
428
|
+
attachments?: EmailAttachment[];
|
|
429
|
+
headers?: Record<string, string>;
|
|
430
|
+
tags?: string[];
|
|
431
|
+
metadata?: Record<string, any>;
|
|
432
|
+
priority?: 'high' | 'normal' | 'low';
|
|
433
|
+
scheduledAt?: Date;
|
|
434
|
+
provider?: EmailProvider;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
interface SendEmailResult {
|
|
438
|
+
success: boolean;
|
|
439
|
+
messageId?: string;
|
|
440
|
+
deliveryId?: string;
|
|
441
|
+
provider?: EmailProvider;
|
|
442
|
+
error?: string;
|
|
443
|
+
timestamp: Date;
|
|
444
|
+
queuedForLater?: boolean;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
interface DeliveryStats {
|
|
448
|
+
total: number;
|
|
449
|
+
sent: number;
|
|
450
|
+
delivered: number;
|
|
451
|
+
opened: number;
|
|
452
|
+
clicked: number;
|
|
453
|
+
bounced: number;
|
|
454
|
+
failed: number;
|
|
455
|
+
openRate: number;
|
|
456
|
+
clickRate: number;
|
|
457
|
+
bounceRate: number;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
enum DeliveryStatus {
|
|
461
|
+
QUEUED = 'queued',
|
|
462
|
+
SENDING = 'sending',
|
|
463
|
+
SENT = 'sent',
|
|
464
|
+
DELIVERED = 'delivered',
|
|
465
|
+
OPENED = 'opened',
|
|
466
|
+
CLICKED = 'clicked',
|
|
467
|
+
BOUNCED = 'bounced',
|
|
468
|
+
FAILED = 'failed',
|
|
469
|
+
UNSUBSCRIBED = 'unsubscribed'
|
|
470
|
+
}
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
## Best Practices
|
|
474
|
+
|
|
475
|
+
### Error Handling
|
|
476
|
+
|
|
477
|
+
```typescript
|
|
478
|
+
try {
|
|
479
|
+
await service.send(emailRequest);
|
|
480
|
+
} catch (error) {
|
|
481
|
+
if (error instanceof ProviderError) {
|
|
482
|
+
// Switch to backup provider
|
|
483
|
+
console.error('Provider failed:', error.provider);
|
|
484
|
+
} else if (error instanceof TemplateError) {
|
|
485
|
+
// Template rendering failed
|
|
486
|
+
console.error('Template error:', error.message);
|
|
487
|
+
} else if (error instanceof DeliveryError) {
|
|
488
|
+
// Delivery failed
|
|
489
|
+
console.error('Delivery error:', error.message);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
### Template Variables
|
|
495
|
+
|
|
496
|
+
```typescript
|
|
497
|
+
// Always validate template data matches template variables
|
|
498
|
+
const template = await service.getTemplate(templateId);
|
|
499
|
+
const missingVars = template.variables.filter(
|
|
500
|
+
v => !(v in templateData)
|
|
501
|
+
);
|
|
502
|
+
if (missingVars.length > 0) {
|
|
503
|
+
throw new Error(`Missing template variables: ${missingVars.join(', ')}`);
|
|
504
|
+
}
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
### Rate Limiting
|
|
508
|
+
|
|
509
|
+
```typescript
|
|
510
|
+
// Configure per-provider rate limits
|
|
511
|
+
const service = new EmailService({
|
|
512
|
+
providers: [
|
|
513
|
+
{
|
|
514
|
+
type: 'sendgrid',
|
|
515
|
+
apiKey: process.env.SENDGRID_API_KEY,
|
|
516
|
+
rateLimit: {
|
|
517
|
+
maxPerSecond: 100,
|
|
518
|
+
maxPerMinute: 5000,
|
|
519
|
+
maxPerHour: 100000
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
],
|
|
523
|
+
// ...
|
|
524
|
+
});
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
### Monitoring
|
|
528
|
+
|
|
529
|
+
```typescript
|
|
530
|
+
// Regular health monitoring
|
|
531
|
+
setInterval(async () => {
|
|
532
|
+
const stats = await service.getDeliveryStats();
|
|
533
|
+
|
|
534
|
+
if (stats.bounceRate > 5) {
|
|
535
|
+
console.warn('High bounce rate detected:', stats.bounceRate);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
if (stats.failed > 100) {
|
|
539
|
+
console.error('High failure count:', stats.failed);
|
|
540
|
+
}
|
|
541
|
+
}, 60000); // Every minute
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
## Dependencies
|
|
545
|
+
|
|
546
|
+
This package orchestrates:
|
|
547
|
+
|
|
548
|
+
- [@bernierllc/email-sender](../../core/email-sender) - Multi-provider email delivery
|
|
549
|
+
- [@bernierllc/email-parser](../../core/email-parser) - Email content parsing
|
|
550
|
+
- [@bernierllc/template-engine](../../core/template-engine) - Template rendering
|
|
551
|
+
- [@bernierllc/queue-manager](../../core/queue-manager) - Background job processing
|
|
552
|
+
- [@bernierllc/webhook-validator](../../core/webhook-validator) - Webhook verification
|
|
553
|
+
- [@bernierllc/database-adapter](../../core/database-adapter) - Data persistence
|
|
554
|
+
- [@bernierllc/logger](../../core/logger) - Structured logging
|
|
555
|
+
- [@bernierllc/config-manager](../../core/config-manager) - Configuration management
|
|
556
|
+
|
|
557
|
+
## Integration Status
|
|
558
|
+
|
|
559
|
+
- **Logger**: Integrated - Uses @bernierllc/logger for structured logging
|
|
560
|
+
- **Docs-Suite**: Ready - Markdown documentation available
|
|
561
|
+
- **NeverHub integration**: Planned - Service discovery and event bus integration with @bernierllc/neverhub-adapter
|
|
562
|
+
|
|
563
|
+
## Examples
|
|
564
|
+
|
|
565
|
+
See the [examples directory](./examples) for complete working examples:
|
|
566
|
+
|
|
567
|
+
- `basic-smtp.ts` - Basic SMTP email sending
|
|
568
|
+
- `templates.ts` - Template management and rendering
|
|
569
|
+
- `tracking.ts` - Delivery tracking and analytics
|
|
570
|
+
- `subscribers.ts` - Subscriber management
|
|
571
|
+
- `webhooks.ts` - Webhook handling
|
|
572
|
+
- `multi-provider.ts` - Multi-provider configuration
|
|
573
|
+
|
|
574
|
+
## License
|
|
575
|
+
|
|
576
|
+
Copyright (c) 2025 Bernier LLC. All rights reserved.
|
|
577
|
+
|
|
578
|
+
This package is proprietary software licensed for use only within the scope of the project it was delivered for.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { EmailServiceConfig, EmailRequest, SendEmailResult, EmailTemplate, TemplateCreateRequest, TemplateUpdateRequest, DeliveryRecord, DeliveryStats, Subscriber, SubscriberCreateRequest, SubscriberUpdateRequest, SubscriberList, WebhookEvent, WebhookHandler } from './types.js';
|
|
2
|
+
export declare class EmailService {
|
|
3
|
+
private db;
|
|
4
|
+
private queue?;
|
|
5
|
+
private templateEngine;
|
|
6
|
+
private emailSenders;
|
|
7
|
+
private logger;
|
|
8
|
+
private config;
|
|
9
|
+
private webhookHandlers;
|
|
10
|
+
private templateCache;
|
|
11
|
+
constructor(config: EmailServiceConfig);
|
|
12
|
+
private initializeProviders;
|
|
13
|
+
initialize(): Promise<void>;
|
|
14
|
+
private createTables;
|
|
15
|
+
send(request: EmailRequest): Promise<SendEmailResult>;
|
|
16
|
+
private scheduleEmail;
|
|
17
|
+
sendBulk(requests: EmailRequest[]): Promise<SendEmailResult[]>;
|
|
18
|
+
createTemplate(request: TemplateCreateRequest): Promise<EmailTemplate>;
|
|
19
|
+
getTemplate(id: string): Promise<EmailTemplate | null>;
|
|
20
|
+
updateTemplate(id: string, update: TemplateUpdateRequest): Promise<EmailTemplate>;
|
|
21
|
+
deleteTemplate(id: string): Promise<boolean>;
|
|
22
|
+
private renderTemplate;
|
|
23
|
+
private extractVariables;
|
|
24
|
+
getDelivery(id: string): Promise<DeliveryRecord | null>;
|
|
25
|
+
trackOpen(deliveryId: string): Promise<void>;
|
|
26
|
+
trackClick(deliveryId: string): Promise<void>;
|
|
27
|
+
getDeliveryStats(startDate?: Date, endDate?: Date): Promise<DeliveryStats>;
|
|
28
|
+
private parseDeliveryRecord;
|
|
29
|
+
createSubscriber(request: SubscriberCreateRequest): Promise<Subscriber>;
|
|
30
|
+
getSubscriber(id: string): Promise<Subscriber | null>;
|
|
31
|
+
updateSubscriber(id: string, update: SubscriberUpdateRequest): Promise<Subscriber>;
|
|
32
|
+
unsubscribe(email: string): Promise<boolean>;
|
|
33
|
+
private parseSubscriber;
|
|
34
|
+
createList(name: string, description?: string): Promise<SubscriberList>;
|
|
35
|
+
registerWebhookHandler(event: string, handler: WebhookHandler): void;
|
|
36
|
+
handleWebhook(event: WebhookEvent): Promise<void>;
|
|
37
|
+
shutdown(): Promise<void>;
|
|
38
|
+
private generateId;
|
|
39
|
+
}
|