@flink-app/email-plugin 1.0.0 → 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/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 Flowmailer.
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 three different email providers through a unified client interface:
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 { emailPluginContext } from "@flink-app/email-plugin";
226
+ import { EmailPluginContext } from "@flink-app/email-plugin";
128
227
 
129
- export interface Ctx extends FlinkContext<emailPluginContext> {
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 emailPluginContext {
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