@parsrun/email 0.1.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/README.md +145 -0
- package/dist/index.d.ts +103 -0
- package/dist/index.js +1192 -0
- package/dist/index.js.map +1 -0
- package/dist/providers/console.d.ts +47 -0
- package/dist/providers/console.js +126 -0
- package/dist/providers/console.js.map +1 -0
- package/dist/providers/index.d.ts +6 -0
- package/dist/providers/index.js +621 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/postmark.d.ts +47 -0
- package/dist/providers/postmark.js +202 -0
- package/dist/providers/postmark.js.map +1 -0
- package/dist/providers/resend.d.ts +47 -0
- package/dist/providers/resend.js +174 -0
- package/dist/providers/resend.js.map +1 -0
- package/dist/providers/sendgrid.d.ts +47 -0
- package/dist/providers/sendgrid.js +193 -0
- package/dist/providers/sendgrid.js.map +1 -0
- package/dist/templates/index.d.ts +114 -0
- package/dist/templates/index.js +415 -0
- package/dist/templates/index.js.map +1 -0
- package/dist/types.d.ts +186 -0
- package/dist/types.js +50 -0
- package/dist/types.js.map +1 -0
- package/package.json +80 -0
|
@@ -0,0 +1,621 @@
|
|
|
1
|
+
// src/types.ts
|
|
2
|
+
import {
|
|
3
|
+
type,
|
|
4
|
+
emailAddress,
|
|
5
|
+
emailAttachment,
|
|
6
|
+
sendEmailOptions,
|
|
7
|
+
sendTemplateEmailOptions,
|
|
8
|
+
emailSendResult,
|
|
9
|
+
smtpConfig,
|
|
10
|
+
resendConfig,
|
|
11
|
+
sendgridConfig,
|
|
12
|
+
sesConfig,
|
|
13
|
+
postmarkConfig,
|
|
14
|
+
emailConfig
|
|
15
|
+
} from "@parsrun/types";
|
|
16
|
+
var EmailError = class extends Error {
|
|
17
|
+
constructor(message, code, cause) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.code = code;
|
|
20
|
+
this.cause = cause;
|
|
21
|
+
this.name = "EmailError";
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
var EmailErrorCodes = {
|
|
25
|
+
INVALID_CONFIG: "INVALID_CONFIG",
|
|
26
|
+
INVALID_RECIPIENT: "INVALID_RECIPIENT",
|
|
27
|
+
INVALID_CONTENT: "INVALID_CONTENT",
|
|
28
|
+
SEND_FAILED: "SEND_FAILED",
|
|
29
|
+
RATE_LIMITED: "RATE_LIMITED",
|
|
30
|
+
PROVIDER_ERROR: "PROVIDER_ERROR",
|
|
31
|
+
TEMPLATE_ERROR: "TEMPLATE_ERROR",
|
|
32
|
+
ATTACHMENT_ERROR: "ATTACHMENT_ERROR"
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// src/providers/resend.ts
|
|
36
|
+
var ResendProvider = class {
|
|
37
|
+
type = "resend";
|
|
38
|
+
apiKey;
|
|
39
|
+
fromEmail;
|
|
40
|
+
fromName;
|
|
41
|
+
baseUrl = "https://api.resend.com";
|
|
42
|
+
constructor(config) {
|
|
43
|
+
this.apiKey = config.apiKey;
|
|
44
|
+
this.fromEmail = config.fromEmail;
|
|
45
|
+
this.fromName = config.fromName;
|
|
46
|
+
}
|
|
47
|
+
formatAddress(address) {
|
|
48
|
+
if (typeof address === "string") {
|
|
49
|
+
return address;
|
|
50
|
+
}
|
|
51
|
+
if (address.name) {
|
|
52
|
+
return `${address.name} <${address.email}>`;
|
|
53
|
+
}
|
|
54
|
+
return address.email;
|
|
55
|
+
}
|
|
56
|
+
formatAddresses(addresses) {
|
|
57
|
+
if (Array.isArray(addresses)) {
|
|
58
|
+
return addresses.map((a) => this.formatAddress(a));
|
|
59
|
+
}
|
|
60
|
+
return [this.formatAddress(addresses)];
|
|
61
|
+
}
|
|
62
|
+
async send(options) {
|
|
63
|
+
const from = options.from ? this.formatAddress(options.from) : this.fromName ? `${this.fromName} <${this.fromEmail}>` : this.fromEmail;
|
|
64
|
+
const payload = {
|
|
65
|
+
from,
|
|
66
|
+
to: this.formatAddresses(options.to),
|
|
67
|
+
subject: options.subject
|
|
68
|
+
};
|
|
69
|
+
if (options.html) payload["html"] = options.html;
|
|
70
|
+
if (options.text) payload["text"] = options.text;
|
|
71
|
+
if (options.replyTo) payload["reply_to"] = this.formatAddress(options.replyTo);
|
|
72
|
+
if (options.cc) payload["cc"] = this.formatAddresses(options.cc);
|
|
73
|
+
if (options.bcc) payload["bcc"] = this.formatAddresses(options.bcc);
|
|
74
|
+
if (options.headers) payload["headers"] = options.headers;
|
|
75
|
+
if (options.tags) payload["tags"] = Object.entries(options.tags).map(([name, value]) => ({ name, value }));
|
|
76
|
+
if (options.scheduledAt) payload["scheduled_at"] = options.scheduledAt.toISOString();
|
|
77
|
+
if (options.attachments && options.attachments.length > 0) {
|
|
78
|
+
payload["attachments"] = options.attachments.map((att) => ({
|
|
79
|
+
filename: att.filename,
|
|
80
|
+
content: typeof att.content === "string" ? att.content : this.uint8ArrayToBase64(att.content),
|
|
81
|
+
content_type: att.contentType
|
|
82
|
+
}));
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
const response = await fetch(`${this.baseUrl}/emails`, {
|
|
86
|
+
method: "POST",
|
|
87
|
+
headers: {
|
|
88
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
89
|
+
"Content-Type": "application/json"
|
|
90
|
+
},
|
|
91
|
+
body: JSON.stringify(payload)
|
|
92
|
+
});
|
|
93
|
+
const data = await response.json();
|
|
94
|
+
if (!response.ok) {
|
|
95
|
+
return {
|
|
96
|
+
success: false,
|
|
97
|
+
error: data.message || `HTTP ${response.status}`,
|
|
98
|
+
data
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
success: true,
|
|
103
|
+
messageId: data.id,
|
|
104
|
+
data
|
|
105
|
+
};
|
|
106
|
+
} catch (err) {
|
|
107
|
+
throw new EmailError(
|
|
108
|
+
`Resend send failed: ${err instanceof Error ? err.message : "Unknown error"}`,
|
|
109
|
+
EmailErrorCodes.SEND_FAILED,
|
|
110
|
+
err
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
async sendBatch(options) {
|
|
115
|
+
const results = [];
|
|
116
|
+
let successful = 0;
|
|
117
|
+
let failed = 0;
|
|
118
|
+
for (const email of options.emails) {
|
|
119
|
+
try {
|
|
120
|
+
const result = await this.send(email);
|
|
121
|
+
results.push(result);
|
|
122
|
+
if (result.success) {
|
|
123
|
+
successful++;
|
|
124
|
+
} else {
|
|
125
|
+
failed++;
|
|
126
|
+
if (options.stopOnError) break;
|
|
127
|
+
}
|
|
128
|
+
} catch (err) {
|
|
129
|
+
failed++;
|
|
130
|
+
results.push({
|
|
131
|
+
success: false,
|
|
132
|
+
error: err instanceof Error ? err.message : "Unknown error"
|
|
133
|
+
});
|
|
134
|
+
if (options.stopOnError) break;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
total: options.emails.length,
|
|
139
|
+
successful,
|
|
140
|
+
failed,
|
|
141
|
+
results
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
async verify() {
|
|
145
|
+
try {
|
|
146
|
+
const response = await fetch(`${this.baseUrl}/domains`, {
|
|
147
|
+
headers: {
|
|
148
|
+
"Authorization": `Bearer ${this.apiKey}`
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
return response.ok;
|
|
152
|
+
} catch {
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
uint8ArrayToBase64(data) {
|
|
157
|
+
let binary = "";
|
|
158
|
+
for (let i = 0; i < data.length; i++) {
|
|
159
|
+
const byte = data[i];
|
|
160
|
+
if (byte !== void 0) {
|
|
161
|
+
binary += String.fromCharCode(byte);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return btoa(binary);
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
function createResendProvider(config) {
|
|
168
|
+
return new ResendProvider(config);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// src/providers/sendgrid.ts
|
|
172
|
+
var SendGridProvider = class {
|
|
173
|
+
type = "sendgrid";
|
|
174
|
+
apiKey;
|
|
175
|
+
fromEmail;
|
|
176
|
+
fromName;
|
|
177
|
+
baseUrl = "https://api.sendgrid.com/v3";
|
|
178
|
+
constructor(config) {
|
|
179
|
+
this.apiKey = config.apiKey;
|
|
180
|
+
this.fromEmail = config.fromEmail;
|
|
181
|
+
this.fromName = config.fromName;
|
|
182
|
+
}
|
|
183
|
+
formatAddress(address) {
|
|
184
|
+
if (typeof address === "string") {
|
|
185
|
+
return { email: address };
|
|
186
|
+
}
|
|
187
|
+
return address.name ? { email: address.email, name: address.name } : { email: address.email };
|
|
188
|
+
}
|
|
189
|
+
formatAddresses(addresses) {
|
|
190
|
+
if (Array.isArray(addresses)) {
|
|
191
|
+
return addresses.map((a) => this.formatAddress(a));
|
|
192
|
+
}
|
|
193
|
+
return [this.formatAddress(addresses)];
|
|
194
|
+
}
|
|
195
|
+
async send(options) {
|
|
196
|
+
const from = options.from ? this.formatAddress(options.from) : this.fromName ? { email: this.fromEmail, name: this.fromName } : { email: this.fromEmail };
|
|
197
|
+
const personalization = {
|
|
198
|
+
to: this.formatAddresses(options.to)
|
|
199
|
+
};
|
|
200
|
+
if (options.cc) {
|
|
201
|
+
personalization.cc = this.formatAddresses(options.cc);
|
|
202
|
+
}
|
|
203
|
+
if (options.bcc) {
|
|
204
|
+
personalization.bcc = this.formatAddresses(options.bcc);
|
|
205
|
+
}
|
|
206
|
+
if (options.headers) {
|
|
207
|
+
personalization.headers = options.headers;
|
|
208
|
+
}
|
|
209
|
+
const payload = {
|
|
210
|
+
personalizations: [personalization],
|
|
211
|
+
from,
|
|
212
|
+
subject: options.subject,
|
|
213
|
+
content: []
|
|
214
|
+
};
|
|
215
|
+
const content = [];
|
|
216
|
+
if (options.text) {
|
|
217
|
+
content.push({ type: "text/plain", value: options.text });
|
|
218
|
+
}
|
|
219
|
+
if (options.html) {
|
|
220
|
+
content.push({ type: "text/html", value: options.html });
|
|
221
|
+
}
|
|
222
|
+
payload["content"] = content;
|
|
223
|
+
if (options.replyTo) {
|
|
224
|
+
payload["reply_to"] = this.formatAddress(options.replyTo);
|
|
225
|
+
}
|
|
226
|
+
if (options.attachments && options.attachments.length > 0) {
|
|
227
|
+
payload["attachments"] = options.attachments.map((att) => ({
|
|
228
|
+
filename: att.filename,
|
|
229
|
+
content: typeof att.content === "string" ? att.content : this.uint8ArrayToBase64(att.content),
|
|
230
|
+
type: att.contentType,
|
|
231
|
+
content_id: att.contentId,
|
|
232
|
+
disposition: att.contentId ? "inline" : "attachment"
|
|
233
|
+
}));
|
|
234
|
+
}
|
|
235
|
+
if (options.scheduledAt) {
|
|
236
|
+
payload["send_at"] = Math.floor(options.scheduledAt.getTime() / 1e3);
|
|
237
|
+
}
|
|
238
|
+
try {
|
|
239
|
+
const response = await fetch(`${this.baseUrl}/mail/send`, {
|
|
240
|
+
method: "POST",
|
|
241
|
+
headers: {
|
|
242
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
243
|
+
"Content-Type": "application/json"
|
|
244
|
+
},
|
|
245
|
+
body: JSON.stringify(payload)
|
|
246
|
+
});
|
|
247
|
+
if (response.status === 202) {
|
|
248
|
+
const messageId = response.headers.get("x-message-id");
|
|
249
|
+
return {
|
|
250
|
+
success: true,
|
|
251
|
+
messageId: messageId ?? void 0
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
const data = await response.json().catch(() => ({}));
|
|
255
|
+
const errorMessage = data.errors?.[0]?.message || `HTTP ${response.status}`;
|
|
256
|
+
return {
|
|
257
|
+
success: false,
|
|
258
|
+
error: errorMessage,
|
|
259
|
+
data
|
|
260
|
+
};
|
|
261
|
+
} catch (err) {
|
|
262
|
+
throw new EmailError(
|
|
263
|
+
`SendGrid send failed: ${err instanceof Error ? err.message : "Unknown error"}`,
|
|
264
|
+
EmailErrorCodes.SEND_FAILED,
|
|
265
|
+
err
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
async sendBatch(options) {
|
|
270
|
+
const results = [];
|
|
271
|
+
let successful = 0;
|
|
272
|
+
let failed = 0;
|
|
273
|
+
for (const email of options.emails) {
|
|
274
|
+
try {
|
|
275
|
+
const result = await this.send(email);
|
|
276
|
+
results.push(result);
|
|
277
|
+
if (result.success) {
|
|
278
|
+
successful++;
|
|
279
|
+
} else {
|
|
280
|
+
failed++;
|
|
281
|
+
if (options.stopOnError) break;
|
|
282
|
+
}
|
|
283
|
+
} catch (err) {
|
|
284
|
+
failed++;
|
|
285
|
+
results.push({
|
|
286
|
+
success: false,
|
|
287
|
+
error: err instanceof Error ? err.message : "Unknown error"
|
|
288
|
+
});
|
|
289
|
+
if (options.stopOnError) break;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return {
|
|
293
|
+
total: options.emails.length,
|
|
294
|
+
successful,
|
|
295
|
+
failed,
|
|
296
|
+
results
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
async verify() {
|
|
300
|
+
try {
|
|
301
|
+
const response = await fetch(`${this.baseUrl}/scopes`, {
|
|
302
|
+
headers: {
|
|
303
|
+
"Authorization": `Bearer ${this.apiKey}`
|
|
304
|
+
}
|
|
305
|
+
});
|
|
306
|
+
return response.ok;
|
|
307
|
+
} catch {
|
|
308
|
+
return false;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
uint8ArrayToBase64(data) {
|
|
312
|
+
let binary = "";
|
|
313
|
+
for (let i = 0; i < data.length; i++) {
|
|
314
|
+
const byte = data[i];
|
|
315
|
+
if (byte !== void 0) {
|
|
316
|
+
binary += String.fromCharCode(byte);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return btoa(binary);
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
function createSendGridProvider(config) {
|
|
323
|
+
return new SendGridProvider(config);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// src/providers/postmark.ts
|
|
327
|
+
var PostmarkProvider = class {
|
|
328
|
+
type = "postmark";
|
|
329
|
+
apiKey;
|
|
330
|
+
fromEmail;
|
|
331
|
+
fromName;
|
|
332
|
+
baseUrl = "https://api.postmarkapp.com";
|
|
333
|
+
constructor(config) {
|
|
334
|
+
this.apiKey = config.apiKey;
|
|
335
|
+
this.fromEmail = config.fromEmail;
|
|
336
|
+
this.fromName = config.fromName;
|
|
337
|
+
}
|
|
338
|
+
formatAddress(address) {
|
|
339
|
+
if (typeof address === "string") {
|
|
340
|
+
return address;
|
|
341
|
+
}
|
|
342
|
+
if (address.name) {
|
|
343
|
+
return `${address.name} <${address.email}>`;
|
|
344
|
+
}
|
|
345
|
+
return address.email;
|
|
346
|
+
}
|
|
347
|
+
formatAddresses(addresses) {
|
|
348
|
+
if (Array.isArray(addresses)) {
|
|
349
|
+
return addresses.map((a) => this.formatAddress(a)).join(",");
|
|
350
|
+
}
|
|
351
|
+
return this.formatAddress(addresses);
|
|
352
|
+
}
|
|
353
|
+
async send(options) {
|
|
354
|
+
const from = options.from ? this.formatAddress(options.from) : this.fromName ? `${this.fromName} <${this.fromEmail}>` : this.fromEmail;
|
|
355
|
+
const payload = {
|
|
356
|
+
From: from,
|
|
357
|
+
To: this.formatAddresses(options.to),
|
|
358
|
+
Subject: options.subject
|
|
359
|
+
};
|
|
360
|
+
if (options.html) payload["HtmlBody"] = options.html;
|
|
361
|
+
if (options.text) payload["TextBody"] = options.text;
|
|
362
|
+
if (options.replyTo) payload["ReplyTo"] = this.formatAddress(options.replyTo);
|
|
363
|
+
if (options.cc) payload["Cc"] = this.formatAddresses(options.cc);
|
|
364
|
+
if (options.bcc) payload["Bcc"] = this.formatAddresses(options.bcc);
|
|
365
|
+
if (options.headers) {
|
|
366
|
+
payload["Headers"] = Object.entries(options.headers).map(([Name, Value]) => ({ Name, Value }));
|
|
367
|
+
}
|
|
368
|
+
if (options.tags) {
|
|
369
|
+
const tagEntries = Object.entries(options.tags);
|
|
370
|
+
if (tagEntries.length > 0 && tagEntries[0]) {
|
|
371
|
+
payload["Tag"] = tagEntries[0][1];
|
|
372
|
+
}
|
|
373
|
+
payload["Metadata"] = options.tags;
|
|
374
|
+
}
|
|
375
|
+
if (options.attachments && options.attachments.length > 0) {
|
|
376
|
+
payload["Attachments"] = options.attachments.map((att) => ({
|
|
377
|
+
Name: att.filename,
|
|
378
|
+
Content: typeof att.content === "string" ? att.content : this.uint8ArrayToBase64(att.content),
|
|
379
|
+
ContentType: att.contentType || "application/octet-stream",
|
|
380
|
+
ContentID: att.contentId
|
|
381
|
+
}));
|
|
382
|
+
}
|
|
383
|
+
try {
|
|
384
|
+
const response = await fetch(`${this.baseUrl}/email`, {
|
|
385
|
+
method: "POST",
|
|
386
|
+
headers: {
|
|
387
|
+
"X-Postmark-Server-Token": this.apiKey,
|
|
388
|
+
"Content-Type": "application/json",
|
|
389
|
+
"Accept": "application/json"
|
|
390
|
+
},
|
|
391
|
+
body: JSON.stringify(payload)
|
|
392
|
+
});
|
|
393
|
+
const data = await response.json();
|
|
394
|
+
if (!response.ok || data.ErrorCode) {
|
|
395
|
+
return {
|
|
396
|
+
success: false,
|
|
397
|
+
error: data.Message || `HTTP ${response.status}`,
|
|
398
|
+
data
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
return {
|
|
402
|
+
success: true,
|
|
403
|
+
messageId: data.MessageID,
|
|
404
|
+
data
|
|
405
|
+
};
|
|
406
|
+
} catch (err) {
|
|
407
|
+
throw new EmailError(
|
|
408
|
+
`Postmark send failed: ${err instanceof Error ? err.message : "Unknown error"}`,
|
|
409
|
+
EmailErrorCodes.SEND_FAILED,
|
|
410
|
+
err
|
|
411
|
+
);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
async sendBatch(options) {
|
|
415
|
+
const batchPayload = options.emails.map((email) => {
|
|
416
|
+
const from = email.from ? this.formatAddress(email.from) : this.fromName ? `${this.fromName} <${this.fromEmail}>` : this.fromEmail;
|
|
417
|
+
const item = {
|
|
418
|
+
From: from,
|
|
419
|
+
To: this.formatAddresses(email.to),
|
|
420
|
+
Subject: email.subject
|
|
421
|
+
};
|
|
422
|
+
if (email.html) item["HtmlBody"] = email.html;
|
|
423
|
+
if (email.text) item["TextBody"] = email.text;
|
|
424
|
+
if (email.replyTo) item["ReplyTo"] = this.formatAddress(email.replyTo);
|
|
425
|
+
if (email.cc) item["Cc"] = this.formatAddresses(email.cc);
|
|
426
|
+
if (email.bcc) item["Bcc"] = this.formatAddresses(email.bcc);
|
|
427
|
+
return item;
|
|
428
|
+
});
|
|
429
|
+
try {
|
|
430
|
+
const response = await fetch(`${this.baseUrl}/email/batch`, {
|
|
431
|
+
method: "POST",
|
|
432
|
+
headers: {
|
|
433
|
+
"X-Postmark-Server-Token": this.apiKey,
|
|
434
|
+
"Content-Type": "application/json",
|
|
435
|
+
"Accept": "application/json"
|
|
436
|
+
},
|
|
437
|
+
body: JSON.stringify(batchPayload)
|
|
438
|
+
});
|
|
439
|
+
const data = await response.json();
|
|
440
|
+
const results = data.map((item) => ({
|
|
441
|
+
success: !item.ErrorCode,
|
|
442
|
+
messageId: item.MessageID,
|
|
443
|
+
error: item.ErrorCode ? item.Message : void 0,
|
|
444
|
+
data: item
|
|
445
|
+
}));
|
|
446
|
+
const successful = results.filter((r) => r.success).length;
|
|
447
|
+
const failed = results.filter((r) => !r.success).length;
|
|
448
|
+
return {
|
|
449
|
+
total: options.emails.length,
|
|
450
|
+
successful,
|
|
451
|
+
failed,
|
|
452
|
+
results
|
|
453
|
+
};
|
|
454
|
+
} catch (err) {
|
|
455
|
+
throw new EmailError(
|
|
456
|
+
`Postmark batch send failed: ${err instanceof Error ? err.message : "Unknown error"}`,
|
|
457
|
+
EmailErrorCodes.SEND_FAILED,
|
|
458
|
+
err
|
|
459
|
+
);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
async verify() {
|
|
463
|
+
try {
|
|
464
|
+
const response = await fetch(`${this.baseUrl}/server`, {
|
|
465
|
+
headers: {
|
|
466
|
+
"X-Postmark-Server-Token": this.apiKey,
|
|
467
|
+
"Accept": "application/json"
|
|
468
|
+
}
|
|
469
|
+
});
|
|
470
|
+
return response.ok;
|
|
471
|
+
} catch {
|
|
472
|
+
return false;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
uint8ArrayToBase64(data) {
|
|
476
|
+
let binary = "";
|
|
477
|
+
for (let i = 0; i < data.length; i++) {
|
|
478
|
+
const byte = data[i];
|
|
479
|
+
if (byte !== void 0) {
|
|
480
|
+
binary += String.fromCharCode(byte);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
return btoa(binary);
|
|
484
|
+
}
|
|
485
|
+
};
|
|
486
|
+
function createPostmarkProvider(config) {
|
|
487
|
+
return new PostmarkProvider(config);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// src/providers/console.ts
|
|
491
|
+
var ConsoleProvider = class {
|
|
492
|
+
type = "console";
|
|
493
|
+
fromEmail;
|
|
494
|
+
fromName;
|
|
495
|
+
messageCounter = 0;
|
|
496
|
+
constructor(config) {
|
|
497
|
+
this.fromEmail = config.fromEmail;
|
|
498
|
+
this.fromName = config.fromName;
|
|
499
|
+
}
|
|
500
|
+
formatAddress(address) {
|
|
501
|
+
if (typeof address === "string") {
|
|
502
|
+
return address;
|
|
503
|
+
}
|
|
504
|
+
if (address.name) {
|
|
505
|
+
return `${address.name} <${address.email}>`;
|
|
506
|
+
}
|
|
507
|
+
return address.email;
|
|
508
|
+
}
|
|
509
|
+
formatAddresses(addresses) {
|
|
510
|
+
if (Array.isArray(addresses)) {
|
|
511
|
+
return addresses.map((a) => this.formatAddress(a)).join(", ");
|
|
512
|
+
}
|
|
513
|
+
return this.formatAddress(addresses);
|
|
514
|
+
}
|
|
515
|
+
async send(options) {
|
|
516
|
+
this.messageCounter++;
|
|
517
|
+
const messageId = `console-${Date.now()}-${this.messageCounter}`;
|
|
518
|
+
const from = options.from ? this.formatAddress(options.from) : this.fromName ? `${this.fromName} <${this.fromEmail}>` : this.fromEmail;
|
|
519
|
+
const separator = "\u2500".repeat(60);
|
|
520
|
+
console.log(`
|
|
521
|
+
${separator}`);
|
|
522
|
+
console.log("\u{1F4E7} EMAIL (Console Provider)");
|
|
523
|
+
console.log(separator);
|
|
524
|
+
console.log(`Message ID: ${messageId}`);
|
|
525
|
+
console.log(`From: ${from}`);
|
|
526
|
+
console.log(`To: ${this.formatAddresses(options.to)}`);
|
|
527
|
+
if (options.cc) {
|
|
528
|
+
console.log(`CC: ${this.formatAddresses(options.cc)}`);
|
|
529
|
+
}
|
|
530
|
+
if (options.bcc) {
|
|
531
|
+
console.log(`BCC: ${this.formatAddresses(options.bcc)}`);
|
|
532
|
+
}
|
|
533
|
+
if (options.replyTo) {
|
|
534
|
+
console.log(`Reply-To: ${this.formatAddress(options.replyTo)}`);
|
|
535
|
+
}
|
|
536
|
+
console.log(`Subject: ${options.subject}`);
|
|
537
|
+
if (options.headers) {
|
|
538
|
+
console.log(`Headers: ${JSON.stringify(options.headers)}`);
|
|
539
|
+
}
|
|
540
|
+
if (options.tags) {
|
|
541
|
+
console.log(`Tags: ${JSON.stringify(options.tags)}`);
|
|
542
|
+
}
|
|
543
|
+
if (options.scheduledAt) {
|
|
544
|
+
console.log(`Scheduled: ${options.scheduledAt.toISOString()}`);
|
|
545
|
+
}
|
|
546
|
+
if (options.attachments && options.attachments.length > 0) {
|
|
547
|
+
console.log(`Attachments:`);
|
|
548
|
+
for (const att of options.attachments) {
|
|
549
|
+
const size = typeof att.content === "string" ? att.content.length : att.content.length;
|
|
550
|
+
console.log(` - ${att.filename} (${att.contentType || "unknown"}, ${size} bytes)`);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
console.log(separator);
|
|
554
|
+
if (options.text) {
|
|
555
|
+
console.log("TEXT CONTENT:");
|
|
556
|
+
console.log(options.text);
|
|
557
|
+
}
|
|
558
|
+
if (options.html) {
|
|
559
|
+
console.log("HTML CONTENT:");
|
|
560
|
+
console.log(options.html);
|
|
561
|
+
}
|
|
562
|
+
console.log(`${separator}
|
|
563
|
+
`);
|
|
564
|
+
return {
|
|
565
|
+
success: true,
|
|
566
|
+
messageId
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
async sendBatch(options) {
|
|
570
|
+
const results = [];
|
|
571
|
+
let successful = 0;
|
|
572
|
+
let failed = 0;
|
|
573
|
+
console.log(`
|
|
574
|
+
\u{1F4EC} BATCH EMAIL (${options.emails.length} emails)`);
|
|
575
|
+
for (const email of options.emails) {
|
|
576
|
+
try {
|
|
577
|
+
const result = await this.send(email);
|
|
578
|
+
results.push(result);
|
|
579
|
+
if (result.success) {
|
|
580
|
+
successful++;
|
|
581
|
+
} else {
|
|
582
|
+
failed++;
|
|
583
|
+
if (options.stopOnError) break;
|
|
584
|
+
}
|
|
585
|
+
} catch (err) {
|
|
586
|
+
failed++;
|
|
587
|
+
results.push({
|
|
588
|
+
success: false,
|
|
589
|
+
error: err instanceof Error ? err.message : "Unknown error"
|
|
590
|
+
});
|
|
591
|
+
if (options.stopOnError) break;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
console.log(`\u{1F4EC} BATCH COMPLETE: ${successful} sent, ${failed} failed
|
|
595
|
+
`);
|
|
596
|
+
return {
|
|
597
|
+
total: options.emails.length,
|
|
598
|
+
successful,
|
|
599
|
+
failed,
|
|
600
|
+
results
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
async verify() {
|
|
604
|
+
console.log("\u{1F4E7} Console email provider verified (always returns true)");
|
|
605
|
+
return true;
|
|
606
|
+
}
|
|
607
|
+
};
|
|
608
|
+
function createConsoleProvider(config) {
|
|
609
|
+
return new ConsoleProvider(config);
|
|
610
|
+
}
|
|
611
|
+
export {
|
|
612
|
+
ConsoleProvider,
|
|
613
|
+
PostmarkProvider,
|
|
614
|
+
ResendProvider,
|
|
615
|
+
SendGridProvider,
|
|
616
|
+
createConsoleProvider,
|
|
617
|
+
createPostmarkProvider,
|
|
618
|
+
createResendProvider,
|
|
619
|
+
createSendGridProvider
|
|
620
|
+
};
|
|
621
|
+
//# sourceMappingURL=index.js.map
|