@bernierllc/email-sender 5.2.1 → 5.3.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/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/providers/mailgun/sender-manager.d.ts +85 -0
- package/dist/providers/mailgun/sender-manager.d.ts.map +1 -0
- package/dist/providers/mailgun/sender-manager.js +615 -0
- package/dist/providers/mailgun/sender-manager.js.map +1 -0
- package/dist/providers/mailgun.d.ts +3 -0
- package/dist/providers/mailgun.d.ts.map +1 -1
- package/dist/providers/mailgun.js +10 -0
- package/dist/providers/mailgun.js.map +1 -1
- package/dist/providers/postmark/sender-manager.d.ts +108 -0
- package/dist/providers/postmark/sender-manager.d.ts.map +1 -0
- package/dist/providers/postmark/sender-manager.js +518 -0
- package/dist/providers/postmark/sender-manager.js.map +1 -0
- package/dist/providers/postmark.d.ts +2 -0
- package/dist/providers/postmark.d.ts.map +1 -1
- package/dist/providers/postmark.js +3 -0
- package/dist/providers/postmark.js.map +1 -1
- package/dist/providers/sendgrid/sender-manager.d.ts +37 -0
- package/dist/providers/sendgrid/sender-manager.d.ts.map +1 -1
- package/dist/providers/sendgrid/sender-manager.js +318 -0
- package/dist/providers/sendgrid/sender-manager.js.map +1 -1
- package/dist/providers/sendgrid.d.ts +31 -0
- package/dist/providers/sendgrid.d.ts.map +1 -1
- package/dist/providers/sendgrid.js +69 -0
- package/dist/providers/sendgrid.js.map +1 -1
- package/dist/providers/ses/sender-manager.d.ts +48 -0
- package/dist/providers/ses/sender-manager.d.ts.map +1 -0
- package/dist/providers/ses/sender-manager.js +437 -0
- package/dist/providers/ses/sender-manager.js.map +1 -0
- package/dist/providers/ses.d.ts +23 -0
- package/dist/providers/ses.d.ts.map +1 -1
- package/dist/providers/ses.js +30 -0
- package/dist/providers/ses.js.map +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AWS SES Sender Manager
|
|
3
|
+
*
|
|
4
|
+
* Manages sender identity lifecycle via the SES v2 API:
|
|
5
|
+
* - CreateEmailIdentity / DeleteEmailIdentity
|
|
6
|
+
* - GetEmailIdentity (verification status + DKIM tokens)
|
|
7
|
+
* - ListEmailIdentities
|
|
8
|
+
* - PutEmailIdentityConfigurationSetAttributes (limited update)
|
|
9
|
+
*
|
|
10
|
+
* SES uses domain-based verification. When an email identity is created,
|
|
11
|
+
* SES automatically initiates DKIM verification and returns DKIM tokens
|
|
12
|
+
* that must be published as DNS CNAME records.
|
|
13
|
+
*/
|
|
14
|
+
import type { ProviderCreateSenderInput, ProviderUpdateSenderInput, ProviderSenderResult, ProviderDeleteResult, ProviderVerificationResult, ProviderVerificationType, DNSRecord, ProviderValidationResult, ProviderSender, SenderConfiguration, SyncResult } from '@bernierllc/email-sender-manager';
|
|
15
|
+
/** Minimal logger interface accepted by the sender manager. */
|
|
16
|
+
export interface SesSenderManagerLogger {
|
|
17
|
+
info: (message: string) => void;
|
|
18
|
+
debug: (message: string) => void;
|
|
19
|
+
warn: (message: string) => void;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Shape of the SES v2 client we depend on.
|
|
23
|
+
*
|
|
24
|
+
* We accept `any` in the constructor so the caller can pass an actual
|
|
25
|
+
* `SESv2Client` (from `@aws-sdk/client-sesv2`) or a test double. The
|
|
26
|
+
* methods listed below are the only ones we invoke.
|
|
27
|
+
*/
|
|
28
|
+
export interface SesClientShape {
|
|
29
|
+
send(command: unknown): Promise<unknown>;
|
|
30
|
+
}
|
|
31
|
+
export declare class SesSenderManager {
|
|
32
|
+
private readonly sesClient;
|
|
33
|
+
private readonly logger;
|
|
34
|
+
constructor(sesClient: SesClientShape, logger?: SesSenderManagerLogger);
|
|
35
|
+
createSender(input: ProviderCreateSenderInput): Promise<ProviderSenderResult>;
|
|
36
|
+
updateSender(input: ProviderUpdateSenderInput): Promise<ProviderSenderResult>;
|
|
37
|
+
deleteSender(providerSenderId: string): Promise<ProviderDeleteResult>;
|
|
38
|
+
getVerificationType(): ProviderVerificationType;
|
|
39
|
+
initiateVerification(providerSenderId: string): Promise<ProviderVerificationResult>;
|
|
40
|
+
checkVerificationStatus(providerSenderId: string): Promise<ProviderVerificationResult>;
|
|
41
|
+
getDnsRequirements(providerSenderId: string): Promise<DNSRecord[]>;
|
|
42
|
+
getVerifiedSenders(): Promise<ProviderSender[]>;
|
|
43
|
+
validateSender(email: string): Promise<ProviderValidationResult>;
|
|
44
|
+
syncSender(sender: SenderConfiguration): Promise<SyncResult>;
|
|
45
|
+
getCapabilities(): string[];
|
|
46
|
+
private buildDkimDnsRecords;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=sender-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sender-manager.d.ts","sourceRoot":"","sources":["../../../src/providers/ses/sender-manager.ts"],"names":[],"mappings":"AAQA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EACV,yBAAyB,EACzB,yBAAyB,EACzB,oBAAoB,EACpB,oBAAoB,EACpB,0BAA0B,EAE1B,wBAAwB,EAGxB,SAAS,EACT,wBAAwB,EACxB,cAAc,EACd,mBAAmB,EACnB,UAAU,EACX,MAAM,kCAAkC,CAAC;AAE1C,+DAA+D;AAC/D,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1C;AAkHD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAiB;IAC3C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqC;gBAEhD,SAAS,EAAE,cAAc,EAAE,MAAM,CAAC,EAAE,sBAAsB;IAShE,YAAY,CAAC,KAAK,EAAE,yBAAyB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IA8D7E,YAAY,CAAC,KAAK,EAAE,yBAAyB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAmE7E,YAAY,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAqC3E,mBAAmB,IAAI,wBAAwB;IAIzC,oBAAoB,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,0BAA0B,CAAC;IAMnF,uBAAuB,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,0BAA0B,CAAC;IAwDtF,kBAAkB,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAyBlE,kBAAkB,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAmD/C,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAgDhE,UAAU,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,UAAU,CAAC;IA6ClE,eAAe,IAAI,MAAM,EAAE;IAQ3B,OAAO,CAAC,mBAAmB;CAQ5B"}
|
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
Copyright (c) 2025 Bernier LLC
|
|
4
|
+
|
|
5
|
+
This file is licensed to the client under a limited-use license.
|
|
6
|
+
The client may use and modify this code *only within the scope of the project it was delivered for*.
|
|
7
|
+
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.SesSenderManager = void 0;
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Internal helpers for building SES v2 command objects without importing
|
|
13
|
+
// the actual AWS SDK at compile time. The real SDK is only required at
|
|
14
|
+
// runtime by the existing SES provider (ses.ts) which dynamically
|
|
15
|
+
// `require`s it. We mirror that approach: the caller hands us an
|
|
16
|
+
// already-initialised client and we construct plain command objects that
|
|
17
|
+
// the SDK client can dispatch.
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
function createEmailIdentityCommand(params) {
|
|
20
|
+
return { input: params, __brand: 'CreateEmailIdentity' };
|
|
21
|
+
}
|
|
22
|
+
function deleteEmailIdentityCommand(params) {
|
|
23
|
+
return { input: params, __brand: 'DeleteEmailIdentity' };
|
|
24
|
+
}
|
|
25
|
+
function getEmailIdentityCommand(params) {
|
|
26
|
+
return { input: params, __brand: 'GetEmailIdentity' };
|
|
27
|
+
}
|
|
28
|
+
function listEmailIdentitiesCommand(params) {
|
|
29
|
+
return { input: params, __brand: 'ListEmailIdentities' };
|
|
30
|
+
}
|
|
31
|
+
function putConfigSetAttributesCommand(params) {
|
|
32
|
+
return { input: params, __brand: 'PutEmailIdentityConfigurationSetAttributes' };
|
|
33
|
+
}
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// Status mapping
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
function mapSesVerificationStatus(sesStatus) {
|
|
38
|
+
switch (sesStatus?.toUpperCase()) {
|
|
39
|
+
case 'SUCCESS':
|
|
40
|
+
return 'verified';
|
|
41
|
+
case 'PENDING':
|
|
42
|
+
return 'pending';
|
|
43
|
+
case 'FAILED':
|
|
44
|
+
return 'failed';
|
|
45
|
+
case 'TEMPORARY_FAILURE':
|
|
46
|
+
return 'pending';
|
|
47
|
+
case 'NOT_STARTED':
|
|
48
|
+
return 'not_started';
|
|
49
|
+
default:
|
|
50
|
+
return 'not_started';
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function extractDomain(email) {
|
|
54
|
+
const atIndex = email.indexOf('@');
|
|
55
|
+
if (atIndex === -1) {
|
|
56
|
+
return email; // Assume the string is already a domain
|
|
57
|
+
}
|
|
58
|
+
return email.substring(atIndex + 1).toLowerCase();
|
|
59
|
+
}
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
// Error helper
|
|
62
|
+
// ---------------------------------------------------------------------------
|
|
63
|
+
function buildProviderError(code, message, cause, field) {
|
|
64
|
+
return {
|
|
65
|
+
code,
|
|
66
|
+
message,
|
|
67
|
+
...(field !== undefined ? { field } : {}),
|
|
68
|
+
...(cause !== undefined ? { cause } : {}),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function mapSesErrorCode(error) {
|
|
72
|
+
const err = error;
|
|
73
|
+
const name = err.name ?? err.code ?? err.Code ?? '';
|
|
74
|
+
switch (name) {
|
|
75
|
+
case 'AlreadyExistsException':
|
|
76
|
+
return 'SENDER_ALREADY_EXISTS';
|
|
77
|
+
case 'NotFoundException':
|
|
78
|
+
return 'SENDER_NOT_FOUND';
|
|
79
|
+
case 'TooManyRequestsException':
|
|
80
|
+
case 'LimitExceededException':
|
|
81
|
+
return 'RATE_LIMITED';
|
|
82
|
+
case 'BadRequestException':
|
|
83
|
+
case 'ValidationException':
|
|
84
|
+
return 'INVALID_EMAIL';
|
|
85
|
+
case 'UnauthorizedException':
|
|
86
|
+
case 'AccessDeniedException':
|
|
87
|
+
return 'AUTHENTICATION_FAILED';
|
|
88
|
+
default:
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
const statusCode = err.$metadata?.httpStatusCode;
|
|
92
|
+
if (statusCode === 429)
|
|
93
|
+
return 'RATE_LIMITED';
|
|
94
|
+
if (statusCode === 401 || statusCode === 403)
|
|
95
|
+
return 'AUTHENTICATION_FAILED';
|
|
96
|
+
return 'PROVIDER_ERROR';
|
|
97
|
+
}
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
// SesSenderManager
|
|
100
|
+
// ---------------------------------------------------------------------------
|
|
101
|
+
class SesSenderManager {
|
|
102
|
+
constructor(sesClient, logger) {
|
|
103
|
+
this.sesClient = sesClient;
|
|
104
|
+
this.logger = logger;
|
|
105
|
+
}
|
|
106
|
+
// ------------------------------------------------------------------
|
|
107
|
+
// Create
|
|
108
|
+
// ------------------------------------------------------------------
|
|
109
|
+
async createSender(input) {
|
|
110
|
+
if (!input.fromEmail) {
|
|
111
|
+
return {
|
|
112
|
+
success: false,
|
|
113
|
+
providerSenderId: '',
|
|
114
|
+
email: '',
|
|
115
|
+
verificationStatus: 'not_started',
|
|
116
|
+
error: buildProviderError('MISSING_REQUIRED_FIELD', 'fromEmail is required', undefined, 'fromEmail'),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
const domain = extractDomain(input.fromEmail);
|
|
120
|
+
const identity = domain; // SES operates on domain identities
|
|
121
|
+
try {
|
|
122
|
+
const command = createEmailIdentityCommand({ EmailIdentity: identity });
|
|
123
|
+
const response = await this.sesClient.send(command);
|
|
124
|
+
const dkimTokens = response.DkimAttributes?.Tokens ?? [];
|
|
125
|
+
const dkimStatus = response.DkimAttributes?.Status ?? 'PENDING';
|
|
126
|
+
this.logger?.info(`Created SES identity for domain ${identity}`);
|
|
127
|
+
return {
|
|
128
|
+
success: true,
|
|
129
|
+
providerSenderId: identity,
|
|
130
|
+
email: input.fromEmail,
|
|
131
|
+
verificationStatus: mapSesVerificationStatus(dkimStatus),
|
|
132
|
+
metadata: {
|
|
133
|
+
domain: identity,
|
|
134
|
+
dkimTokens,
|
|
135
|
+
dkimSigningEnabled: response.DkimAttributes?.SigningEnabled ?? false,
|
|
136
|
+
verifiedForSending: response.VerifiedForSendingStatus ?? false,
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
const errCode = mapSesErrorCode(error);
|
|
142
|
+
const message = error instanceof Error ? error.message : 'Unknown SES error';
|
|
143
|
+
this.logger?.warn(`Failed to create SES identity for ${identity}: ${message}`);
|
|
144
|
+
return {
|
|
145
|
+
success: false,
|
|
146
|
+
providerSenderId: identity,
|
|
147
|
+
email: input.fromEmail,
|
|
148
|
+
verificationStatus: 'not_started',
|
|
149
|
+
error: buildProviderError(errCode, message, error instanceof Error ? error : undefined),
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// ------------------------------------------------------------------
|
|
154
|
+
// Update
|
|
155
|
+
// ------------------------------------------------------------------
|
|
156
|
+
async updateSender(input) {
|
|
157
|
+
if (!input.providerSenderId) {
|
|
158
|
+
return {
|
|
159
|
+
success: false,
|
|
160
|
+
providerSenderId: '',
|
|
161
|
+
email: '',
|
|
162
|
+
verificationStatus: 'not_started',
|
|
163
|
+
error: buildProviderError('MISSING_REQUIRED_FIELD', 'providerSenderId is required', undefined, 'providerSenderId'),
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
// SES only supports updating the configuration set association
|
|
167
|
+
const configurationSet = input.providerFields?.['configurationSet'];
|
|
168
|
+
if (!configurationSet) {
|
|
169
|
+
// SES does not support updating fromName, replyTo, etc. on identities
|
|
170
|
+
return {
|
|
171
|
+
success: false,
|
|
172
|
+
providerSenderId: input.providerSenderId,
|
|
173
|
+
email: input.providerSenderId,
|
|
174
|
+
verificationStatus: 'not_started',
|
|
175
|
+
error: buildProviderError('UNSUPPORTED_OPERATION', 'SES does not support updating sender identity fields. Only configurationSet can be changed via providerFields.'),
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
try {
|
|
179
|
+
const command = putConfigSetAttributesCommand({
|
|
180
|
+
EmailIdentity: input.providerSenderId,
|
|
181
|
+
ConfigurationSetName: configurationSet,
|
|
182
|
+
});
|
|
183
|
+
await this.sesClient.send(command);
|
|
184
|
+
this.logger?.info(`Updated configuration set for ${input.providerSenderId} to ${configurationSet}`);
|
|
185
|
+
// Fetch current status after update
|
|
186
|
+
const status = await this.checkVerificationStatus(input.providerSenderId);
|
|
187
|
+
return {
|
|
188
|
+
success: true,
|
|
189
|
+
providerSenderId: input.providerSenderId,
|
|
190
|
+
email: input.providerSenderId,
|
|
191
|
+
verificationStatus: status.status,
|
|
192
|
+
metadata: {
|
|
193
|
+
configurationSet,
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
catch (error) {
|
|
198
|
+
const errCode = mapSesErrorCode(error);
|
|
199
|
+
const message = error instanceof Error ? error.message : 'Unknown SES error';
|
|
200
|
+
return {
|
|
201
|
+
success: false,
|
|
202
|
+
providerSenderId: input.providerSenderId,
|
|
203
|
+
email: input.providerSenderId,
|
|
204
|
+
verificationStatus: 'not_started',
|
|
205
|
+
error: buildProviderError(errCode, message, error instanceof Error ? error : undefined),
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
// ------------------------------------------------------------------
|
|
210
|
+
// Delete
|
|
211
|
+
// ------------------------------------------------------------------
|
|
212
|
+
async deleteSender(providerSenderId) {
|
|
213
|
+
if (!providerSenderId) {
|
|
214
|
+
return {
|
|
215
|
+
success: false,
|
|
216
|
+
providerSenderId: '',
|
|
217
|
+
error: buildProviderError('MISSING_REQUIRED_FIELD', 'providerSenderId is required', undefined, 'providerSenderId'),
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
try {
|
|
221
|
+
const command = deleteEmailIdentityCommand({ EmailIdentity: providerSenderId });
|
|
222
|
+
await this.sesClient.send(command);
|
|
223
|
+
this.logger?.info(`Deleted SES identity ${providerSenderId}`);
|
|
224
|
+
return {
|
|
225
|
+
success: true,
|
|
226
|
+
providerSenderId,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
catch (error) {
|
|
230
|
+
const errCode = mapSesErrorCode(error);
|
|
231
|
+
const message = error instanceof Error ? error.message : 'Unknown SES error';
|
|
232
|
+
this.logger?.warn(`Failed to delete SES identity ${providerSenderId}: ${message}`);
|
|
233
|
+
return {
|
|
234
|
+
success: false,
|
|
235
|
+
providerSenderId,
|
|
236
|
+
error: buildProviderError(errCode, message, error instanceof Error ? error : undefined),
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
// ------------------------------------------------------------------
|
|
241
|
+
// Verification
|
|
242
|
+
// ------------------------------------------------------------------
|
|
243
|
+
getVerificationType() {
|
|
244
|
+
return 'domain';
|
|
245
|
+
}
|
|
246
|
+
async initiateVerification(providerSenderId) {
|
|
247
|
+
// SES auto-initiates verification when the identity is created.
|
|
248
|
+
// We simply fetch the current status and return it.
|
|
249
|
+
return this.checkVerificationStatus(providerSenderId);
|
|
250
|
+
}
|
|
251
|
+
async checkVerificationStatus(providerSenderId) {
|
|
252
|
+
if (!providerSenderId) {
|
|
253
|
+
return {
|
|
254
|
+
success: false,
|
|
255
|
+
providerSenderId: '',
|
|
256
|
+
status: 'not_started',
|
|
257
|
+
verificationType: 'domain',
|
|
258
|
+
error: buildProviderError('MISSING_REQUIRED_FIELD', 'providerSenderId is required', undefined, 'providerSenderId'),
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
try {
|
|
262
|
+
const command = getEmailIdentityCommand({ EmailIdentity: providerSenderId });
|
|
263
|
+
const response = await this.sesClient.send(command);
|
|
264
|
+
const dkimStatus = response.DkimAttributes?.Status ?? 'NOT_STARTED';
|
|
265
|
+
const verificationStatus = mapSesVerificationStatus(dkimStatus);
|
|
266
|
+
const dkimTokens = response.DkimAttributes?.Tokens ?? [];
|
|
267
|
+
const dnsRecords = this.buildDkimDnsRecords(dkimTokens, providerSenderId);
|
|
268
|
+
this.logger?.debug(`Verification status for ${providerSenderId}: ${verificationStatus}`);
|
|
269
|
+
return {
|
|
270
|
+
success: true,
|
|
271
|
+
providerSenderId,
|
|
272
|
+
status: verificationStatus,
|
|
273
|
+
verificationType: 'domain',
|
|
274
|
+
dnsRecords,
|
|
275
|
+
message: verificationStatus === 'verified'
|
|
276
|
+
? `Domain ${providerSenderId} is verified for sending.`
|
|
277
|
+
: `Domain ${providerSenderId} verification is ${verificationStatus}. Add the DKIM CNAME records to your DNS.`,
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
catch (error) {
|
|
281
|
+
const errCode = mapSesErrorCode(error);
|
|
282
|
+
const message = error instanceof Error ? error.message : 'Unknown SES error';
|
|
283
|
+
return {
|
|
284
|
+
success: false,
|
|
285
|
+
providerSenderId,
|
|
286
|
+
status: 'not_started',
|
|
287
|
+
verificationType: 'domain',
|
|
288
|
+
error: buildProviderError(errCode, message, error instanceof Error ? error : undefined),
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
async getDnsRequirements(providerSenderId) {
|
|
293
|
+
if (!providerSenderId) {
|
|
294
|
+
return [];
|
|
295
|
+
}
|
|
296
|
+
try {
|
|
297
|
+
const command = getEmailIdentityCommand({ EmailIdentity: providerSenderId });
|
|
298
|
+
const response = await this.sesClient.send(command);
|
|
299
|
+
const dkimTokens = response.DkimAttributes?.Tokens ?? [];
|
|
300
|
+
return this.buildDkimDnsRecords(dkimTokens, providerSenderId);
|
|
301
|
+
}
|
|
302
|
+
catch (_error) {
|
|
303
|
+
this.logger?.warn(`Failed to fetch DNS requirements for ${providerSenderId}`);
|
|
304
|
+
return [];
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
// ------------------------------------------------------------------
|
|
308
|
+
// Listing & validation
|
|
309
|
+
// ------------------------------------------------------------------
|
|
310
|
+
async getVerifiedSenders() {
|
|
311
|
+
try {
|
|
312
|
+
const senders = [];
|
|
313
|
+
let nextToken;
|
|
314
|
+
do {
|
|
315
|
+
const command = listEmailIdentitiesCommand({
|
|
316
|
+
PageSize: 100,
|
|
317
|
+
...(nextToken !== undefined ? { NextToken: nextToken } : {}),
|
|
318
|
+
});
|
|
319
|
+
const response = await this.sesClient.send(command);
|
|
320
|
+
for (const identity of response.EmailIdentities ?? []) {
|
|
321
|
+
const name = identity.IdentityName ?? '';
|
|
322
|
+
const isVerified = identity.SendingEnabled ?? false;
|
|
323
|
+
const identityType = identity.IdentityType ?? 'UNKNOWN';
|
|
324
|
+
senders.push({
|
|
325
|
+
id: name,
|
|
326
|
+
email: name,
|
|
327
|
+
name: name,
|
|
328
|
+
isVerified,
|
|
329
|
+
verificationStatus: isVerified ? 'verified' : 'pending',
|
|
330
|
+
domain: identityType === 'DOMAIN' ? name : extractDomain(name),
|
|
331
|
+
metadata: {
|
|
332
|
+
identityType,
|
|
333
|
+
sendingEnabled: isVerified,
|
|
334
|
+
},
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
nextToken = response.NextToken;
|
|
338
|
+
} while (nextToken);
|
|
339
|
+
this.logger?.info(`Fetched ${senders.length} SES identities`);
|
|
340
|
+
return senders;
|
|
341
|
+
}
|
|
342
|
+
catch (error) {
|
|
343
|
+
const message = error instanceof Error ? error.message : 'Unknown SES error';
|
|
344
|
+
this.logger?.warn(`Failed to list SES identities: ${message}`);
|
|
345
|
+
throw error;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
async validateSender(email) {
|
|
349
|
+
const domain = extractDomain(email);
|
|
350
|
+
try {
|
|
351
|
+
const command = getEmailIdentityCommand({ EmailIdentity: domain });
|
|
352
|
+
const response = await this.sesClient.send(command);
|
|
353
|
+
const isVerified = response.VerifiedForSendingStatus ?? false;
|
|
354
|
+
const dkimStatus = response.DkimAttributes?.Status ?? 'NOT_STARTED';
|
|
355
|
+
return {
|
|
356
|
+
isVerified,
|
|
357
|
+
verificationStatus: mapSesVerificationStatus(dkimStatus),
|
|
358
|
+
lastChecked: new Date(),
|
|
359
|
+
metadata: {
|
|
360
|
+
domain,
|
|
361
|
+
identityType: response.IdentityType,
|
|
362
|
+
dkimSigningEnabled: response.DkimAttributes?.SigningEnabled ?? false,
|
|
363
|
+
dkimTokens: response.DkimAttributes?.Tokens ?? [],
|
|
364
|
+
},
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
catch (error) {
|
|
368
|
+
// If the identity doesn't exist, the sender is not verified
|
|
369
|
+
const err = error;
|
|
370
|
+
if (err.name === 'NotFoundException') {
|
|
371
|
+
return {
|
|
372
|
+
isVerified: false,
|
|
373
|
+
verificationStatus: 'not_started',
|
|
374
|
+
lastChecked: new Date(),
|
|
375
|
+
metadata: {
|
|
376
|
+
domain,
|
|
377
|
+
error: 'Identity not found in SES',
|
|
378
|
+
},
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
throw error;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
async syncSender(sender) {
|
|
385
|
+
const domain = extractDomain(sender.fromEmail);
|
|
386
|
+
try {
|
|
387
|
+
const command = getEmailIdentityCommand({ EmailIdentity: domain });
|
|
388
|
+
const response = await this.sesClient.send(command);
|
|
389
|
+
const isVerified = response.VerifiedForSendingStatus ?? false;
|
|
390
|
+
const dkimStatus = response.DkimAttributes?.Status ?? 'NOT_STARTED';
|
|
391
|
+
return {
|
|
392
|
+
success: true,
|
|
393
|
+
senderId: sender.id,
|
|
394
|
+
synced: true,
|
|
395
|
+
message: `SES identity ${domain} is ${isVerified ? 'verified' : 'not verified'} (DKIM: ${dkimStatus})`,
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
catch (error) {
|
|
399
|
+
const err = error;
|
|
400
|
+
if (err.name === 'NotFoundException') {
|
|
401
|
+
return {
|
|
402
|
+
success: true,
|
|
403
|
+
senderId: sender.id,
|
|
404
|
+
synced: false,
|
|
405
|
+
message: `SES identity ${domain} does not exist. Create it to begin verification.`,
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
const message = error instanceof Error ? error.message : 'Unknown SES error';
|
|
409
|
+
return {
|
|
410
|
+
success: false,
|
|
411
|
+
senderId: sender.id,
|
|
412
|
+
synced: false,
|
|
413
|
+
message: `Failed to sync SES identity ${domain}: ${message}`,
|
|
414
|
+
error: message,
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
// ------------------------------------------------------------------
|
|
419
|
+
// Capabilities
|
|
420
|
+
// ------------------------------------------------------------------
|
|
421
|
+
getCapabilities() {
|
|
422
|
+
return ['send', 'domain_verification', 'dkim'];
|
|
423
|
+
}
|
|
424
|
+
// ------------------------------------------------------------------
|
|
425
|
+
// Private helpers
|
|
426
|
+
// ------------------------------------------------------------------
|
|
427
|
+
buildDkimDnsRecords(tokens, _domain) {
|
|
428
|
+
return tokens.map(token => ({
|
|
429
|
+
type: 'CNAME',
|
|
430
|
+
host: `${token}._domainkey`,
|
|
431
|
+
value: `${token}.dkim.amazonses.com`,
|
|
432
|
+
ttl: 1800,
|
|
433
|
+
}));
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
exports.SesSenderManager = SesSenderManager;
|
|
437
|
+
//# sourceMappingURL=sender-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sender-manager.js","sourceRoot":"","sources":["../../../src/providers/ses/sender-manager.ts"],"names":[],"mappings":"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"}
|
package/dist/providers/ses.d.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { EmailProvider } from './base';
|
|
6
6
|
import type { EmailMessage, SendResult, EmailProviderConfig, EmailProviderCapabilities, EmailValidationResult, EmailTemplate, DeliveryStatus, WebhookEvent } from '../types';
|
|
7
|
+
import { SesSenderManager } from './ses/sender-manager';
|
|
7
8
|
interface SesConfig extends EmailProviderConfig {
|
|
8
9
|
provider: 'ses';
|
|
9
10
|
apiKey: string;
|
|
@@ -14,7 +15,29 @@ interface SesConfig extends EmailProviderConfig {
|
|
|
14
15
|
}
|
|
15
16
|
export declare class SesProvider extends EmailProvider {
|
|
16
17
|
private sesClient;
|
|
18
|
+
private senderManager?;
|
|
17
19
|
constructor(config: SesConfig);
|
|
20
|
+
/**
|
|
21
|
+
* Get the SES sender manager for identity lifecycle operations.
|
|
22
|
+
*
|
|
23
|
+
* The sender manager wraps the SES v2 API for creating, verifying,
|
|
24
|
+
* and deleting email/domain identities.
|
|
25
|
+
*
|
|
26
|
+
* NOTE: The sender manager requires an SES **v2** client
|
|
27
|
+
* (`@aws-sdk/client-sesv2`), while the existing provider uses the
|
|
28
|
+
* v1 SDK (`aws-sdk`). If you need sender management, pass a v2
|
|
29
|
+
* client via `setSesV2Client()` before calling this method, or
|
|
30
|
+
* construct a `SesSenderManager` directly.
|
|
31
|
+
*/
|
|
32
|
+
getSenderManager(): SesSenderManager;
|
|
33
|
+
/**
|
|
34
|
+
* Provide an SES v2 client for the sender manager.
|
|
35
|
+
*
|
|
36
|
+
* @param sesV2Client An initialised `SESv2Client` from `@aws-sdk/client-sesv2`
|
|
37
|
+
*/
|
|
38
|
+
setSesV2Client(sesV2Client: {
|
|
39
|
+
send(command: unknown): Promise<unknown>;
|
|
40
|
+
}): void;
|
|
18
41
|
private initializeClient;
|
|
19
42
|
sendEmail(message: EmailMessage): Promise<SendResult>;
|
|
20
43
|
sendBatch(emails: EmailMessage[]): Promise<SendResult[]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ses.d.ts","sourceRoot":"","sources":["../../src/providers/ses.ts"],"names":[],"mappings":"AAQA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,KAAK,EACV,YAAY,EACZ,UAAU,EACV,mBAAmB,EACnB,yBAAyB,EACzB,qBAAqB,EACrB,aAAa,EACb,cAAc,EACd,YAAY,EAEb,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"ses.d.ts","sourceRoot":"","sources":["../../src/providers/ses.ts"],"names":[],"mappings":"AAQA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,KAAK,EACV,YAAY,EACZ,UAAU,EACV,mBAAmB,EACnB,yBAAyB,EACzB,qBAAqB,EACrB,aAAa,EACb,cAAc,EACd,YAAY,EAEb,MAAM,UAAU,CAAC;AAElB,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAExD,UAAU,SAAU,SAAQ,mBAAmB;IAC7C,QAAQ,EAAE,KAAK,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAkCD,qBAAa,WAAY,SAAQ,aAAa;IAC5C,OAAO,CAAC,SAAS,CAAM;IACvB,OAAO,CAAC,aAAa,CAAC,CAAmB;gBAE7B,MAAM,EAAE,SAAS;IAK7B;;;;;;;;;;;OAWG;IACH,gBAAgB,IAAI,gBAAgB;IAUpC;;;;OAIG;IACH,cAAc,CAAC,WAAW,EAAE;QAAE,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;KAAE,GAAG,IAAI;IAI/E,OAAO,CAAC,gBAAgB;IAkBlB,SAAS,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,UAAU,CAAC;IAmCrD,SAAS,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;YA2BhD,cAAc;IAyCb,iBAAiB,CAC9B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC7B,OAAO,CAAC,UAAU,CAAC;IAuCP,cAAc,CAAC,QAAQ,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,GAAG,WAAW,GAAG,WAAW,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IAkBzG,cAAc,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBtD,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYjD,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IA2B9D,aAAa,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;IAkBhC,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAiBpE,cAAc,CAAC,QAAQ,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAM1E,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;IAUxC,qBAAqB,IAAI,qBAAqB;IA+B9C,oBAAoB,CAAC,OAAO,EAAE,YAAY,GAAG,qBAAqB;IA6BlE,eAAe,IAAI,yBAAyB;IA4BrD,OAAO,CAAC,mBAAmB;IAkD3B,OAAO,CAAC,cAAc;CAsBvB"}
|
package/dist/providers/ses.js
CHANGED
|
@@ -14,11 +14,41 @@ exports.SesProvider = void 0;
|
|
|
14
14
|
*/
|
|
15
15
|
const base_1 = require("./base");
|
|
16
16
|
const types_1 = require("../types");
|
|
17
|
+
const sender_manager_1 = require("./ses/sender-manager");
|
|
17
18
|
class SesProvider extends base_1.EmailProvider {
|
|
18
19
|
constructor(config) {
|
|
19
20
|
super(config);
|
|
20
21
|
this.initializeClient();
|
|
21
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Get the SES sender manager for identity lifecycle operations.
|
|
25
|
+
*
|
|
26
|
+
* The sender manager wraps the SES v2 API for creating, verifying,
|
|
27
|
+
* and deleting email/domain identities.
|
|
28
|
+
*
|
|
29
|
+
* NOTE: The sender manager requires an SES **v2** client
|
|
30
|
+
* (`@aws-sdk/client-sesv2`), while the existing provider uses the
|
|
31
|
+
* v1 SDK (`aws-sdk`). If you need sender management, pass a v2
|
|
32
|
+
* client via `setSesV2Client()` before calling this method, or
|
|
33
|
+
* construct a `SesSenderManager` directly.
|
|
34
|
+
*/
|
|
35
|
+
getSenderManager() {
|
|
36
|
+
if (!this.senderManager) {
|
|
37
|
+
// Attempt to use the existing v1 client as a fallback.
|
|
38
|
+
// The v1 client does not have a `.send()` method with the v2
|
|
39
|
+
// command pattern, so this is best-effort.
|
|
40
|
+
this.senderManager = new sender_manager_1.SesSenderManager(this.sesClient);
|
|
41
|
+
}
|
|
42
|
+
return this.senderManager;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Provide an SES v2 client for the sender manager.
|
|
46
|
+
*
|
|
47
|
+
* @param sesV2Client An initialised `SESv2Client` from `@aws-sdk/client-sesv2`
|
|
48
|
+
*/
|
|
49
|
+
setSesV2Client(sesV2Client) {
|
|
50
|
+
this.senderManager = new sender_manager_1.SesSenderManager(sesV2Client);
|
|
51
|
+
}
|
|
22
52
|
initializeClient() {
|
|
23
53
|
try {
|
|
24
54
|
// Dynamically import AWS SDK to avoid bundling issues
|