@flink-app/email-plugin 2.0.0-alpha.74 → 2.0.0-alpha.75
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 +6 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +18 -1
- package/dist/schemas/client.d.ts +2 -1
- 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 +7 -5
- package/readme.md +199 -4
- package/spec/sesClient.spec.ts +464 -0
- package/spec/support/jasmine.json +7 -0
- package/src/index.ts +4 -1
- package/src/schemas/client.ts +2 -1
- package/src/schemas/emailSes.ts +73 -0
- package/src/ses-types.ts +93 -0
- package/src/sesClient.ts +352 -0
package/CHANGELOG.md
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,10 @@ import { client } from "./schemas/client";
|
|
|
3
3
|
export { sendgridClient } from "./sendgridClient";
|
|
4
4
|
export { smtpClient } from "./smtpClient";
|
|
5
5
|
export { flowMailerClient } from "./flowmailerClient";
|
|
6
|
+
export { sesClient } from "./sesClient";
|
|
6
7
|
export type { email } from "./schemas/email";
|
|
8
|
+
export type { emailSes } from "./schemas/emailSes";
|
|
9
|
+
export * from "./ses-types";
|
|
7
10
|
export type emailPluginOptions = {
|
|
8
11
|
/**
|
|
9
12
|
* Path for request
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,29 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
2
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.emailPlugin = exports.flowMailerClient = exports.smtpClient = exports.sendgridClient = void 0;
|
|
17
|
+
exports.emailPlugin = exports.sesClient = exports.flowMailerClient = exports.smtpClient = exports.sendgridClient = void 0;
|
|
4
18
|
var sendgridClient_1 = require("./sendgridClient");
|
|
5
19
|
Object.defineProperty(exports, "sendgridClient", { enumerable: true, get: function () { return sendgridClient_1.sendgridClient; } });
|
|
6
20
|
var smtpClient_1 = require("./smtpClient");
|
|
7
21
|
Object.defineProperty(exports, "smtpClient", { enumerable: true, get: function () { return smtpClient_1.smtpClient; } });
|
|
8
22
|
var flowmailerClient_1 = require("./flowmailerClient");
|
|
9
23
|
Object.defineProperty(exports, "flowMailerClient", { enumerable: true, get: function () { return flowmailerClient_1.flowMailerClient; } });
|
|
24
|
+
var sesClient_1 = require("./sesClient");
|
|
25
|
+
Object.defineProperty(exports, "sesClient", { enumerable: true, get: function () { return sesClient_1.sesClient; } });
|
|
26
|
+
__exportStar(require("./ses-types"), exports);
|
|
10
27
|
var emailPlugin = function (options) {
|
|
11
28
|
return {
|
|
12
29
|
id: "emailPlugin",
|
package/dist/schemas/client.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { email } from "./email";
|
|
2
2
|
import { emailFlowmailer } from "./emailFlowmailer";
|
|
3
3
|
import { emailSendgrid } from "./emailSendgrid";
|
|
4
|
+
import { emailSes } from "./emailSes";
|
|
4
5
|
export interface client {
|
|
5
|
-
send(email: email | emailSendgrid | emailFlowmailer): Promise<boolean>;
|
|
6
|
+
send(email: email | emailSendgrid | emailFlowmailer | emailSes): Promise<boolean>;
|
|
6
7
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export type emailSes = {
|
|
2
|
+
/**
|
|
3
|
+
* From address used to send the email
|
|
4
|
+
*/
|
|
5
|
+
from: string;
|
|
6
|
+
/**
|
|
7
|
+
* Email addresses to send to
|
|
8
|
+
*/
|
|
9
|
+
to: string[];
|
|
10
|
+
/**
|
|
11
|
+
* Reply-to addresses
|
|
12
|
+
*/
|
|
13
|
+
replyTo?: string[];
|
|
14
|
+
/**
|
|
15
|
+
* CC addresses
|
|
16
|
+
*/
|
|
17
|
+
cc?: string[];
|
|
18
|
+
/**
|
|
19
|
+
* Email addresses to add as BCC
|
|
20
|
+
*/
|
|
21
|
+
bcc?: string[];
|
|
22
|
+
/**
|
|
23
|
+
* Subject of email
|
|
24
|
+
*/
|
|
25
|
+
subject: string;
|
|
26
|
+
/**
|
|
27
|
+
* Plain text body
|
|
28
|
+
*/
|
|
29
|
+
text?: string;
|
|
30
|
+
/**
|
|
31
|
+
* HTML body
|
|
32
|
+
*/
|
|
33
|
+
html?: string;
|
|
34
|
+
/**
|
|
35
|
+
* File attachments
|
|
36
|
+
*/
|
|
37
|
+
attachments?: SesAttachment[];
|
|
38
|
+
/**
|
|
39
|
+
* SES configuration set for tracking (opens, clicks, bounces)
|
|
40
|
+
*/
|
|
41
|
+
configurationSet?: string;
|
|
42
|
+
/**
|
|
43
|
+
* SES tags for event filtering
|
|
44
|
+
*/
|
|
45
|
+
tags?: Record<string, string>;
|
|
46
|
+
};
|
|
47
|
+
export interface SesAttachment {
|
|
48
|
+
/**
|
|
49
|
+
* Filename shown to recipient
|
|
50
|
+
*/
|
|
51
|
+
filename: string;
|
|
52
|
+
/**
|
|
53
|
+
* Raw content as Buffer or base64 string
|
|
54
|
+
*/
|
|
55
|
+
content: Buffer | string;
|
|
56
|
+
/**
|
|
57
|
+
* MIME content type (e.g. "application/pdf"). Defaults to "application/octet-stream"
|
|
58
|
+
*/
|
|
59
|
+
contentType?: string;
|
|
60
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parameters for sending a templated email via SES
|
|
3
|
+
*/
|
|
4
|
+
export interface SesTemplatedEmailParams {
|
|
5
|
+
/** Sender address (overrides defaultFrom) */
|
|
6
|
+
from?: string;
|
|
7
|
+
/** Recipient addresses */
|
|
8
|
+
to: string[];
|
|
9
|
+
/** CC addresses */
|
|
10
|
+
cc?: string[];
|
|
11
|
+
/** BCC addresses */
|
|
12
|
+
bcc?: string[];
|
|
13
|
+
/** Reply-to addresses */
|
|
14
|
+
replyTo?: string[];
|
|
15
|
+
/** SES template name */
|
|
16
|
+
template: string;
|
|
17
|
+
/** Template data as key-value pairs (will be JSON.stringify'd for SES) */
|
|
18
|
+
templateData: Record<string, unknown>;
|
|
19
|
+
/** SES configuration set (overrides client default) */
|
|
20
|
+
configurationSet?: string;
|
|
21
|
+
/** SES tags for event filtering */
|
|
22
|
+
tags?: Record<string, string>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Parameters for sending bulk emails via SES template
|
|
26
|
+
*/
|
|
27
|
+
export interface SesBulkEmailParams {
|
|
28
|
+
/** Sender address (overrides defaultFrom) */
|
|
29
|
+
from?: string;
|
|
30
|
+
/** SES template name */
|
|
31
|
+
template: string;
|
|
32
|
+
/** Default template data applied to all destinations */
|
|
33
|
+
defaultTemplateData?: Record<string, unknown>;
|
|
34
|
+
/** Individual recipients with optional per-recipient template overrides */
|
|
35
|
+
destinations: SesBulkDestination[];
|
|
36
|
+
/** SES configuration set (overrides client default) */
|
|
37
|
+
configurationSet?: string;
|
|
38
|
+
/** Reply-to addresses */
|
|
39
|
+
replyTo?: string[];
|
|
40
|
+
/** SES tags for event filtering */
|
|
41
|
+
tags?: Record<string, string>;
|
|
42
|
+
}
|
|
43
|
+
export interface SesBulkDestination {
|
|
44
|
+
to: string[];
|
|
45
|
+
cc?: string[];
|
|
46
|
+
bcc?: string[];
|
|
47
|
+
/** Per-destination template data (merged with defaultTemplateData) */
|
|
48
|
+
templateData?: Record<string, unknown>;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Result from a single send operation
|
|
52
|
+
*/
|
|
53
|
+
export interface SesResult {
|
|
54
|
+
success: boolean;
|
|
55
|
+
/** AWS MessageId, present on success */
|
|
56
|
+
messageId?: string;
|
|
57
|
+
/** Error details, present on failure */
|
|
58
|
+
error?: {
|
|
59
|
+
code: string;
|
|
60
|
+
message: string;
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Result from a bulk send operation
|
|
65
|
+
*/
|
|
66
|
+
export interface SesBulkResult {
|
|
67
|
+
success: boolean;
|
|
68
|
+
/** Per-destination results */
|
|
69
|
+
results: Array<{
|
|
70
|
+
success: boolean;
|
|
71
|
+
messageId?: string;
|
|
72
|
+
error?: {
|
|
73
|
+
code: string;
|
|
74
|
+
message: string;
|
|
75
|
+
};
|
|
76
|
+
}>;
|
|
77
|
+
/** Number of successful sends */
|
|
78
|
+
successCount: number;
|
|
79
|
+
/** Number of failed sends */
|
|
80
|
+
failureCount: number;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Result from verifySetup()
|
|
84
|
+
*/
|
|
85
|
+
export interface SesSetupStatus {
|
|
86
|
+
/** Whether credentials are valid and SES is accessible */
|
|
87
|
+
verified: boolean;
|
|
88
|
+
/** Whether the account is out of the SES sandbox */
|
|
89
|
+
sendingEnabled: boolean;
|
|
90
|
+
/** The configured AWS region */
|
|
91
|
+
region: string;
|
|
92
|
+
/** Error message if verification failed */
|
|
93
|
+
error?: string;
|
|
94
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { SESv2Client } from "@aws-sdk/client-sesv2";
|
|
2
|
+
import { client } from "./schemas/client";
|
|
3
|
+
import { emailSes } from "./schemas/emailSes";
|
|
4
|
+
import { SesTemplatedEmailParams, SesBulkEmailParams, SesResult, SesBulkResult, SesSetupStatus } from "./ses-types";
|
|
5
|
+
export interface sesClientOptions {
|
|
6
|
+
/** AWS region (defaults to AWS_REGION env var) */
|
|
7
|
+
region?: string;
|
|
8
|
+
/** Explicit credentials. Omit to use default AWS credential chain (env vars, IAM roles, etc.) */
|
|
9
|
+
credentials?: {
|
|
10
|
+
accessKeyId: string;
|
|
11
|
+
secretAccessKey: string;
|
|
12
|
+
sessionToken?: string;
|
|
13
|
+
};
|
|
14
|
+
/** Default "from" address when not specified per-email */
|
|
15
|
+
defaultFrom?: string;
|
|
16
|
+
/** Default SES configuration set name */
|
|
17
|
+
configurationSet?: string;
|
|
18
|
+
}
|
|
19
|
+
export declare class sesClient implements client {
|
|
20
|
+
private awsClient;
|
|
21
|
+
private defaultFrom?;
|
|
22
|
+
private defaultConfigurationSet?;
|
|
23
|
+
constructor(options: sesClientOptions, awsClient?: SESv2Client);
|
|
24
|
+
/**
|
|
25
|
+
* Send an email via SES. Implements the base `client` interface.
|
|
26
|
+
* Returns `true` on success, `false` on failure.
|
|
27
|
+
* For richer results (messageId, error details), use `sendEmail()` instead.
|
|
28
|
+
*/
|
|
29
|
+
send(email: emailSes): Promise<boolean>;
|
|
30
|
+
/**
|
|
31
|
+
* Send an email via SES with rich result including messageId and error details.
|
|
32
|
+
*/
|
|
33
|
+
sendEmail(email: emailSes): Promise<SesResult>;
|
|
34
|
+
/**
|
|
35
|
+
* Send a templated email using an SES template.
|
|
36
|
+
*/
|
|
37
|
+
sendTemplated(params: SesTemplatedEmailParams): Promise<SesResult>;
|
|
38
|
+
/**
|
|
39
|
+
* Send bulk emails using an SES template.
|
|
40
|
+
*/
|
|
41
|
+
sendBulk(params: SesBulkEmailParams): Promise<SesBulkResult>;
|
|
42
|
+
/**
|
|
43
|
+
* Verify that the SES setup is working — checks credentials and account status.
|
|
44
|
+
*/
|
|
45
|
+
verifySetup(): Promise<SesSetupStatus>;
|
|
46
|
+
private toMessageTags;
|
|
47
|
+
private buildRawMimeMessage;
|
|
48
|
+
}
|
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
|
3
|
+
__assign = Object.assign || function(t) {
|
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
+
s = arguments[i];
|
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
+
t[p] = s[p];
|
|
8
|
+
}
|
|
9
|
+
return t;
|
|
10
|
+
};
|
|
11
|
+
return __assign.apply(this, arguments);
|
|
12
|
+
};
|
|
13
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
14
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
15
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
16
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
17
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
18
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
19
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
23
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
24
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
25
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
26
|
+
function step(op) {
|
|
27
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
28
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
29
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
30
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
31
|
+
switch (op[0]) {
|
|
32
|
+
case 0: case 1: t = op; break;
|
|
33
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
34
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
35
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
36
|
+
default:
|
|
37
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
38
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
39
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
40
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
41
|
+
if (t[2]) _.ops.pop();
|
|
42
|
+
_.trys.pop(); continue;
|
|
43
|
+
}
|
|
44
|
+
op = body.call(thisArg, _);
|
|
45
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
46
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
|
+
exports.sesClient = void 0;
|
|
51
|
+
var client_sesv2_1 = require("@aws-sdk/client-sesv2");
|
|
52
|
+
var sesClient = /** @class */ (function () {
|
|
53
|
+
function sesClient(options, awsClient) {
|
|
54
|
+
this.defaultFrom = options.defaultFrom;
|
|
55
|
+
this.defaultConfigurationSet = options.configurationSet;
|
|
56
|
+
this.awsClient =
|
|
57
|
+
awsClient !== null && awsClient !== void 0 ? awsClient : new client_sesv2_1.SESv2Client({
|
|
58
|
+
region: options.region,
|
|
59
|
+
credentials: options.credentials,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Send an email via SES. Implements the base `client` interface.
|
|
64
|
+
* Returns `true` on success, `false` on failure.
|
|
65
|
+
* For richer results (messageId, error details), use `sendEmail()` instead.
|
|
66
|
+
*/
|
|
67
|
+
sesClient.prototype.send = function (email) {
|
|
68
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
69
|
+
var result;
|
|
70
|
+
return __generator(this, function (_a) {
|
|
71
|
+
switch (_a.label) {
|
|
72
|
+
case 0: return [4 /*yield*/, this.sendEmail(email)];
|
|
73
|
+
case 1:
|
|
74
|
+
result = _a.sent();
|
|
75
|
+
return [2 /*return*/, result.success];
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Send an email via SES with rich result including messageId and error details.
|
|
82
|
+
*/
|
|
83
|
+
sesClient.prototype.sendEmail = function (email) {
|
|
84
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
85
|
+
var from, hasAttachments, content, input, response, err_1;
|
|
86
|
+
return __generator(this, function (_a) {
|
|
87
|
+
switch (_a.label) {
|
|
88
|
+
case 0:
|
|
89
|
+
from = email.from || this.defaultFrom;
|
|
90
|
+
if (!from) {
|
|
91
|
+
return [2 /*return*/, {
|
|
92
|
+
success: false,
|
|
93
|
+
error: {
|
|
94
|
+
code: "MISSING_FROM",
|
|
95
|
+
message: "No 'from' address specified. Set it on the email or use defaultFrom in sesClientOptions.",
|
|
96
|
+
},
|
|
97
|
+
}];
|
|
98
|
+
}
|
|
99
|
+
_a.label = 1;
|
|
100
|
+
case 1:
|
|
101
|
+
_a.trys.push([1, 3, , 4]);
|
|
102
|
+
hasAttachments = email.attachments && email.attachments.length > 0;
|
|
103
|
+
content = hasAttachments
|
|
104
|
+
? { Raw: { Data: this.buildRawMimeMessage(email, from) } }
|
|
105
|
+
: {
|
|
106
|
+
Simple: {
|
|
107
|
+
Subject: { Data: email.subject, Charset: "UTF-8" },
|
|
108
|
+
Body: __assign(__assign({}, (email.text
|
|
109
|
+
? { Text: { Data: email.text, Charset: "UTF-8" } }
|
|
110
|
+
: {})), (email.html
|
|
111
|
+
? { Html: { Data: email.html, Charset: "UTF-8" } }
|
|
112
|
+
: {})),
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
input = {
|
|
116
|
+
FromEmailAddress: from,
|
|
117
|
+
Destination: {
|
|
118
|
+
ToAddresses: email.to,
|
|
119
|
+
CcAddresses: email.cc,
|
|
120
|
+
BccAddresses: email.bcc,
|
|
121
|
+
},
|
|
122
|
+
ReplyToAddresses: email.replyTo,
|
|
123
|
+
ConfigurationSetName: email.configurationSet || this.defaultConfigurationSet,
|
|
124
|
+
EmailTags: this.toMessageTags(email.tags),
|
|
125
|
+
Content: content,
|
|
126
|
+
};
|
|
127
|
+
return [4 /*yield*/, this.awsClient.send(new client_sesv2_1.SendEmailCommand(input))];
|
|
128
|
+
case 2:
|
|
129
|
+
response = _a.sent();
|
|
130
|
+
return [2 /*return*/, {
|
|
131
|
+
success: true,
|
|
132
|
+
messageId: response.MessageId,
|
|
133
|
+
}];
|
|
134
|
+
case 3:
|
|
135
|
+
err_1 = _a.sent();
|
|
136
|
+
return [2 /*return*/, {
|
|
137
|
+
success: false,
|
|
138
|
+
error: {
|
|
139
|
+
code: err_1.name || err_1.code || "UNKNOWN",
|
|
140
|
+
message: err_1.message || "Unknown error",
|
|
141
|
+
},
|
|
142
|
+
}];
|
|
143
|
+
case 4: return [2 /*return*/];
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
};
|
|
148
|
+
/**
|
|
149
|
+
* Send a templated email using an SES template.
|
|
150
|
+
*/
|
|
151
|
+
sesClient.prototype.sendTemplated = function (params) {
|
|
152
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
153
|
+
var from, input, response, err_2;
|
|
154
|
+
return __generator(this, function (_a) {
|
|
155
|
+
switch (_a.label) {
|
|
156
|
+
case 0:
|
|
157
|
+
from = params.from || this.defaultFrom;
|
|
158
|
+
if (!from) {
|
|
159
|
+
return [2 /*return*/, {
|
|
160
|
+
success: false,
|
|
161
|
+
error: {
|
|
162
|
+
code: "MISSING_FROM",
|
|
163
|
+
message: "No 'from' address specified. Set it on params or use defaultFrom in sesClientOptions.",
|
|
164
|
+
},
|
|
165
|
+
}];
|
|
166
|
+
}
|
|
167
|
+
_a.label = 1;
|
|
168
|
+
case 1:
|
|
169
|
+
_a.trys.push([1, 3, , 4]);
|
|
170
|
+
input = {
|
|
171
|
+
FromEmailAddress: from,
|
|
172
|
+
Destination: {
|
|
173
|
+
ToAddresses: params.to,
|
|
174
|
+
CcAddresses: params.cc,
|
|
175
|
+
BccAddresses: params.bcc,
|
|
176
|
+
},
|
|
177
|
+
ReplyToAddresses: params.replyTo,
|
|
178
|
+
ConfigurationSetName: params.configurationSet || this.defaultConfigurationSet,
|
|
179
|
+
EmailTags: this.toMessageTags(params.tags),
|
|
180
|
+
Content: {
|
|
181
|
+
Template: {
|
|
182
|
+
TemplateName: params.template,
|
|
183
|
+
TemplateData: JSON.stringify(params.templateData),
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
return [4 /*yield*/, this.awsClient.send(new client_sesv2_1.SendEmailCommand(input))];
|
|
188
|
+
case 2:
|
|
189
|
+
response = _a.sent();
|
|
190
|
+
return [2 /*return*/, {
|
|
191
|
+
success: true,
|
|
192
|
+
messageId: response.MessageId,
|
|
193
|
+
}];
|
|
194
|
+
case 3:
|
|
195
|
+
err_2 = _a.sent();
|
|
196
|
+
return [2 /*return*/, {
|
|
197
|
+
success: false,
|
|
198
|
+
error: {
|
|
199
|
+
code: err_2.name || err_2.code || "UNKNOWN",
|
|
200
|
+
message: err_2.message || "Unknown error",
|
|
201
|
+
},
|
|
202
|
+
}];
|
|
203
|
+
case 4: return [2 /*return*/];
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
};
|
|
208
|
+
/**
|
|
209
|
+
* Send bulk emails using an SES template.
|
|
210
|
+
*/
|
|
211
|
+
sesClient.prototype.sendBulk = function (params) {
|
|
212
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
213
|
+
var from, input, response, results, successCount, failureCount, err_3;
|
|
214
|
+
return __generator(this, function (_a) {
|
|
215
|
+
switch (_a.label) {
|
|
216
|
+
case 0:
|
|
217
|
+
from = params.from || this.defaultFrom;
|
|
218
|
+
if (!from) {
|
|
219
|
+
return [2 /*return*/, {
|
|
220
|
+
success: false,
|
|
221
|
+
results: [],
|
|
222
|
+
successCount: 0,
|
|
223
|
+
failureCount: params.destinations.length,
|
|
224
|
+
}];
|
|
225
|
+
}
|
|
226
|
+
_a.label = 1;
|
|
227
|
+
case 1:
|
|
228
|
+
_a.trys.push([1, 3, , 4]);
|
|
229
|
+
input = {
|
|
230
|
+
FromEmailAddress: from,
|
|
231
|
+
ReplyToAddresses: params.replyTo,
|
|
232
|
+
ConfigurationSetName: params.configurationSet || this.defaultConfigurationSet,
|
|
233
|
+
DefaultEmailTags: this.toMessageTags(params.tags),
|
|
234
|
+
DefaultContent: {
|
|
235
|
+
Template: {
|
|
236
|
+
TemplateName: params.template,
|
|
237
|
+
TemplateData: params.defaultTemplateData
|
|
238
|
+
? JSON.stringify(params.defaultTemplateData)
|
|
239
|
+
: undefined,
|
|
240
|
+
},
|
|
241
|
+
},
|
|
242
|
+
BulkEmailEntries: params.destinations.map(function (dest) { return ({
|
|
243
|
+
Destination: {
|
|
244
|
+
ToAddresses: dest.to,
|
|
245
|
+
CcAddresses: dest.cc,
|
|
246
|
+
BccAddresses: dest.bcc,
|
|
247
|
+
},
|
|
248
|
+
ReplacementEmailContent: dest.templateData
|
|
249
|
+
? {
|
|
250
|
+
ReplacementTemplate: {
|
|
251
|
+
ReplacementTemplateData: JSON.stringify(dest.templateData),
|
|
252
|
+
},
|
|
253
|
+
}
|
|
254
|
+
: undefined,
|
|
255
|
+
}); }),
|
|
256
|
+
};
|
|
257
|
+
return [4 /*yield*/, this.awsClient.send(new client_sesv2_1.SendBulkEmailCommand(input))];
|
|
258
|
+
case 2:
|
|
259
|
+
response = _a.sent();
|
|
260
|
+
results = (response.BulkEmailEntryResults || []).map(function (entry) {
|
|
261
|
+
var success = entry.Status === "SUCCESS";
|
|
262
|
+
return {
|
|
263
|
+
success: success,
|
|
264
|
+
messageId: success ? entry.MessageId : undefined,
|
|
265
|
+
error: !success
|
|
266
|
+
? {
|
|
267
|
+
code: entry.Error || "UNKNOWN",
|
|
268
|
+
message: entry.Error || "Bulk send entry failed",
|
|
269
|
+
}
|
|
270
|
+
: undefined,
|
|
271
|
+
};
|
|
272
|
+
});
|
|
273
|
+
successCount = results.filter(function (r) { return r.success; }).length;
|
|
274
|
+
failureCount = results.filter(function (r) { return !r.success; }).length;
|
|
275
|
+
return [2 /*return*/, {
|
|
276
|
+
success: failureCount === 0,
|
|
277
|
+
results: results,
|
|
278
|
+
successCount: successCount,
|
|
279
|
+
failureCount: failureCount,
|
|
280
|
+
}];
|
|
281
|
+
case 3:
|
|
282
|
+
err_3 = _a.sent();
|
|
283
|
+
return [2 /*return*/, {
|
|
284
|
+
success: false,
|
|
285
|
+
results: [],
|
|
286
|
+
successCount: 0,
|
|
287
|
+
failureCount: params.destinations.length,
|
|
288
|
+
}];
|
|
289
|
+
case 4: return [2 /*return*/];
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
};
|
|
294
|
+
/**
|
|
295
|
+
* Verify that the SES setup is working — checks credentials and account status.
|
|
296
|
+
*/
|
|
297
|
+
sesClient.prototype.verifySetup = function () {
|
|
298
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
299
|
+
var response, region, err_4;
|
|
300
|
+
return __generator(this, function (_a) {
|
|
301
|
+
switch (_a.label) {
|
|
302
|
+
case 0:
|
|
303
|
+
_a.trys.push([0, 3, , 4]);
|
|
304
|
+
return [4 /*yield*/, this.awsClient.send(new client_sesv2_1.GetAccountCommand({}))];
|
|
305
|
+
case 1:
|
|
306
|
+
response = _a.sent();
|
|
307
|
+
return [4 /*yield*/, this.awsClient.config.region()];
|
|
308
|
+
case 2:
|
|
309
|
+
region = (_a.sent()) || "unknown";
|
|
310
|
+
return [2 /*return*/, {
|
|
311
|
+
verified: true,
|
|
312
|
+
sendingEnabled: response.ProductionAccessEnabled === true,
|
|
313
|
+
region: region,
|
|
314
|
+
}];
|
|
315
|
+
case 3:
|
|
316
|
+
err_4 = _a.sent();
|
|
317
|
+
return [2 /*return*/, {
|
|
318
|
+
verified: false,
|
|
319
|
+
sendingEnabled: false,
|
|
320
|
+
region: "unknown",
|
|
321
|
+
error: err_4.message || "Failed to verify SES setup",
|
|
322
|
+
}];
|
|
323
|
+
case 4: return [2 /*return*/];
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
});
|
|
327
|
+
};
|
|
328
|
+
sesClient.prototype.toMessageTags = function (tags) {
|
|
329
|
+
if (!tags)
|
|
330
|
+
return undefined;
|
|
331
|
+
return Object.entries(tags).map(function (_a) {
|
|
332
|
+
var Name = _a[0], Value = _a[1];
|
|
333
|
+
return ({ Name: Name, Value: Value });
|
|
334
|
+
});
|
|
335
|
+
};
|
|
336
|
+
sesClient.prototype.buildRawMimeMessage = function (email, from) {
|
|
337
|
+
var _a, _b;
|
|
338
|
+
var boundary = "----=_Part_".concat(Date.now(), "_").concat(Math.random().toString(36).substring(2));
|
|
339
|
+
var lines = [];
|
|
340
|
+
lines.push("From: ".concat(from));
|
|
341
|
+
lines.push("To: ".concat(email.to.join(", ")));
|
|
342
|
+
if ((_a = email.cc) === null || _a === void 0 ? void 0 : _a.length)
|
|
343
|
+
lines.push("Cc: ".concat(email.cc.join(", ")));
|
|
344
|
+
if ((_b = email.replyTo) === null || _b === void 0 ? void 0 : _b.length)
|
|
345
|
+
lines.push("Reply-To: ".concat(email.replyTo.join(", ")));
|
|
346
|
+
lines.push("Subject: =?UTF-8?B?".concat(Buffer.from(email.subject).toString("base64"), "?="));
|
|
347
|
+
lines.push("MIME-Version: 1.0");
|
|
348
|
+
lines.push("Content-Type: multipart/mixed; boundary=\"".concat(boundary, "\""));
|
|
349
|
+
lines.push("");
|
|
350
|
+
// Text part
|
|
351
|
+
if (email.text) {
|
|
352
|
+
lines.push("--".concat(boundary));
|
|
353
|
+
lines.push("Content-Type: text/plain; charset=UTF-8");
|
|
354
|
+
lines.push("Content-Transfer-Encoding: 7bit");
|
|
355
|
+
lines.push("");
|
|
356
|
+
lines.push(email.text);
|
|
357
|
+
lines.push("");
|
|
358
|
+
}
|
|
359
|
+
// HTML part
|
|
360
|
+
if (email.html) {
|
|
361
|
+
lines.push("--".concat(boundary));
|
|
362
|
+
lines.push("Content-Type: text/html; charset=UTF-8");
|
|
363
|
+
lines.push("Content-Transfer-Encoding: 7bit");
|
|
364
|
+
lines.push("");
|
|
365
|
+
lines.push(email.html);
|
|
366
|
+
lines.push("");
|
|
367
|
+
}
|
|
368
|
+
// Attachments
|
|
369
|
+
for (var _i = 0, _c = email.attachments || []; _i < _c.length; _i++) {
|
|
370
|
+
var attachment = _c[_i];
|
|
371
|
+
var contentType = attachment.contentType || "application/octet-stream";
|
|
372
|
+
var base64Content = Buffer.isBuffer(attachment.content)
|
|
373
|
+
? attachment.content.toString("base64")
|
|
374
|
+
: attachment.content;
|
|
375
|
+
lines.push("--".concat(boundary));
|
|
376
|
+
lines.push("Content-Type: ".concat(contentType, "; name=\"").concat(attachment.filename, "\""));
|
|
377
|
+
lines.push("Content-Disposition: attachment; filename=\"".concat(attachment.filename, "\""));
|
|
378
|
+
lines.push("Content-Transfer-Encoding: base64");
|
|
379
|
+
lines.push("");
|
|
380
|
+
lines.push(base64Content);
|
|
381
|
+
lines.push("");
|
|
382
|
+
}
|
|
383
|
+
lines.push("--".concat(boundary, "--"));
|
|
384
|
+
return new TextEncoder().encode(lines.join("\r\n"));
|
|
385
|
+
};
|
|
386
|
+
return sesClient;
|
|
387
|
+
}());
|
|
388
|
+
exports.sesClient = sesClient;
|