@visulima/email 1.0.0-alpha.1 → 1.0.0-alpha.2
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 +31 -0
- package/README.md +377 -60
- package/dist/crypto/index.js +1 -1
- package/dist/draft-mail-message.d.ts +13 -0
- package/dist/index.d.ts +3 -16
- package/dist/index.js +1 -1
- package/dist/mail-message.d.ts +425 -0
- package/dist/mail.d.ts +124 -275
- package/dist/packem_shared/{DkimSigner-Z8D4Il10.js → DkimSigner-pFd4c3fZ.js} +1 -1
- package/dist/packem_shared/Mail-6Bltpy_p.js +1 -0
- package/dist/packem_shared/MailMessage-B76GPBBA.js +1 -0
- package/dist/packem_shared/{SmimeSigner-02aXVi90.js → SmimeSigner-CObA4jzT.js} +1 -1
- package/dist/packem_shared/ahaSendProvider-DlFKEQ6D.js +1 -0
- package/dist/packem_shared/{awsSesProvider-CkuFOzb0.js → awsSesProvider-Ba-eVJxZ.js} +6 -6
- package/dist/packem_shared/azureProvider-CQYAkgVF.js +1 -0
- package/dist/packem_shared/brevoProvider-5p6jjiK9.js +1 -0
- package/dist/packem_shared/build-mime-message-IYaUqqPJ.js +2 -0
- package/dist/packem_shared/create-logger-BiWdqFNg.js +1 -0
- package/dist/packem_shared/failoverProvider-CAHQQueo.js +1 -0
- package/dist/packem_shared/{generateBoundary-CZ8kJuY6.js → generate-boundary-Cx8nXYS0.js} +1 -1
- package/dist/packem_shared/{generateMessageId-11Ls5JsR.js → generate-message-id-D4uA8gkj.js} +1 -1
- package/dist/packem_shared/headers-to-record-Qo124ImV.js +1 -0
- package/dist/packem_shared/httpProvider-CZD6LZX3.js +1 -0
- package/dist/packem_shared/infobipProvider-CtLwrUaP.js +1 -0
- package/dist/packem_shared/{mailCrabProvider-BEwRjB3F.js → mailCrabProvider-CM_CFDca.js} +1 -1
- package/dist/packem_shared/mailPaceProvider-B6yKvh6z.js +1 -0
- package/dist/packem_shared/mailerSendProvider-CeeIXFnW.js +1 -0
- package/dist/packem_shared/mailgunProvider-mmjKzouh.js +1 -0
- package/dist/packem_shared/mailjetProvider-DwN6i0VA.js +1 -0
- package/dist/packem_shared/mailomatProvider-DMQmjKHT.js +1 -0
- package/dist/packem_shared/mailtrapProvider-BN3UBEQw.js +1 -0
- package/dist/packem_shared/{makeRequest-DwxHX0xo.js → make-request-BDzF9W9D.js} +1 -1
- package/dist/packem_shared/mandrillProvider-370y7CLu.js +1 -0
- package/dist/packem_shared/mockProvider-DN5ZwutD.js +1 -0
- package/dist/packem_shared/nodemailerProvider-_w8QXMU-.js +1 -0
- package/dist/packem_shared/opentelemetryProvider-C_ZXOLSd.js +1 -0
- package/dist/packem_shared/plunkProvider-DfJumQ4U.js +1 -0
- package/dist/packem_shared/postalProvider-Bavx2FcH.js +1 -0
- package/dist/packem_shared/postmarkProvider-DFC0uvjO.js +1 -0
- package/dist/packem_shared/provider-base-Cmzx6BTO.js +1 -0
- package/dist/packem_shared/resendProvider-CfqU7UdE.js +1 -0
- package/dist/packem_shared/roundRobinProvider-1WQnuKR8.js +1 -0
- package/dist/packem_shared/scalewayProvider-be1HPimL.js +1 -0
- package/dist/packem_shared/sendGridProvider-BVI1sq3n.js +1 -0
- package/dist/packem_shared/smtpProvider-BV-ufR53.js +23 -0
- package/dist/packem_shared/sweegoProvider-7419CSAq.js +1 -0
- package/dist/packem_shared/validate-email-options-DfJ7llf8.js +1 -0
- package/dist/packem_shared/zeptomailProvider-C2lh0Xmo.js +1 -0
- package/dist/providers/ahasend/index.js +1 -1
- package/dist/providers/aws-ses/index.js +1 -1
- package/dist/providers/azure/index.js +1 -1
- package/dist/providers/brevo/index.js +1 -1
- package/dist/providers/brevo/types.d.ts +10 -3
- package/dist/providers/failover/index.js +1 -1
- package/dist/providers/http/index.js +1 -1
- package/dist/providers/infobip/index.js +1 -1
- package/dist/providers/mailcrab/index.js +1 -1
- package/dist/providers/mailersend/index.js +1 -1
- package/dist/providers/mailgun/index.js +1 -1
- package/dist/providers/mailjet/index.js +1 -1
- package/dist/providers/mailomat/index.js +1 -1
- package/dist/providers/mailpace/index.js +1 -1
- package/dist/providers/mailtrap/index.js +1 -1
- package/dist/providers/mandrill/index.js +1 -1
- package/dist/providers/mock/index.js +1 -1
- package/dist/providers/nodemailer/index.js +1 -1
- package/dist/providers/opentelemetry/index.js +1 -1
- package/dist/providers/plunk/index.js +1 -1
- package/dist/providers/postal/index.js +1 -1
- package/dist/providers/postmark/index.js +1 -1
- package/dist/providers/resend/index.js +1 -1
- package/dist/providers/roundrobin/index.js +1 -1
- package/dist/providers/scaleway/index.js +1 -1
- package/dist/providers/sendgrid/index.js +1 -1
- package/dist/providers/smtp/index.js +1 -1
- package/dist/providers/sweego/index.js +1 -1
- package/dist/providers/zeptomail/index.js +1 -1
- package/dist/types.d.ts +18 -0
- package/dist/utils/cache.d.ts +54 -0
- package/dist/utils/cache.js +1 -0
- package/dist/utils/create-logger.d.ts +2 -4
- package/dist/utils/format-email-address.js +1 -0
- package/dist/utils/normalize-email-aliases.d.ts +22 -0
- package/dist/utils/normalize-email-aliases.js +1 -0
- package/dist/utils/parse-address.js +1 -0
- package/dist/utils/validation/check-mx-records.d.ts +42 -0
- package/dist/utils/validation/check-mx-records.js +1 -0
- package/dist/utils/validation/disposable-email-domains.d.ts +13 -0
- package/dist/utils/validation/disposable-email-domains.js +1 -0
- package/dist/utils/validation/role-accounts.d.ts +21 -0
- package/dist/utils/validation/role-accounts.js +1 -0
- package/dist/utils/{validate-email-options.d.ts → validation/validate-email-options.d.ts} +1 -1
- package/dist/utils/validation/verify-email.d.ts +47 -0
- package/dist/utils/validation/verify-email.js +1 -0
- package/dist/utils/validation/verify-smtp.d.ts +39 -0
- package/dist/utils/validation/verify-smtp.js +4 -0
- package/package.json +47 -1
- package/dist/packem_shared/MailMessage-Hdgowmvi.js +0 -1
- package/dist/packem_shared/ahaSendProvider-NUD_kwyT.js +0 -1
- package/dist/packem_shared/azureProvider-Ckdrpmw9.js +0 -1
- package/dist/packem_shared/brevoProvider-CB3IYW4n.js +0 -1
- package/dist/packem_shared/buildMimeMessage-BPtd0pno.js +0 -2
- package/dist/packem_shared/comparePriority-BfiwjVsV.js +0 -1
- package/dist/packem_shared/createLogger-DlElSVQP.js +0 -1
- package/dist/packem_shared/failoverProvider-sam9n1AG.js +0 -1
- package/dist/packem_shared/formatEmailAddress-CHeME3Vk.js +0 -1
- package/dist/packem_shared/formatEmailAddresses-UegVOe5A.js +0 -1
- package/dist/packem_shared/headersToRecord-BKUTr40L.js +0 -1
- package/dist/packem_shared/httpProvider-BhN0RrK-.js +0 -1
- package/dist/packem_shared/infobipProvider-D8vYTHV4.js +0 -1
- package/dist/packem_shared/isPortAvailable-5kfsfo8u.js +0 -1
- package/dist/packem_shared/mailPaceProvider-C47Izgaj.js +0 -1
- package/dist/packem_shared/mailerSendProvider-C4uAo-fc.js +0 -1
- package/dist/packem_shared/mailgunProvider-B7upu_OV.js +0 -1
- package/dist/packem_shared/mailjetProvider-ReErm08u.js +0 -1
- package/dist/packem_shared/mailomatProvider-OlCT_O2i.js +0 -1
- package/dist/packem_shared/mailtrapProvider-hVMV3h6r.js +0 -1
- package/dist/packem_shared/mandrillProvider-DdnbkHZI.js +0 -1
- package/dist/packem_shared/mockProvider-BDWZJpea.js +0 -1
- package/dist/packem_shared/nodemailerProvider-BV21eRGX.js +0 -1
- package/dist/packem_shared/opentelemetryProvider-kAz62mKm.js +0 -1
- package/dist/packem_shared/parseAddress-CATTKGe_.js +0 -1
- package/dist/packem_shared/plunkProvider-Bs6K51lT.js +0 -1
- package/dist/packem_shared/postalProvider-Bcsxp-z6.js +0 -1
- package/dist/packem_shared/postmarkProvider-BUq3wuYD.js +0 -1
- package/dist/packem_shared/provider-base-_hbWXBdK.js +0 -1
- package/dist/packem_shared/resendProvider-D-_HQpN_.js +0 -1
- package/dist/packem_shared/retry-D1MBqS49.js +0 -1
- package/dist/packem_shared/roundRobinProvider-CejLM1rZ.js +0 -1
- package/dist/packem_shared/scalewayProvider-1n6ePiGl.js +0 -1
- package/dist/packem_shared/sendGridProvider-B1T62dyX.js +0 -1
- package/dist/packem_shared/smtpProvider-CcAoRrkt.js +0 -23
- package/dist/packem_shared/sweegoProvider-CxFmEUh6.js +0 -1
- package/dist/packem_shared/validateEmailOptions-BzlJECG5.js +0 -1
- package/dist/packem_shared/zeptomailProvider-CWYQPAJk.js +0 -1
- package/dist/utils/compare-priority.d.ts +0 -16
- /package/dist/utils/{validate-email.d.ts → validation/validate-email.d.ts} +0 -0
- /package/dist/{packem_shared/validateEmail-BkVdVioP.js → utils/validation/validate-email.js} +0 -0
package/README.md
CHANGED
|
@@ -44,7 +44,7 @@ pnpm add @visulima/email
|
|
|
44
44
|
### Basic Usage
|
|
45
45
|
|
|
46
46
|
```typescript
|
|
47
|
-
import { createMail, resendProvider } from "@visulima/email";
|
|
47
|
+
import { createMail, MailMessage, resendProvider } from "@visulima/email";
|
|
48
48
|
|
|
49
49
|
// Create a provider
|
|
50
50
|
const resend = resendProvider({
|
|
@@ -54,18 +54,82 @@ const resend = resendProvider({
|
|
|
54
54
|
// Create a Mail instance
|
|
55
55
|
const mail = createMail(resend);
|
|
56
56
|
|
|
57
|
+
// Optional: Set default configuration for all emails
|
|
58
|
+
mail.setFrom({ email: "noreply@example.com", name: "My App" });
|
|
59
|
+
|
|
57
60
|
// Send an email using the message builder
|
|
58
|
-
const
|
|
61
|
+
const message = new MailMessage()
|
|
62
|
+
.to("user@example.com")
|
|
63
|
+
// .from() is optional if set via mail.setFrom()
|
|
64
|
+
.subject("Hello")
|
|
65
|
+
.html("<h1>Hello World</h1>");
|
|
66
|
+
|
|
67
|
+
const result = await mail.send(message);
|
|
59
68
|
|
|
60
69
|
if (result.success) {
|
|
61
70
|
console.log("Email sent:", result.data?.messageId);
|
|
62
71
|
}
|
|
63
72
|
```
|
|
64
73
|
|
|
65
|
-
###
|
|
74
|
+
### Default Configuration
|
|
75
|
+
|
|
76
|
+
You can configure default values for all emails sent through a Mail instance:
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
import { createMail, MailMessage, resendProvider } from "@visulima/email";
|
|
80
|
+
|
|
81
|
+
const mail = createMail(resendProvider({ apiKey: "re_xxx" }));
|
|
82
|
+
|
|
83
|
+
// Set default from address
|
|
84
|
+
mail.setFrom({ email: "noreply@example.com", name: "My App" });
|
|
85
|
+
|
|
86
|
+
// Set default reply-to address
|
|
87
|
+
mail.setReplyTo({ email: "support@example.com" });
|
|
88
|
+
|
|
89
|
+
// Set default headers
|
|
90
|
+
mail.setHeaders({
|
|
91
|
+
"X-App-Name": "MyApp",
|
|
92
|
+
"X-Version": "1.0.0",
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Or chain them together
|
|
96
|
+
const mail2 = createMail(resendProvider({ apiKey: "re_xxx" }))
|
|
97
|
+
.setFrom({ email: "noreply@example.com" })
|
|
98
|
+
.setReplyTo({ email: "support@example.com" })
|
|
99
|
+
.setHeaders({ "X-App-Name": "MyApp" });
|
|
100
|
+
|
|
101
|
+
// Now all emails will use these defaults if not specified in the message
|
|
102
|
+
const message = new MailMessage().to("user@example.com").subject("Hello").html("<h1>Hello World</h1>");
|
|
103
|
+
// No need to set .from() - it will use the default
|
|
104
|
+
|
|
105
|
+
await mail.send(message);
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Creating Draft Emails
|
|
109
|
+
|
|
110
|
+
You can create draft emails in EML (RFC 822) format without sending them. The `draft()` method returns the email as an EML string with an `X-Unsent: 1` header automatically added:
|
|
66
111
|
|
|
67
112
|
```typescript
|
|
68
|
-
import { createMail,
|
|
113
|
+
import { createMail, MailMessage, resendProvider } from "@visulima/email";
|
|
114
|
+
import { writeFile } from "fs/promises";
|
|
115
|
+
|
|
116
|
+
const mail = createMail(resendProvider({ apiKey: "re_xxx" }));
|
|
117
|
+
|
|
118
|
+
const message = new MailMessage().to("user@example.com").from("sender@example.com").subject("Hello").html("<h1>Hello World</h1>");
|
|
119
|
+
|
|
120
|
+
// Create a draft in EML format
|
|
121
|
+
const eml = await mail.draft(message);
|
|
122
|
+
|
|
123
|
+
// Save to file
|
|
124
|
+
await writeFile("draft.eml", eml);
|
|
125
|
+
|
|
126
|
+
// EML files can be opened by email clients
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Using Different Providers
|
|
130
|
+
|
|
131
|
+
````typescript
|
|
132
|
+
import { createMail, MailMessage, smtpProvider, resendProvider } from "@visulima/email";
|
|
69
133
|
|
|
70
134
|
// SMTP provider
|
|
71
135
|
const smtp = smtpProvider({
|
|
@@ -86,31 +150,13 @@ const smtpMail = createMail(smtp);
|
|
|
86
150
|
const resendMail = createMail(resend);
|
|
87
151
|
|
|
88
152
|
// Send via specific provider
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
153
|
+
const message = new MailMessage()
|
|
154
|
+
.to("user@example.com")
|
|
155
|
+
.from("sender@example.com")
|
|
156
|
+
.subject("Hello")
|
|
157
|
+
.html("<h1>Hello World</h1>");
|
|
93
158
|
|
|
94
|
-
|
|
95
|
-
import { createMail, type Mailable, type EmailOptions } from "@visulima/email";
|
|
96
|
-
import { resendProvider } from "@visulima/email";
|
|
97
|
-
|
|
98
|
-
class WelcomeEmail implements Mailable {
|
|
99
|
-
constructor(private user: { name: string; email: string }) {}
|
|
100
|
-
|
|
101
|
-
build(): EmailOptions {
|
|
102
|
-
return {
|
|
103
|
-
from: { email: "noreply@example.com" },
|
|
104
|
-
to: { email: this.user.email, name: this.user.name },
|
|
105
|
-
subject: "Welcome!",
|
|
106
|
-
html: `<h1>Welcome ${this.user.name}!</h1>`,
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const mail = createMail(resendProvider({ apiKey: "re_xxx" }));
|
|
112
|
-
const result = await mail.send(new WelcomeEmail({ name: "John", email: "john@example.com" }));
|
|
113
|
-
```
|
|
159
|
+
await resendMail.send(message);
|
|
114
160
|
|
|
115
161
|
### Direct Email Sending
|
|
116
162
|
|
|
@@ -126,7 +172,7 @@ const emailOptions: EmailOptions = {
|
|
|
126
172
|
html: "<h1>Hello World</h1>",
|
|
127
173
|
};
|
|
128
174
|
|
|
129
|
-
const result = await mail.
|
|
175
|
+
const result = await mail.send(emailOptions);
|
|
130
176
|
```
|
|
131
177
|
|
|
132
178
|
### Failover Provider
|
|
@@ -134,7 +180,7 @@ const result = await mail.sendEmail(emailOptions);
|
|
|
134
180
|
The failover provider allows you to configure multiple email providers as backups. If the primary provider fails, it will automatically try the next provider in the list.
|
|
135
181
|
|
|
136
182
|
```typescript
|
|
137
|
-
import { createMail, failoverProvider, resendProvider, smtpProvider } from "@visulima/email";
|
|
183
|
+
import { createMail, MailMessage, failoverProvider, resendProvider, smtpProvider } from "@visulima/email";
|
|
138
184
|
|
|
139
185
|
// Create individual providers
|
|
140
186
|
const resend = resendProvider({ apiKey: "re_xxx" });
|
|
@@ -157,7 +203,9 @@ const failover = failoverProvider({
|
|
|
157
203
|
// Use failover provider
|
|
158
204
|
const mail = createMail(failover);
|
|
159
205
|
|
|
160
|
-
const
|
|
206
|
+
const message = new MailMessage().to("user@example.com").from("sender@example.com").subject("Hello").html("<h1>Hello World</h1>");
|
|
207
|
+
|
|
208
|
+
const result = await mail.send(message);
|
|
161
209
|
|
|
162
210
|
// The failover provider will try Resend first, and if it fails,
|
|
163
211
|
// automatically try SMTP
|
|
@@ -188,7 +236,7 @@ const failover = failoverProvider({
|
|
|
188
236
|
The round-robin provider distributes your email sending workload across multiple providers. Each email is sent using the next available provider in rotation, providing load balancing across your mailers.
|
|
189
237
|
|
|
190
238
|
```typescript
|
|
191
|
-
import { createMail, roundRobinProvider, resendProvider, smtpProvider } from "@visulima/email";
|
|
239
|
+
import { createMail, MailMessage, roundRobinProvider, resendProvider, smtpProvider } from "@visulima/email";
|
|
192
240
|
|
|
193
241
|
// Create individual providers
|
|
194
242
|
const resend = resendProvider({ apiKey: "re_xxx" });
|
|
@@ -212,13 +260,16 @@ const roundRobin = roundRobinProvider({
|
|
|
212
260
|
const mail = createMail(roundRobin);
|
|
213
261
|
|
|
214
262
|
// Each email will be distributed across providers in rotation
|
|
215
|
-
|
|
263
|
+
const message1 = new MailMessage().to("user1@example.com").from("sender@example.com").subject("Email 1").html("<h1>Email 1</h1>");
|
|
264
|
+
await mail.send(message1);
|
|
216
265
|
// Uses resend (or random start)
|
|
217
266
|
|
|
218
|
-
|
|
267
|
+
const message2 = new MailMessage().to("user2@example.com").from("sender@example.com").subject("Email 2").html("<h1>Email 2</h1>");
|
|
268
|
+
await mail.send(message2);
|
|
219
269
|
// Uses smtp (next in rotation)
|
|
220
270
|
|
|
221
|
-
|
|
271
|
+
const message3 = new MailMessage().to("user3@example.com").from("sender@example.com").subject("Email 3").html("<h1>Email 3</h1>");
|
|
272
|
+
await mail.send(message3);
|
|
222
273
|
// Uses resend (back to first)
|
|
223
274
|
```
|
|
224
275
|
|
|
@@ -262,7 +313,8 @@ const mailgun = mailgunProvider({
|
|
|
262
313
|
const mail = createMail(mailgun);
|
|
263
314
|
|
|
264
315
|
// Send email with Mailgun-specific options
|
|
265
|
-
const
|
|
316
|
+
const message = new MailMessage().to("user@example.com").from("sender@example.com").subject("Welcome").html("<h1>Welcome!</h1>");
|
|
317
|
+
const result = await mail.send(message);
|
|
266
318
|
|
|
267
319
|
// Or use Mailgun-specific features
|
|
268
320
|
import type { MailgunEmailOptions } from "@visulima/email/providers/mailgun";
|
|
@@ -280,7 +332,7 @@ const mailgunOptions: MailgunEmailOptions = {
|
|
|
280
332
|
deliveryTime: Math.floor(Date.now() / 1000) + 3600, // Schedule for 1 hour from now
|
|
281
333
|
};
|
|
282
334
|
|
|
283
|
-
await mail.
|
|
335
|
+
await mail.send(mailgunOptions);
|
|
284
336
|
```
|
|
285
337
|
|
|
286
338
|
### Mailjet Provider
|
|
@@ -301,7 +353,8 @@ const mailjet = mailjetProvider({
|
|
|
301
353
|
const mail = createMail(mailjet);
|
|
302
354
|
|
|
303
355
|
// Send email with Mailjet-specific options
|
|
304
|
-
const
|
|
356
|
+
const message = new MailMessage().to("user@example.com").from("sender@example.com").subject("Welcome").html("<h1>Welcome!</h1>");
|
|
357
|
+
const result = await mail.send(message);
|
|
305
358
|
|
|
306
359
|
// Or use Mailjet-specific features
|
|
307
360
|
import type { MailjetEmailOptions } from "@visulima/email/providers/mailjet";
|
|
@@ -320,7 +373,7 @@ const mailjetOptions: MailjetEmailOptions = {
|
|
|
320
373
|
deliveryTime: Math.floor(Date.now() / 1000) + 3600, // Schedule for 1 hour from now
|
|
321
374
|
};
|
|
322
375
|
|
|
323
|
-
await mail.
|
|
376
|
+
await mail.send(mailjetOptions);
|
|
324
377
|
```
|
|
325
378
|
|
|
326
379
|
### MailerSend Provider
|
|
@@ -359,7 +412,7 @@ const mailerSendOptions: MailerSendEmailOptions = {
|
|
|
359
412
|
scheduledAt: Math.floor(Date.now() / 1000) + 3600, // Schedule for 1 hour from now
|
|
360
413
|
};
|
|
361
414
|
|
|
362
|
-
await mail.
|
|
415
|
+
await mail.send(mailerSendOptions);
|
|
363
416
|
```
|
|
364
417
|
|
|
365
418
|
### Mandrill Provider (Mailchimp Transactional)
|
|
@@ -393,7 +446,7 @@ const mandrillOptions: MandrillEmailOptions = {
|
|
|
393
446
|
metadata: { orderId: "123" },
|
|
394
447
|
};
|
|
395
448
|
|
|
396
|
-
await mail.
|
|
449
|
+
await mail.send(mandrillOptions);
|
|
397
450
|
```
|
|
398
451
|
|
|
399
452
|
### Postal Provider
|
|
@@ -426,7 +479,7 @@ const postalOptions: PostalEmailOptions = {
|
|
|
426
479
|
tags: ["welcome"],
|
|
427
480
|
};
|
|
428
481
|
|
|
429
|
-
await mail.
|
|
482
|
+
await mail.send(postalOptions);
|
|
430
483
|
```
|
|
431
484
|
|
|
432
485
|
### Mailtrap Provider
|
|
@@ -460,7 +513,7 @@ const mailtrapOptions: MailtrapEmailOptions = {
|
|
|
460
513
|
tags: ["welcome"],
|
|
461
514
|
};
|
|
462
515
|
|
|
463
|
-
await mail.
|
|
516
|
+
await mail.send(mailtrapOptions);
|
|
464
517
|
```
|
|
465
518
|
|
|
466
519
|
### MailPace Provider
|
|
@@ -493,7 +546,7 @@ const mailPaceOptions: MailPaceEmailOptions = {
|
|
|
493
546
|
listUnsubscribe: "<mailto:unsubscribe@example.com>",
|
|
494
547
|
};
|
|
495
548
|
|
|
496
|
-
await mail.
|
|
549
|
+
await mail.send(mailPaceOptions);
|
|
497
550
|
```
|
|
498
551
|
|
|
499
552
|
### Azure Communication Services Provider
|
|
@@ -530,7 +583,7 @@ const azureOptions: AzureEmailOptions = {
|
|
|
530
583
|
importance: "high", // "normal" or "high"
|
|
531
584
|
};
|
|
532
585
|
|
|
533
|
-
await mail.
|
|
586
|
+
await mail.send(azureOptions);
|
|
534
587
|
```
|
|
535
588
|
|
|
536
589
|
### Infobip Provider
|
|
@@ -564,7 +617,7 @@ const infobipOptions: InfobipEmailOptions = {
|
|
|
564
617
|
sendAt: Date.now() + 3600000, // Schedule for 1 hour from now (milliseconds)
|
|
565
618
|
};
|
|
566
619
|
|
|
567
|
-
await mail.
|
|
620
|
+
await mail.send(infobipOptions);
|
|
568
621
|
```
|
|
569
622
|
|
|
570
623
|
### Scaleway Provider
|
|
@@ -596,7 +649,7 @@ const scalewayOptions: ScalewayEmailOptions = {
|
|
|
596
649
|
projectId: "project-uuid", // Optional
|
|
597
650
|
};
|
|
598
651
|
|
|
599
|
-
await mail.
|
|
652
|
+
await mail.send(scalewayOptions);
|
|
600
653
|
```
|
|
601
654
|
|
|
602
655
|
### AhaSend Provider
|
|
@@ -628,7 +681,7 @@ const ahaSendOptions: AhaSendEmailOptions = {
|
|
|
628
681
|
tags: ["welcome"],
|
|
629
682
|
};
|
|
630
683
|
|
|
631
|
-
await mail.
|
|
684
|
+
await mail.send(ahaSendOptions);
|
|
632
685
|
```
|
|
633
686
|
|
|
634
687
|
### Mailomat Provider
|
|
@@ -660,7 +713,7 @@ const mailomatOptions: MailomatEmailOptions = {
|
|
|
660
713
|
tags: ["welcome"],
|
|
661
714
|
};
|
|
662
715
|
|
|
663
|
-
await mail.
|
|
716
|
+
await mail.send(mailomatOptions);
|
|
664
717
|
```
|
|
665
718
|
|
|
666
719
|
### Sweego Provider
|
|
@@ -692,7 +745,7 @@ const sweegoOptions: SweegoEmailOptions = {
|
|
|
692
745
|
tags: ["welcome"],
|
|
693
746
|
};
|
|
694
747
|
|
|
695
|
-
await mail.
|
|
748
|
+
await mail.send(sweegoOptions);
|
|
696
749
|
```
|
|
697
750
|
|
|
698
751
|
### Brevo Provider (formerly Sendinblue)
|
|
@@ -712,7 +765,8 @@ const brevo = brevoProvider({
|
|
|
712
765
|
const mail = createMail(brevo);
|
|
713
766
|
|
|
714
767
|
// Send email with Brevo-specific options
|
|
715
|
-
const
|
|
768
|
+
const message = new MailMessage().to("user@example.com").from("sender@example.com").subject("Welcome").html("<h1>Welcome!</h1>");
|
|
769
|
+
const result = await mail.send(message);
|
|
716
770
|
|
|
717
771
|
// Or use Brevo-specific features
|
|
718
772
|
import type { BrevoEmailOptions } from "@visulima/email/providers/brevo";
|
|
@@ -728,7 +782,7 @@ const brevoOptions: BrevoEmailOptions = {
|
|
|
728
782
|
scheduledAt: Math.floor(Date.now() / 1000) + 3600, // Schedule for 1 hour from now
|
|
729
783
|
};
|
|
730
784
|
|
|
731
|
-
await mail.
|
|
785
|
+
await mail.send(brevoOptions);
|
|
732
786
|
```
|
|
733
787
|
|
|
734
788
|
### Postmark Provider
|
|
@@ -748,7 +802,8 @@ const postmark = postmarkProvider({
|
|
|
748
802
|
const mail = createMail(postmark);
|
|
749
803
|
|
|
750
804
|
// Send email with Postmark-specific options
|
|
751
|
-
const
|
|
805
|
+
const message = new MailMessage().to("user@example.com").from("sender@example.com").subject("Welcome").html("<h1>Welcome!</h1>");
|
|
806
|
+
const result = await mail.send(message);
|
|
752
807
|
|
|
753
808
|
// Or use Postmark-specific features
|
|
754
809
|
import type { PostmarkEmailOptions } from "@visulima/email/providers/postmark";
|
|
@@ -767,7 +822,7 @@ const postmarkOptions: PostmarkEmailOptions = {
|
|
|
767
822
|
metadata: { userId: "123" }, // Custom metadata
|
|
768
823
|
};
|
|
769
824
|
|
|
770
|
-
await mail.
|
|
825
|
+
await mail.send(postmarkOptions);
|
|
771
826
|
```
|
|
772
827
|
|
|
773
828
|
### SendGrid Provider
|
|
@@ -787,7 +842,8 @@ const sendgrid = sendGridProvider({
|
|
|
787
842
|
const mail = createMail(sendgrid);
|
|
788
843
|
|
|
789
844
|
// Send email with SendGrid-specific options
|
|
790
|
-
const
|
|
845
|
+
const message = new MailMessage().to("user@example.com").from("sender@example.com").subject("Welcome").html("<h1>Welcome!</h1>");
|
|
846
|
+
const result = await mail.send(message);
|
|
791
847
|
|
|
792
848
|
// Or use SendGrid-specific features
|
|
793
849
|
import type { SendGridEmailOptions } from "@visulima/email/providers/sendgrid";
|
|
@@ -807,7 +863,7 @@ const sendGridOptions: SendGridEmailOptions = {
|
|
|
807
863
|
},
|
|
808
864
|
};
|
|
809
865
|
|
|
810
|
-
await mail.
|
|
866
|
+
await mail.send(sendGridOptions);
|
|
811
867
|
```
|
|
812
868
|
|
|
813
869
|
### Plunk Provider
|
|
@@ -827,7 +883,8 @@ const plunk = plunkProvider({
|
|
|
827
883
|
const mail = createMail(plunk);
|
|
828
884
|
|
|
829
885
|
// Send email with Plunk-specific options
|
|
830
|
-
const
|
|
886
|
+
const message = new MailMessage().to("user@example.com").from("sender@example.com").subject("Welcome").html("<h1>Welcome!</h1>");
|
|
887
|
+
const result = await mail.send(message);
|
|
831
888
|
|
|
832
889
|
// Or use Plunk-specific features
|
|
833
890
|
import type { PlunkEmailOptions } from "@visulima/email/providers/plunk";
|
|
@@ -843,7 +900,7 @@ const plunkOptions: PlunkEmailOptions = {
|
|
|
843
900
|
data: { name: "John" }, // Template data
|
|
844
901
|
};
|
|
845
902
|
|
|
846
|
-
await mail.
|
|
903
|
+
await mail.send(plunkOptions);
|
|
847
904
|
```
|
|
848
905
|
|
|
849
906
|
### Mock Provider (for Testing)
|
|
@@ -864,7 +921,8 @@ const mock = mockProvider({
|
|
|
864
921
|
const mail = createMail(mock);
|
|
865
922
|
|
|
866
923
|
// Send email (stored in memory)
|
|
867
|
-
const
|
|
924
|
+
const message = new MailMessage().to("user@example.com").from("sender@example.com").subject("Test").html("<h1>Test</h1>");
|
|
925
|
+
const result = await mail.send(message);
|
|
868
926
|
|
|
869
927
|
// Access stored emails
|
|
870
928
|
const sentEmails = mock.getSentEmails();
|
|
@@ -931,7 +989,8 @@ const customMailCrab = mailCrabProvider({
|
|
|
931
989
|
// Use MailCrab provider
|
|
932
990
|
const mail = createMail(mailCrab);
|
|
933
991
|
|
|
934
|
-
const
|
|
992
|
+
const message = new MailMessage().to("user@example.com").from("sender@example.com").subject("Test Email").html("<h1>Test</h1>");
|
|
993
|
+
const result = await mail.send(message);
|
|
935
994
|
```
|
|
936
995
|
|
|
937
996
|
**Note:** Make sure MailCrab is running locally before using this provider. MailCrab can be installed via Docker or as a standalone application.
|
|
@@ -1054,6 +1113,263 @@ Template engines are optional peer dependencies and work where their underlying
|
|
|
1054
1113
|
|
|
1055
1114
|
\* Runtime support depends on the wrapped providers. Works if all wrapped providers support the runtime.
|
|
1056
1115
|
|
|
1116
|
+
## Disposable Email Detection
|
|
1117
|
+
|
|
1118
|
+
The package includes support for detecting disposable email addresses using the `@visulima/disposable-email-domains` package, which is included as a dependency.
|
|
1119
|
+
|
|
1120
|
+
### Usage
|
|
1121
|
+
|
|
1122
|
+
```typescript
|
|
1123
|
+
import { isDisposableEmail } from "@visulima/email/validation/disposable-email-domains";
|
|
1124
|
+
|
|
1125
|
+
// Check if an email is disposable
|
|
1126
|
+
if (isDisposableEmail("user@mailinator.com")) {
|
|
1127
|
+
console.log("Disposable email detected!");
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
// With custom domains
|
|
1131
|
+
const customDomains = new Set(["my-disposable.com"]);
|
|
1132
|
+
if (isDisposableEmail("user@my-disposable.com", customDomains)) {
|
|
1133
|
+
console.log("Custom disposable email detected!");
|
|
1134
|
+
}
|
|
1135
|
+
```
|
|
1136
|
+
|
|
1137
|
+
**Note:** The `@visulima/disposable-email-domains` package is included as a dependency, so no additional installation is required.
|
|
1138
|
+
|
|
1139
|
+
## Email Verification
|
|
1140
|
+
|
|
1141
|
+
The package provides comprehensive email verification utilities including MX record checking, SMTP verification, and role account detection.
|
|
1142
|
+
|
|
1143
|
+
### MX Record Checking
|
|
1144
|
+
|
|
1145
|
+
Check if a domain has valid MX (Mail Exchange) records:
|
|
1146
|
+
|
|
1147
|
+
```typescript
|
|
1148
|
+
import { checkMxRecords } from "@visulima/email/validation/check-mx-records";
|
|
1149
|
+
|
|
1150
|
+
const result = await checkMxRecords("example.com");
|
|
1151
|
+
|
|
1152
|
+
if (result.valid) {
|
|
1153
|
+
console.log("MX records:", result.records);
|
|
1154
|
+
// Records are sorted by priority (lowest first)
|
|
1155
|
+
} else {
|
|
1156
|
+
console.error("No MX records found:", result.error);
|
|
1157
|
+
}
|
|
1158
|
+
```
|
|
1159
|
+
|
|
1160
|
+
#### Caching MX Records
|
|
1161
|
+
|
|
1162
|
+
Use caching to improve performance and reduce DNS lookups:
|
|
1163
|
+
|
|
1164
|
+
```typescript
|
|
1165
|
+
import { checkMxRecords } from "@visulima/email/validation/check-mx-records";
|
|
1166
|
+
import { InMemoryCache } from "@visulima/email/utils/cache";
|
|
1167
|
+
|
|
1168
|
+
// Create a cache instance
|
|
1169
|
+
const cache = new InMemoryCache();
|
|
1170
|
+
|
|
1171
|
+
// Use cache with default TTL (1 hour)
|
|
1172
|
+
const result1 = await checkMxRecords("example.com", { cache });
|
|
1173
|
+
|
|
1174
|
+
// Use cache with custom TTL (5 minutes)
|
|
1175
|
+
const result2 = await checkMxRecords("example.com", {
|
|
1176
|
+
cache,
|
|
1177
|
+
ttl: 5 * 60 * 1000, // 5 minutes in milliseconds
|
|
1178
|
+
});
|
|
1179
|
+
|
|
1180
|
+
// Clear cache when needed
|
|
1181
|
+
await cache.clear();
|
|
1182
|
+
```
|
|
1183
|
+
|
|
1184
|
+
#### Custom Cache Implementation
|
|
1185
|
+
|
|
1186
|
+
You can implement your own cache using the `Cache` interface (e.g., for Redis, LRU cache, etc.):
|
|
1187
|
+
|
|
1188
|
+
```typescript
|
|
1189
|
+
import type { Cache, MxCheckResult } from "@visulima/email/utils/cache";
|
|
1190
|
+
import { checkMxRecords } from "@visulima/email/validation/check-mx-records";
|
|
1191
|
+
|
|
1192
|
+
// Example: Custom Redis cache implementation
|
|
1193
|
+
const redisCache: Cache<MxCheckResult> = {
|
|
1194
|
+
get: async (key: string) => {
|
|
1195
|
+
const cached = await redis.get(`mx:${key}`);
|
|
1196
|
+
return cached ? JSON.parse(cached) : undefined;
|
|
1197
|
+
},
|
|
1198
|
+
set: async (key: string, value: MxCheckResult, ttl: number) => {
|
|
1199
|
+
await redis.setex(`mx:${key}`, Math.floor(ttl / 1000), JSON.stringify(value));
|
|
1200
|
+
},
|
|
1201
|
+
delete: async (key: string) => {
|
|
1202
|
+
await redis.del(`mx:${key}`);
|
|
1203
|
+
},
|
|
1204
|
+
clear: async () => {
|
|
1205
|
+
// Clear all MX cache keys
|
|
1206
|
+
const keys = await redis.keys("mx:*");
|
|
1207
|
+
if (keys.length > 0) {
|
|
1208
|
+
await redis.del(...keys);
|
|
1209
|
+
}
|
|
1210
|
+
},
|
|
1211
|
+
};
|
|
1212
|
+
|
|
1213
|
+
// Use custom cache
|
|
1214
|
+
const result = await checkMxRecords("example.com", {
|
|
1215
|
+
cache: redisCache,
|
|
1216
|
+
ttl: 10 * 60 * 1000, // 10 minutes
|
|
1217
|
+
});
|
|
1218
|
+
```
|
|
1219
|
+
|
|
1220
|
+
### Role Account Detection
|
|
1221
|
+
|
|
1222
|
+
Detect if an email address is a role account (non-personal email like `noreply@`, `support@`, etc.):
|
|
1223
|
+
|
|
1224
|
+
```typescript
|
|
1225
|
+
import { isRoleAccount } from "@visulima/email/validation/role-accounts";
|
|
1226
|
+
|
|
1227
|
+
if (isRoleAccount("noreply@example.com")) {
|
|
1228
|
+
console.log("This is a role account");
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
// With custom role prefixes
|
|
1232
|
+
const customPrefixes = new Set(["custom-role", "my-role"]);
|
|
1233
|
+
if (isRoleAccount("custom-role@example.com", customPrefixes)) {
|
|
1234
|
+
console.log("Custom role account detected");
|
|
1235
|
+
}
|
|
1236
|
+
```
|
|
1237
|
+
|
|
1238
|
+
### SMTP Verification
|
|
1239
|
+
|
|
1240
|
+
Verify if an email address exists by connecting to the mail server:
|
|
1241
|
+
|
|
1242
|
+
```typescript
|
|
1243
|
+
import { verifySmtp } from "@visulima/email/validation/verify-smtp";
|
|
1244
|
+
import { InMemoryCache } from "@visulima/email/utils/cache";
|
|
1245
|
+
import type { MxCheckResult, SmtpVerificationResult } from "@visulima/email/validation/check-mx-records";
|
|
1246
|
+
|
|
1247
|
+
// Create separate caches for MX records and SMTP results
|
|
1248
|
+
const mxCache = new InMemoryCache<MxCheckResult>();
|
|
1249
|
+
const smtpCache = new InMemoryCache<SmtpVerificationResult>();
|
|
1250
|
+
|
|
1251
|
+
const result = await verifySmtp("user@example.com", {
|
|
1252
|
+
timeout: 5000,
|
|
1253
|
+
fromEmail: "test@example.com",
|
|
1254
|
+
port: 25,
|
|
1255
|
+
cache: mxCache, // Optional: cache MX records
|
|
1256
|
+
smtpCache, // Optional: cache SMTP verification results
|
|
1257
|
+
ttl: 5 * 60 * 1000, // Cache for 5 minutes
|
|
1258
|
+
});
|
|
1259
|
+
|
|
1260
|
+
if (result.valid) {
|
|
1261
|
+
console.log("Email address exists");
|
|
1262
|
+
} else {
|
|
1263
|
+
console.error("Verification failed:", result.error);
|
|
1264
|
+
}
|
|
1265
|
+
```
|
|
1266
|
+
|
|
1267
|
+
**Note:** Many mail servers block SMTP verification to prevent email harvesting. This method may not work for all domains.
|
|
1268
|
+
|
|
1269
|
+
### Comprehensive Email Verification
|
|
1270
|
+
|
|
1271
|
+
Combine all verification checks in a single function:
|
|
1272
|
+
|
|
1273
|
+
```typescript
|
|
1274
|
+
import { verifyEmail } from "@visulima/email/validation/verify-email";
|
|
1275
|
+
import { InMemoryCache } from "@visulima/email/utils/cache";
|
|
1276
|
+
import type { MxCheckResult, SmtpVerificationResult } from "@visulima/email/validation/check-mx-records";
|
|
1277
|
+
|
|
1278
|
+
// Create separate caches for MX records and SMTP results
|
|
1279
|
+
const mxCache = new InMemoryCache<MxCheckResult>();
|
|
1280
|
+
const smtpCache = new InMemoryCache<SmtpVerificationResult>();
|
|
1281
|
+
|
|
1282
|
+
const result = await verifyEmail("user@example.com", {
|
|
1283
|
+
checkDisposable: true,
|
|
1284
|
+
checkRoleAccount: true,
|
|
1285
|
+
checkMx: true,
|
|
1286
|
+
checkSmtp: false, // Optional, many servers block this
|
|
1287
|
+
cache: mxCache, // Optional: cache MX records
|
|
1288
|
+
smtpCache, // Optional: cache SMTP verification results
|
|
1289
|
+
customDisposableDomains: new Set(["custom-disposable.com"]),
|
|
1290
|
+
customRolePrefixes: new Set(["custom-role"]),
|
|
1291
|
+
});
|
|
1292
|
+
|
|
1293
|
+
if (result.valid) {
|
|
1294
|
+
console.log("Email is valid!");
|
|
1295
|
+
} else {
|
|
1296
|
+
console.error("Errors:", result.errors);
|
|
1297
|
+
console.warn("Warnings:", result.warnings);
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
// Access individual check results
|
|
1301
|
+
console.log("Format valid:", result.formatValid);
|
|
1302
|
+
console.log("Is disposable:", result.disposable);
|
|
1303
|
+
console.log("Is role account:", result.roleAccount);
|
|
1304
|
+
console.log("MX valid:", result.mxValid);
|
|
1305
|
+
console.log("SMTP valid:", result.smtpValid);
|
|
1306
|
+
```
|
|
1307
|
+
|
|
1308
|
+
### Email Utilities
|
|
1309
|
+
|
|
1310
|
+
The package also exports standalone utility functions that can be used independently:
|
|
1311
|
+
|
|
1312
|
+
#### Email Validation
|
|
1313
|
+
|
|
1314
|
+
```typescript
|
|
1315
|
+
import { validateEmail } from "@visulima/email/validation/validate-email";
|
|
1316
|
+
|
|
1317
|
+
if (validateEmail("user@example.com")) {
|
|
1318
|
+
console.log("Valid email!");
|
|
1319
|
+
}
|
|
1320
|
+
```
|
|
1321
|
+
|
|
1322
|
+
#### Parse Email Address
|
|
1323
|
+
|
|
1324
|
+
```typescript
|
|
1325
|
+
import { parseAddress } from "@visulima/email/utils/parse-address";
|
|
1326
|
+
|
|
1327
|
+
// Parse email with name
|
|
1328
|
+
const address = parseAddress("John Doe <john@example.com>");
|
|
1329
|
+
// { name: "John Doe", email: "john@example.com" }
|
|
1330
|
+
|
|
1331
|
+
// Parse email without name
|
|
1332
|
+
const simple = parseAddress("jane@example.com");
|
|
1333
|
+
// { email: "jane@example.com" }
|
|
1334
|
+
```
|
|
1335
|
+
|
|
1336
|
+
#### Format Email Address
|
|
1337
|
+
|
|
1338
|
+
```typescript
|
|
1339
|
+
import { formatEmailAddress } from "@visulima/email/utils/format-email-address";
|
|
1340
|
+
|
|
1341
|
+
const formatted = formatEmailAddress({
|
|
1342
|
+
email: "user@example.com",
|
|
1343
|
+
name: "John Doe",
|
|
1344
|
+
});
|
|
1345
|
+
// "John Doe <user@example.com>"
|
|
1346
|
+
|
|
1347
|
+
const simple = formatEmailAddress({ email: "user@example.com" });
|
|
1348
|
+
// "user@example.com"
|
|
1349
|
+
```
|
|
1350
|
+
|
|
1351
|
+
#### Normalize Email Aliases
|
|
1352
|
+
|
|
1353
|
+
Normalize email aliases for supported providers (Gmail, Yahoo, Outlook, etc.):
|
|
1354
|
+
|
|
1355
|
+
```typescript
|
|
1356
|
+
import { normalizeEmailAliases } from "@visulima/email/utils/normalize-email-aliases";
|
|
1357
|
+
|
|
1358
|
+
// Gmail: removes dots and plus aliases
|
|
1359
|
+
normalizeEmailAliases("example+test@gmail.com"); // "example@gmail.com"
|
|
1360
|
+
normalizeEmailAliases("ex.ample@gmail.com"); // "example@gmail.com"
|
|
1361
|
+
|
|
1362
|
+
// Yahoo, Outlook, FastMail, Mail.com, GMX, etc.: removes plus aliases only
|
|
1363
|
+
normalizeEmailAliases("user+tag@yahoo.com"); // "user@yahoo.com"
|
|
1364
|
+
normalizeEmailAliases("user.name@yahoo.com"); // "user.name@yahoo.com" (dots preserved)
|
|
1365
|
+
normalizeEmailAliases("user+tag@fastmail.com"); // "user@fastmail.com"
|
|
1366
|
+
normalizeEmailAliases("user+tag@mail.com"); // "user@mail.com"
|
|
1367
|
+
normalizeEmailAliases("user+tag@gmx.com"); // "user@gmx.com"
|
|
1368
|
+
|
|
1369
|
+
// Unsupported domains return unchanged
|
|
1370
|
+
normalizeEmailAliases("user@example.com"); // "user@example.com"
|
|
1371
|
+
```
|
|
1372
|
+
|
|
1057
1373
|
## Related
|
|
1058
1374
|
|
|
1059
1375
|
## Supported Node.js Versions
|
|
@@ -1082,3 +1398,4 @@ The visulima email is open-sourced software licensed under the [MIT][license-url
|
|
|
1082
1398
|
[license-url]: LICENSE.md "license"
|
|
1083
1399
|
[npm-image]: https://img.shields.io/npm/v/@visulima/email/latest.svg?style=for-the-badge&logo=npm
|
|
1084
1400
|
[npm-url]: https://www.npmjs.com/package/@visulima/email/v/latest "npm"
|
|
1401
|
+
````
|
package/dist/crypto/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{DkimSigner as m,createDkimSigner as i}from"../packem_shared/DkimSigner-
|
|
1
|
+
import{DkimSigner as m,createDkimSigner as i}from"../packem_shared/DkimSigner-pFd4c3fZ.js";import{SmimeEncrypter as S,createSmimeEncrypter as n}from"../packem_shared/SmimeEncrypter-CBevU534.js";import{SmimeSigner as c,createSmimeSigner as p}from"../packem_shared/SmimeSigner-CObA4jzT.js";export{m as DkimSigner,S as SmimeEncrypter,c as SmimeSigner,i as createDkimSigner,n as createSmimeEncrypter,p as createSmimeSigner};
|