@flink-app/email-plugin 0.14.1 → 2.0.0-alpha.100
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/CHANGELOG.md +376 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +20 -1
- package/dist/postmarkClient.d.ts +19 -0
- package/dist/postmarkClient.js +91 -0
- package/dist/schemas/client.d.ts +3 -1
- package/dist/schemas/emailPostmark.d.ts +67 -0
- package/dist/schemas/emailPostmark.js +2 -0
- package/dist/schemas/emailSes.d.ts +60 -0
- package/dist/schemas/emailSes.js +2 -0
- package/dist/ses-types.d.ts +94 -0
- package/dist/ses-types.js +2 -0
- package/dist/sesClient.d.ts +48 -0
- package/dist/sesClient.js +388 -0
- package/package.json +10 -4
- package/readme.md +258 -7
- package/spec/sesClient.spec.ts +464 -0
- package/spec/support/jasmine.json +7 -0
- package/src/index.ts +7 -2
- package/src/postmarkClient.ts +53 -0
- package/src/schemas/client.ts +3 -1
- package/src/schemas/emailPostmark.ts +73 -0
- package/src/schemas/emailSes.ts +73 -0
- package/src/ses-types.ts +93 -0
- package/src/sesClient.ts +352 -0
package/readme.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Email Plugin
|
|
2
2
|
|
|
3
|
-
A Flink plugin that provides multi-provider email sending capabilities with support for SendGrid, SMTP, and
|
|
3
|
+
A Flink plugin that provides multi-provider email sending capabilities with support for SendGrid, SMTP, Flowmailer, AWS SES, and Postmark.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -12,7 +12,7 @@ npm install @flink-app/email-plugin
|
|
|
12
12
|
|
|
13
13
|
## Configuration
|
|
14
14
|
|
|
15
|
-
The email plugin supports
|
|
15
|
+
The email plugin supports five different email providers through a unified client interface:
|
|
16
16
|
|
|
17
17
|
### Option 1: SendGrid
|
|
18
18
|
|
|
@@ -118,15 +118,114 @@ interface flowmailerClientOptions {
|
|
|
118
118
|
}
|
|
119
119
|
```
|
|
120
120
|
|
|
121
|
+
### Option 4: AWS SES
|
|
122
|
+
|
|
123
|
+
Configure the plugin with AWS Simple Email Service (SESv2):
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
import { emailPlugin, sesClient } from "@flink-app/email-plugin";
|
|
127
|
+
|
|
128
|
+
function start() {
|
|
129
|
+
new FlinkApp<AppContext>({
|
|
130
|
+
name: "My app",
|
|
131
|
+
plugins: [
|
|
132
|
+
emailPlugin({
|
|
133
|
+
client: new sesClient({
|
|
134
|
+
region: "eu-north-1",
|
|
135
|
+
defaultFrom: "noreply@example.com",
|
|
136
|
+
configurationSet: "my-tracking-set", // optional
|
|
137
|
+
})
|
|
138
|
+
})
|
|
139
|
+
],
|
|
140
|
+
}).start();
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**SES Client Options:**
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
interface sesClientOptions {
|
|
148
|
+
region?: string; // AWS region (defaults to AWS_REGION env var)
|
|
149
|
+
credentials?: { // Explicit credentials (defaults to AWS credential chain)
|
|
150
|
+
accessKeyId: string;
|
|
151
|
+
secretAccessKey: string;
|
|
152
|
+
sessionToken?: string;
|
|
153
|
+
};
|
|
154
|
+
defaultFrom?: string; // Default sender address
|
|
155
|
+
configurationSet?: string; // Default SES configuration set for tracking
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Credentials are resolved in this order:
|
|
160
|
+
1. Explicit `credentials` option
|
|
161
|
+
2. Environment variables (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`)
|
|
162
|
+
3. IAM instance profile / ECS task role
|
|
163
|
+
4. AWS SSO / credential file
|
|
164
|
+
|
|
165
|
+
### Option 5: Postmark
|
|
166
|
+
|
|
167
|
+
Configure the plugin with [Postmark](https://postmarkapp.com/):
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
import { emailPlugin, postmarkClient } from "@flink-app/email-plugin";
|
|
171
|
+
|
|
172
|
+
function start() {
|
|
173
|
+
new FlinkApp<AppContext>({
|
|
174
|
+
name: "My app",
|
|
175
|
+
plugins: [
|
|
176
|
+
emailPlugin({
|
|
177
|
+
client: new postmarkClient({
|
|
178
|
+
serverToken: process.env.POSTMARK_SERVER_TOKEN!,
|
|
179
|
+
defaultMessageStream: "outbound", // optional
|
|
180
|
+
})
|
|
181
|
+
})
|
|
182
|
+
],
|
|
183
|
+
}).start();
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
**Postmark Client Options:**
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
interface postmarkClientOptions {
|
|
191
|
+
serverToken: string; // Postmark server token
|
|
192
|
+
defaultMessageStream?: string; // Defaults to "outbound"
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
**Postmark Email Type:**
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
type emailPostmark = {
|
|
200
|
+
from: string;
|
|
201
|
+
to: string[];
|
|
202
|
+
replyTo?: string;
|
|
203
|
+
cc?: string[];
|
|
204
|
+
bcc?: string[];
|
|
205
|
+
subject: string;
|
|
206
|
+
messageStream?: string; // Overrides defaultMessageStream
|
|
207
|
+
tag?: string; // Postmark tag for categorization
|
|
208
|
+
metadata?: Record<string, string>; // Custom metadata
|
|
209
|
+
attachments?: PostmarkAttachment[];
|
|
210
|
+
} & ({ text: string } | { html: string } | { text: string; html: string });
|
|
211
|
+
|
|
212
|
+
interface PostmarkAttachment {
|
|
213
|
+
content: string; // Base64 encoded
|
|
214
|
+
filename: string;
|
|
215
|
+
contentType?: string; // Defaults to "application/octet-stream"
|
|
216
|
+
contentId?: string; // For inline images, e.g. "cid:image1"
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
121
220
|
## TypeScript Setup
|
|
122
221
|
|
|
123
222
|
Add the plugin context to your app's context type (usually in `Ctx.ts`):
|
|
124
223
|
|
|
125
224
|
```typescript
|
|
126
225
|
import { FlinkContext } from "@flink-app/flink";
|
|
127
|
-
import {
|
|
226
|
+
import { EmailPluginContext } from "@flink-app/email-plugin";
|
|
128
227
|
|
|
129
|
-
export interface Ctx extends FlinkContext<
|
|
228
|
+
export interface Ctx extends FlinkContext<EmailPluginContext> {
|
|
130
229
|
// Your other context properties
|
|
131
230
|
}
|
|
132
231
|
```
|
|
@@ -134,7 +233,7 @@ export interface Ctx extends FlinkContext<emailPluginContext> {
|
|
|
134
233
|
**Plugin Context Interface:**
|
|
135
234
|
|
|
136
235
|
```typescript
|
|
137
|
-
interface
|
|
236
|
+
interface EmailPluginContext {
|
|
138
237
|
emailPlugin: {
|
|
139
238
|
client: client; // Unified email client interface
|
|
140
239
|
};
|
|
@@ -306,7 +405,7 @@ All email clients implement this unified interface:
|
|
|
306
405
|
|
|
307
406
|
```typescript
|
|
308
407
|
interface client {
|
|
309
|
-
send(email: email | emailSendgrid | emailFlowmailer): Promise<boolean>;
|
|
408
|
+
send(email: email | emailSendgrid | emailFlowmailer | emailSes | emailPostmark): Promise<boolean>;
|
|
310
409
|
}
|
|
311
410
|
```
|
|
312
411
|
|
|
@@ -400,11 +499,163 @@ if (!success) {
|
|
|
400
499
|
}
|
|
401
500
|
```
|
|
402
501
|
|
|
502
|
+
## AWS SES — Extended Features
|
|
503
|
+
|
|
504
|
+
The SES client supports additional features beyond the basic `send()` interface. Access them by casting the client to `sesClient`:
|
|
505
|
+
|
|
506
|
+
```typescript
|
|
507
|
+
import { sesClient } from "@flink-app/email-plugin";
|
|
508
|
+
const ses = ctx.plugins.emailPlugin.client as sesClient;
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
### Rich Send Results
|
|
512
|
+
|
|
513
|
+
Use `sendEmail()` instead of `send()` for detailed results:
|
|
514
|
+
|
|
515
|
+
```typescript
|
|
516
|
+
const result = await ses.sendEmail({
|
|
517
|
+
from: "noreply@example.com",
|
|
518
|
+
to: ["user@example.com"],
|
|
519
|
+
subject: "Hello",
|
|
520
|
+
html: "<h1>Welcome</h1>",
|
|
521
|
+
tags: { campaign: "welcome", env: "prod" },
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
if (result.success) {
|
|
525
|
+
console.log("Sent:", result.messageId);
|
|
526
|
+
} else {
|
|
527
|
+
console.error(`Failed: ${result.error?.code} - ${result.error?.message}`);
|
|
528
|
+
}
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
### Templated Emails
|
|
532
|
+
|
|
533
|
+
Send emails using SES templates:
|
|
534
|
+
|
|
535
|
+
```typescript
|
|
536
|
+
const result = await ses.sendTemplated({
|
|
537
|
+
to: ["user@example.com"],
|
|
538
|
+
template: "WelcomeEmail",
|
|
539
|
+
templateData: { name: "Joel", company: "Frost" },
|
|
540
|
+
});
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
### Bulk Email
|
|
544
|
+
|
|
545
|
+
Send to many recipients using a single SES template:
|
|
546
|
+
|
|
547
|
+
```typescript
|
|
548
|
+
const result = await ses.sendBulk({
|
|
549
|
+
template: "Newsletter",
|
|
550
|
+
defaultTemplateData: { company: "Frost" },
|
|
551
|
+
destinations: [
|
|
552
|
+
{ to: ["alice@example.com"], templateData: { name: "Alice" } },
|
|
553
|
+
{ to: ["bob@example.com"], templateData: { name: "Bob" } },
|
|
554
|
+
],
|
|
555
|
+
});
|
|
556
|
+
|
|
557
|
+
console.log(`Sent: ${result.successCount}, Failed: ${result.failureCount}`);
|
|
558
|
+
|
|
559
|
+
// Check individual results
|
|
560
|
+
for (const r of result.results) {
|
|
561
|
+
if (!r.success) {
|
|
562
|
+
console.error(`Failed: ${r.error?.code}`);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
### Verify Setup
|
|
568
|
+
|
|
569
|
+
Check that your SES credentials and configuration are working:
|
|
570
|
+
|
|
571
|
+
```typescript
|
|
572
|
+
const status = await ses.verifySetup();
|
|
573
|
+
console.log(status);
|
|
574
|
+
// { verified: true, sendingEnabled: true, region: "eu-north-1" }
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
`sendingEnabled: false` means the account is still in the SES sandbox (can only send to verified addresses).
|
|
578
|
+
|
|
579
|
+
### SES Email Type
|
|
580
|
+
|
|
581
|
+
```typescript
|
|
582
|
+
type emailSes = {
|
|
583
|
+
from: string;
|
|
584
|
+
to: string[];
|
|
585
|
+
replyTo?: string[];
|
|
586
|
+
cc?: string[];
|
|
587
|
+
bcc?: string[];
|
|
588
|
+
subject: string;
|
|
589
|
+
text?: string;
|
|
590
|
+
html?: string;
|
|
591
|
+
attachments?: SesAttachment[];
|
|
592
|
+
configurationSet?: string; // Override default config set
|
|
593
|
+
tags?: Record<string, string>; // Event tracking tags
|
|
594
|
+
};
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
## AWS SES Setup Guide
|
|
598
|
+
|
|
599
|
+
### 1. Verify your sending domain
|
|
600
|
+
|
|
601
|
+
```bash
|
|
602
|
+
# Verify a domain (recommended for production)
|
|
603
|
+
aws sesv2 create-email-identity --email-identity example.com --region eu-north-1
|
|
604
|
+
|
|
605
|
+
# Or verify a single email address (for testing)
|
|
606
|
+
aws sesv2 create-email-identity --email-identity sender@example.com --region eu-north-1
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
### 2. Check verification status
|
|
610
|
+
|
|
611
|
+
```bash
|
|
612
|
+
aws sesv2 get-email-identity --email-identity example.com --region eu-north-1
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
For domain verification, add the DKIM CNAME records shown in the response to your DNS.
|
|
616
|
+
|
|
617
|
+
### 3. Check account status
|
|
618
|
+
|
|
619
|
+
```bash
|
|
620
|
+
aws sesv2 get-account --region eu-north-1
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
Look for `"ProductionAccessEnabled": true`. If `false`, you're in the sandbox.
|
|
624
|
+
|
|
625
|
+
### 4. Request production access (exit sandbox)
|
|
626
|
+
|
|
627
|
+
```bash
|
|
628
|
+
aws sesv2 put-account-details \
|
|
629
|
+
--production-access-enabled \
|
|
630
|
+
--mail-type TRANSACTIONAL \
|
|
631
|
+
--website-url "https://example.com" \
|
|
632
|
+
--use-case-description "Sending transactional emails (order confirmations, password resets)" \
|
|
633
|
+
--region eu-north-1
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
### 5. Send a test email
|
|
637
|
+
|
|
638
|
+
```bash
|
|
639
|
+
aws sesv2 send-email \
|
|
640
|
+
--from-email-address sender@example.com \
|
|
641
|
+
--destination '{"ToAddresses":["recipient@example.com"]}' \
|
|
642
|
+
--content '{"Simple":{"Subject":{"Data":"Test"},"Body":{"Text":{"Data":"Hello from SES"}}}}' \
|
|
643
|
+
--region eu-north-1
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
### 6. Create a configuration set (optional, for tracking)
|
|
647
|
+
|
|
648
|
+
```bash
|
|
649
|
+
aws sesv2 create-configuration-set --configuration-set-name my-tracking-set --region eu-north-1
|
|
650
|
+
```
|
|
651
|
+
|
|
403
652
|
## Notes
|
|
404
653
|
|
|
405
654
|
- Either `text` or `html` must be provided (not both required, but at least one)
|
|
406
|
-
- All clients return a boolean indicating success/failure
|
|
655
|
+
- All clients return a boolean indicating success/failure via the `send()` interface
|
|
656
|
+
- The SES client additionally offers `sendEmail()`, `sendTemplated()`, `sendBulk()`, and `verifySetup()` with richer return types
|
|
407
657
|
- Flowmailer automatically handles OAuth token refresh
|
|
408
658
|
- SendGrid attachments must be base64 encoded
|
|
409
659
|
- SMTP client uses nodemailer internally
|
|
660
|
+
- Postmark attachments must be base64 encoded; supports `messageStream`, `tag`, and `metadata` Postmark-specific fields
|
|
410
661
|
- Multiple recipients are supported by all clients
|