@visulima/email 1.0.0-alpha.1 → 1.0.0-alpha.3

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.
Files changed (142) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/README.md +408 -72
  3. package/dist/crypto/index.js +1 -1
  4. package/dist/draft-mail-message.d.ts +13 -0
  5. package/dist/index.d.ts +3 -16
  6. package/dist/index.js +1 -1
  7. package/dist/mail-message.d.ts +425 -0
  8. package/dist/mail.d.ts +124 -275
  9. package/dist/packem_shared/{DkimSigner-Z8D4Il10.js → DkimSigner-BrJfmMey.js} +1 -1
  10. package/dist/packem_shared/Mail-CC7Oh--8.js +1 -0
  11. package/dist/packem_shared/MailMessage-n7kyh9vB.js +1 -0
  12. package/dist/packem_shared/{SmimeEncrypter-CBevU534.js → SmimeEncrypter-CtvWNS8B.js} +1 -1
  13. package/dist/packem_shared/{SmimeSigner-02aXVi90.js → SmimeSigner-DZ1hSOM3.js} +1 -1
  14. package/dist/packem_shared/ahaSendProvider-DlFKEQ6D.js +1 -0
  15. package/dist/packem_shared/{awsSesProvider-CkuFOzb0.js → awsSesProvider-Ba-eVJxZ.js} +6 -6
  16. package/dist/packem_shared/azureProvider-CQYAkgVF.js +1 -0
  17. package/dist/packem_shared/brevoProvider-5p6jjiK9.js +1 -0
  18. package/dist/packem_shared/build-mime-message-IYaUqqPJ.js +2 -0
  19. package/dist/packem_shared/create-logger-BiWdqFNg.js +1 -0
  20. package/dist/packem_shared/{detectMimeType-S8WRsNtY.js → detectMimeType-CrDG3LaZ.js} +1 -1
  21. package/dist/packem_shared/failoverProvider-CAHQQueo.js +1 -0
  22. package/dist/packem_shared/{generateBoundary-CZ8kJuY6.js → generate-boundary-Cx8nXYS0.js} +1 -1
  23. package/dist/packem_shared/{generateMessageId-11Ls5JsR.js → generate-message-id-D4uA8gkj.js} +1 -1
  24. package/dist/packem_shared/headers-to-record-Qo124ImV.js +1 -0
  25. package/dist/packem_shared/httpProvider-CZD6LZX3.js +1 -0
  26. package/dist/packem_shared/infobipProvider-CtLwrUaP.js +1 -0
  27. package/dist/packem_shared/{mailCrabProvider-BEwRjB3F.js → mailCrabProvider-CM_CFDca.js} +1 -1
  28. package/dist/packem_shared/mailPaceProvider-B6yKvh6z.js +1 -0
  29. package/dist/packem_shared/mailerSendProvider-CeeIXFnW.js +1 -0
  30. package/dist/packem_shared/mailgunProvider-mmjKzouh.js +1 -0
  31. package/dist/packem_shared/mailjetProvider-DwN6i0VA.js +1 -0
  32. package/dist/packem_shared/mailomatProvider-DMQmjKHT.js +1 -0
  33. package/dist/packem_shared/mailtrapProvider-BN3UBEQw.js +1 -0
  34. package/dist/packem_shared/{makeRequest-DwxHX0xo.js → make-request-BDzF9W9D.js} +1 -1
  35. package/dist/packem_shared/mandrillProvider-370y7CLu.js +1 -0
  36. package/dist/packem_shared/mockProvider-DN5ZwutD.js +1 -0
  37. package/dist/packem_shared/nodemailerProvider-_w8QXMU-.js +1 -0
  38. package/dist/packem_shared/opentelemetryProvider-C_ZXOLSd.js +1 -0
  39. package/dist/packem_shared/plunkProvider-DfJumQ4U.js +1 -0
  40. package/dist/packem_shared/postalProvider-Bavx2FcH.js +1 -0
  41. package/dist/packem_shared/postmarkProvider-DFC0uvjO.js +1 -0
  42. package/dist/packem_shared/provider-base-Cmzx6BTO.js +1 -0
  43. package/dist/packem_shared/readFile-BlZxbhCU-C8Z4K-ib.js +1 -0
  44. package/dist/packem_shared/resendProvider-CfqU7UdE.js +1 -0
  45. package/dist/packem_shared/roundRobinProvider-1WQnuKR8.js +1 -0
  46. package/dist/packem_shared/scalewayProvider-be1HPimL.js +1 -0
  47. package/dist/packem_shared/sendGridProvider-BVI1sq3n.js +1 -0
  48. package/dist/packem_shared/smtpProvider-BV-ufR53.js +23 -0
  49. package/dist/packem_shared/sweegoProvider-7419CSAq.js +1 -0
  50. package/dist/packem_shared/validate-email-options-DfJ7llf8.js +1 -0
  51. package/dist/packem_shared/zeptomailProvider-C2lh0Xmo.js +1 -0
  52. package/dist/providers/ahasend/index.js +1 -1
  53. package/dist/providers/aws-ses/index.js +1 -1
  54. package/dist/providers/azure/index.js +1 -1
  55. package/dist/providers/brevo/index.js +1 -1
  56. package/dist/providers/brevo/types.d.ts +10 -3
  57. package/dist/providers/failover/index.js +1 -1
  58. package/dist/providers/http/index.js +1 -1
  59. package/dist/providers/infobip/index.js +1 -1
  60. package/dist/providers/mailcrab/index.js +1 -1
  61. package/dist/providers/mailersend/index.js +1 -1
  62. package/dist/providers/mailgun/index.js +1 -1
  63. package/dist/providers/mailjet/index.js +1 -1
  64. package/dist/providers/mailomat/index.js +1 -1
  65. package/dist/providers/mailpace/index.js +1 -1
  66. package/dist/providers/mailtrap/index.js +1 -1
  67. package/dist/providers/mandrill/index.js +1 -1
  68. package/dist/providers/mock/index.js +1 -1
  69. package/dist/providers/nodemailer/index.js +1 -1
  70. package/dist/providers/opentelemetry/index.js +1 -1
  71. package/dist/providers/plunk/index.js +1 -1
  72. package/dist/providers/postal/index.js +1 -1
  73. package/dist/providers/postmark/index.js +1 -1
  74. package/dist/providers/resend/index.js +1 -1
  75. package/dist/providers/roundrobin/index.js +1 -1
  76. package/dist/providers/scaleway/index.js +1 -1
  77. package/dist/providers/sendgrid/index.js +1 -1
  78. package/dist/providers/smtp/index.js +1 -1
  79. package/dist/providers/sweego/index.js +1 -1
  80. package/dist/providers/zeptomail/index.js +1 -1
  81. package/dist/types.d.ts +18 -0
  82. package/dist/utils/cache.d.ts +54 -0
  83. package/dist/utils/cache.js +1 -0
  84. package/dist/utils/create-logger.d.ts +2 -4
  85. package/dist/utils/format-email-address.js +1 -0
  86. package/dist/utils/normalize-email-aliases.d.ts +22 -0
  87. package/dist/utils/normalize-email-aliases.js +1 -0
  88. package/dist/utils/parse-address.js +1 -0
  89. package/dist/utils/validation/check-mx-records.d.ts +42 -0
  90. package/dist/utils/validation/check-mx-records.js +1 -0
  91. package/dist/utils/validation/disposable-email-domains.d.ts +13 -0
  92. package/dist/utils/validation/disposable-email-domains.js +1 -0
  93. package/dist/utils/validation/role-accounts.d.ts +21 -0
  94. package/dist/utils/validation/role-accounts.js +1 -0
  95. package/dist/utils/{validate-email-options.d.ts → validation/validate-email-options.d.ts} +1 -1
  96. package/dist/utils/validation/verify-email.d.ts +47 -0
  97. package/dist/utils/validation/verify-email.js +1 -0
  98. package/dist/utils/validation/verify-smtp.d.ts +39 -0
  99. package/dist/utils/validation/verify-smtp.js +4 -0
  100. package/package.json +49 -3
  101. package/dist/packem_shared/MailMessage-Hdgowmvi.js +0 -1
  102. package/dist/packem_shared/ahaSendProvider-NUD_kwyT.js +0 -1
  103. package/dist/packem_shared/azureProvider-Ckdrpmw9.js +0 -1
  104. package/dist/packem_shared/brevoProvider-CB3IYW4n.js +0 -1
  105. package/dist/packem_shared/buildMimeMessage-BPtd0pno.js +0 -2
  106. package/dist/packem_shared/comparePriority-BfiwjVsV.js +0 -1
  107. package/dist/packem_shared/createLogger-DlElSVQP.js +0 -1
  108. package/dist/packem_shared/failoverProvider-sam9n1AG.js +0 -1
  109. package/dist/packem_shared/formatEmailAddress-CHeME3Vk.js +0 -1
  110. package/dist/packem_shared/formatEmailAddresses-UegVOe5A.js +0 -1
  111. package/dist/packem_shared/headersToRecord-BKUTr40L.js +0 -1
  112. package/dist/packem_shared/httpProvider-BhN0RrK-.js +0 -1
  113. package/dist/packem_shared/infobipProvider-D8vYTHV4.js +0 -1
  114. package/dist/packem_shared/isPortAvailable-5kfsfo8u.js +0 -1
  115. package/dist/packem_shared/mailPaceProvider-C47Izgaj.js +0 -1
  116. package/dist/packem_shared/mailerSendProvider-C4uAo-fc.js +0 -1
  117. package/dist/packem_shared/mailgunProvider-B7upu_OV.js +0 -1
  118. package/dist/packem_shared/mailjetProvider-ReErm08u.js +0 -1
  119. package/dist/packem_shared/mailomatProvider-OlCT_O2i.js +0 -1
  120. package/dist/packem_shared/mailtrapProvider-hVMV3h6r.js +0 -1
  121. package/dist/packem_shared/mandrillProvider-DdnbkHZI.js +0 -1
  122. package/dist/packem_shared/mockProvider-BDWZJpea.js +0 -1
  123. package/dist/packem_shared/nodemailerProvider-BV21eRGX.js +0 -1
  124. package/dist/packem_shared/opentelemetryProvider-kAz62mKm.js +0 -1
  125. package/dist/packem_shared/parseAddress-CATTKGe_.js +0 -1
  126. package/dist/packem_shared/plunkProvider-Bs6K51lT.js +0 -1
  127. package/dist/packem_shared/postalProvider-Bcsxp-z6.js +0 -1
  128. package/dist/packem_shared/postmarkProvider-BUq3wuYD.js +0 -1
  129. package/dist/packem_shared/provider-base-_hbWXBdK.js +0 -1
  130. package/dist/packem_shared/readFile-BlZxbhCU-C8bCdiA2.js +0 -1
  131. package/dist/packem_shared/resendProvider-D-_HQpN_.js +0 -1
  132. package/dist/packem_shared/retry-D1MBqS49.js +0 -1
  133. package/dist/packem_shared/roundRobinProvider-CejLM1rZ.js +0 -1
  134. package/dist/packem_shared/scalewayProvider-1n6ePiGl.js +0 -1
  135. package/dist/packem_shared/sendGridProvider-B1T62dyX.js +0 -1
  136. package/dist/packem_shared/smtpProvider-CcAoRrkt.js +0 -23
  137. package/dist/packem_shared/sweegoProvider-CxFmEUh6.js +0 -1
  138. package/dist/packem_shared/validateEmailOptions-BzlJECG5.js +0 -1
  139. package/dist/packem_shared/zeptomailProvider-CWYQPAJk.js +0 -1
  140. package/dist/utils/compare-priority.d.ts +0 -16
  141. /package/dist/utils/{validate-email.d.ts → validation/validate-email.d.ts} +0 -0
  142. /package/dist/{packem_shared/validateEmail-BkVdVioP.js → utils/validation/validate-email.js} +0 -0
package/README.md CHANGED
@@ -1,15 +1,24 @@
1
- <div align="center">
2
- <h3>visulima email</h3>
3
- <p>
4
- Email sending package with multiple provider support
5
- </p>
6
- </div>
1
+ <!-- START_PACKAGE_OG_IMAGE_PLACEHOLDER -->
2
+
3
+ <a href="https://www.anolilab.com/open-source" align="center">
4
+
5
+ <img src="__assets__/package-og.svg" alt="email" />
6
+
7
+ </a>
8
+
9
+ <h3 align="center">A comprehensive email library with multi-provider support, crypto utilities, and template engines</h3>
10
+
11
+ <!-- END_PACKAGE_OG_IMAGE_PLACEHOLDER -->
7
12
 
8
13
  <br />
9
14
 
10
15
  <div align="center">
11
16
 
12
- [![typescript-image]][typescript-url] [![npm-image]][npm-url] [![license-image]][license-url]
17
+ [![typescript-image][typescript-badge]][typescript-url]
18
+ [![mit licence][license-badge]][license]
19
+ [![npm downloads][npm-downloads-badge]][npm-downloads]
20
+ [![Chat][chat-badge]][chat]
21
+ [![PRs Welcome][prs-welcome-badge]][prs-welcome]
13
22
 
14
23
  </div>
15
24
 
@@ -44,7 +53,7 @@ pnpm add @visulima/email
44
53
  ### Basic Usage
45
54
 
46
55
  ```typescript
47
- import { createMail, resendProvider } from "@visulima/email";
56
+ import { createMail, MailMessage, resendProvider } from "@visulima/email";
48
57
 
49
58
  // Create a provider
50
59
  const resend = resendProvider({
@@ -54,18 +63,82 @@ const resend = resendProvider({
54
63
  // Create a Mail instance
55
64
  const mail = createMail(resend);
56
65
 
66
+ // Optional: Set default configuration for all emails
67
+ mail.setFrom({ email: "noreply@example.com", name: "My App" });
68
+
57
69
  // Send an email using the message builder
58
- const result = await mail.message().to("user@example.com").from("sender@example.com").subject("Hello").html("<h1>Hello World</h1>").send();
70
+ const message = new MailMessage()
71
+ .to("user@example.com")
72
+ // .from() is optional if set via mail.setFrom()
73
+ .subject("Hello")
74
+ .html("<h1>Hello World</h1>");
75
+
76
+ const result = await mail.send(message);
59
77
 
60
78
  if (result.success) {
61
79
  console.log("Email sent:", result.data?.messageId);
62
80
  }
63
81
  ```
64
82
 
83
+ ### Default Configuration
84
+
85
+ You can configure default values for all emails sent through a Mail instance:
86
+
87
+ ```typescript
88
+ import { createMail, MailMessage, resendProvider } from "@visulima/email";
89
+
90
+ const mail = createMail(resendProvider({ apiKey: "re_xxx" }));
91
+
92
+ // Set default from address
93
+ mail.setFrom({ email: "noreply@example.com", name: "My App" });
94
+
95
+ // Set default reply-to address
96
+ mail.setReplyTo({ email: "support@example.com" });
97
+
98
+ // Set default headers
99
+ mail.setHeaders({
100
+ "X-App-Name": "MyApp",
101
+ "X-Version": "1.0.0",
102
+ });
103
+
104
+ // Or chain them together
105
+ const mail2 = createMail(resendProvider({ apiKey: "re_xxx" }))
106
+ .setFrom({ email: "noreply@example.com" })
107
+ .setReplyTo({ email: "support@example.com" })
108
+ .setHeaders({ "X-App-Name": "MyApp" });
109
+
110
+ // Now all emails will use these defaults if not specified in the message
111
+ const message = new MailMessage().to("user@example.com").subject("Hello").html("<h1>Hello World</h1>");
112
+ // No need to set .from() - it will use the default
113
+
114
+ await mail.send(message);
115
+ ```
116
+
117
+ ### Creating Draft Emails
118
+
119
+ 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:
120
+
121
+ ```typescript
122
+ import { createMail, MailMessage, resendProvider } from "@visulima/email";
123
+ import { writeFile } from "fs/promises";
124
+
125
+ const mail = createMail(resendProvider({ apiKey: "re_xxx" }));
126
+
127
+ const message = new MailMessage().to("user@example.com").from("sender@example.com").subject("Hello").html("<h1>Hello World</h1>");
128
+
129
+ // Create a draft in EML format
130
+ const eml = await mail.draft(message);
131
+
132
+ // Save to file
133
+ await writeFile("draft.eml", eml);
134
+
135
+ // EML files can be opened by email clients
136
+ ```
137
+
65
138
  ### Using Different Providers
66
139
 
67
140
  ```typescript
68
- import { createMail, smtpProvider, resendProvider } from "@visulima/email";
141
+ import { createMail, MailMessage, smtpProvider, resendProvider } from "@visulima/email";
69
142
 
70
143
  // SMTP provider
71
144
  const smtp = smtpProvider({
@@ -86,30 +159,13 @@ const smtpMail = createMail(smtp);
86
159
  const resendMail = createMail(resend);
87
160
 
88
161
  // Send via specific provider
89
- await resendMail.message().to("user@example.com").from("sender@example.com").subject("Hello").html("<h1>Hello World</h1>").send();
90
- ```
91
-
92
- ### Using Mailable Classes
162
+ const message = new MailMessage()
163
+ .to("user@example.com")
164
+ .from("sender@example.com")
165
+ .subject("Hello")
166
+ .html("<h1>Hello World</h1>");
93
167
 
94
- ```typescript
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" }));
168
+ await resendMail.send(message);
113
169
  ```
114
170
 
115
171
  ### Direct Email Sending
@@ -126,7 +182,7 @@ const emailOptions: EmailOptions = {
126
182
  html: "<h1>Hello World</h1>",
127
183
  };
128
184
 
129
- const result = await mail.sendEmail(emailOptions);
185
+ const result = await mail.send(emailOptions);
130
186
  ```
131
187
 
132
188
  ### Failover Provider
@@ -134,7 +190,7 @@ const result = await mail.sendEmail(emailOptions);
134
190
  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
191
 
136
192
  ```typescript
137
- import { createMail, failoverProvider, resendProvider, smtpProvider } from "@visulima/email";
193
+ import { createMail, MailMessage, failoverProvider, resendProvider, smtpProvider } from "@visulima/email";
138
194
 
139
195
  // Create individual providers
140
196
  const resend = resendProvider({ apiKey: "re_xxx" });
@@ -157,7 +213,9 @@ const failover = failoverProvider({
157
213
  // Use failover provider
158
214
  const mail = createMail(failover);
159
215
 
160
- const result = await mail.message().to("user@example.com").from("sender@example.com").subject("Hello").html("<h1>Hello World</h1>").send();
216
+ const message = new MailMessage().to("user@example.com").from("sender@example.com").subject("Hello").html("<h1>Hello World</h1>");
217
+
218
+ const result = await mail.send(message);
161
219
 
162
220
  // The failover provider will try Resend first, and if it fails,
163
221
  // automatically try SMTP
@@ -188,7 +246,7 @@ const failover = failoverProvider({
188
246
  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
247
 
190
248
  ```typescript
191
- import { createMail, roundRobinProvider, resendProvider, smtpProvider } from "@visulima/email";
249
+ import { createMail, MailMessage, roundRobinProvider, resendProvider, smtpProvider } from "@visulima/email";
192
250
 
193
251
  // Create individual providers
194
252
  const resend = resendProvider({ apiKey: "re_xxx" });
@@ -212,13 +270,16 @@ const roundRobin = roundRobinProvider({
212
270
  const mail = createMail(roundRobin);
213
271
 
214
272
  // Each email will be distributed across providers in rotation
215
- await mail.message().to("user1@example.com").from("sender@example.com").subject("Email 1").html("<h1>Email 1</h1>").send();
273
+ const message1 = new MailMessage().to("user1@example.com").from("sender@example.com").subject("Email 1").html("<h1>Email 1</h1>");
274
+ await mail.send(message1);
216
275
  // Uses resend (or random start)
217
276
 
218
- await mail.message().to("user2@example.com").from("sender@example.com").subject("Email 2").html("<h1>Email 2</h1>").send();
277
+ const message2 = new MailMessage().to("user2@example.com").from("sender@example.com").subject("Email 2").html("<h1>Email 2</h1>");
278
+ await mail.send(message2);
219
279
  // Uses smtp (next in rotation)
220
280
 
221
- await mail.message().to("user3@example.com").from("sender@example.com").subject("Email 3").html("<h1>Email 3</h1>").send();
281
+ const message3 = new MailMessage().to("user3@example.com").from("sender@example.com").subject("Email 3").html("<h1>Email 3</h1>");
282
+ await mail.send(message3);
222
283
  // Uses resend (back to first)
223
284
  ```
224
285
 
@@ -262,7 +323,8 @@ const mailgun = mailgunProvider({
262
323
  const mail = createMail(mailgun);
263
324
 
264
325
  // Send email with Mailgun-specific options
265
- const result = await mail.message().to("user@example.com").from("sender@example.com").subject("Welcome").html("<h1>Welcome!</h1>").send();
326
+ const message = new MailMessage().to("user@example.com").from("sender@example.com").subject("Welcome").html("<h1>Welcome!</h1>");
327
+ const result = await mail.send(message);
266
328
 
267
329
  // Or use Mailgun-specific features
268
330
  import type { MailgunEmailOptions } from "@visulima/email/providers/mailgun";
@@ -280,7 +342,7 @@ const mailgunOptions: MailgunEmailOptions = {
280
342
  deliveryTime: Math.floor(Date.now() / 1000) + 3600, // Schedule for 1 hour from now
281
343
  };
282
344
 
283
- await mail.sendEmail(mailgunOptions);
345
+ await mail.send(mailgunOptions);
284
346
  ```
285
347
 
286
348
  ### Mailjet Provider
@@ -301,7 +363,8 @@ const mailjet = mailjetProvider({
301
363
  const mail = createMail(mailjet);
302
364
 
303
365
  // Send email with Mailjet-specific options
304
- const result = await mail.message().to("user@example.com").from("sender@example.com").subject("Welcome").html("<h1>Welcome!</h1>").send();
366
+ const message = new MailMessage().to("user@example.com").from("sender@example.com").subject("Welcome").html("<h1>Welcome!</h1>");
367
+ const result = await mail.send(message);
305
368
 
306
369
  // Or use Mailjet-specific features
307
370
  import type { MailjetEmailOptions } from "@visulima/email/providers/mailjet";
@@ -320,7 +383,7 @@ const mailjetOptions: MailjetEmailOptions = {
320
383
  deliveryTime: Math.floor(Date.now() / 1000) + 3600, // Schedule for 1 hour from now
321
384
  };
322
385
 
323
- await mail.sendEmail(mailjetOptions);
386
+ await mail.send(mailjetOptions);
324
387
  ```
325
388
 
326
389
  ### MailerSend Provider
@@ -359,7 +422,7 @@ const mailerSendOptions: MailerSendEmailOptions = {
359
422
  scheduledAt: Math.floor(Date.now() / 1000) + 3600, // Schedule for 1 hour from now
360
423
  };
361
424
 
362
- await mail.sendEmail(mailerSendOptions);
425
+ await mail.send(mailerSendOptions);
363
426
  ```
364
427
 
365
428
  ### Mandrill Provider (Mailchimp Transactional)
@@ -393,7 +456,7 @@ const mandrillOptions: MandrillEmailOptions = {
393
456
  metadata: { orderId: "123" },
394
457
  };
395
458
 
396
- await mail.sendEmail(mandrillOptions);
459
+ await mail.send(mandrillOptions);
397
460
  ```
398
461
 
399
462
  ### Postal Provider
@@ -426,7 +489,7 @@ const postalOptions: PostalEmailOptions = {
426
489
  tags: ["welcome"],
427
490
  };
428
491
 
429
- await mail.sendEmail(postalOptions);
492
+ await mail.send(postalOptions);
430
493
  ```
431
494
 
432
495
  ### Mailtrap Provider
@@ -460,7 +523,7 @@ const mailtrapOptions: MailtrapEmailOptions = {
460
523
  tags: ["welcome"],
461
524
  };
462
525
 
463
- await mail.sendEmail(mailtrapOptions);
526
+ await mail.send(mailtrapOptions);
464
527
  ```
465
528
 
466
529
  ### MailPace Provider
@@ -493,7 +556,7 @@ const mailPaceOptions: MailPaceEmailOptions = {
493
556
  listUnsubscribe: "<mailto:unsubscribe@example.com>",
494
557
  };
495
558
 
496
- await mail.sendEmail(mailPaceOptions);
559
+ await mail.send(mailPaceOptions);
497
560
  ```
498
561
 
499
562
  ### Azure Communication Services Provider
@@ -530,7 +593,7 @@ const azureOptions: AzureEmailOptions = {
530
593
  importance: "high", // "normal" or "high"
531
594
  };
532
595
 
533
- await mail.sendEmail(azureOptions);
596
+ await mail.send(azureOptions);
534
597
  ```
535
598
 
536
599
  ### Infobip Provider
@@ -564,7 +627,7 @@ const infobipOptions: InfobipEmailOptions = {
564
627
  sendAt: Date.now() + 3600000, // Schedule for 1 hour from now (milliseconds)
565
628
  };
566
629
 
567
- await mail.sendEmail(infobipOptions);
630
+ await mail.send(infobipOptions);
568
631
  ```
569
632
 
570
633
  ### Scaleway Provider
@@ -596,7 +659,7 @@ const scalewayOptions: ScalewayEmailOptions = {
596
659
  projectId: "project-uuid", // Optional
597
660
  };
598
661
 
599
- await mail.sendEmail(scalewayOptions);
662
+ await mail.send(scalewayOptions);
600
663
  ```
601
664
 
602
665
  ### AhaSend Provider
@@ -628,7 +691,7 @@ const ahaSendOptions: AhaSendEmailOptions = {
628
691
  tags: ["welcome"],
629
692
  };
630
693
 
631
- await mail.sendEmail(ahaSendOptions);
694
+ await mail.send(ahaSendOptions);
632
695
  ```
633
696
 
634
697
  ### Mailomat Provider
@@ -660,7 +723,7 @@ const mailomatOptions: MailomatEmailOptions = {
660
723
  tags: ["welcome"],
661
724
  };
662
725
 
663
- await mail.sendEmail(mailomatOptions);
726
+ await mail.send(mailomatOptions);
664
727
  ```
665
728
 
666
729
  ### Sweego Provider
@@ -692,7 +755,7 @@ const sweegoOptions: SweegoEmailOptions = {
692
755
  tags: ["welcome"],
693
756
  };
694
757
 
695
- await mail.sendEmail(sweegoOptions);
758
+ await mail.send(sweegoOptions);
696
759
  ```
697
760
 
698
761
  ### Brevo Provider (formerly Sendinblue)
@@ -712,7 +775,8 @@ const brevo = brevoProvider({
712
775
  const mail = createMail(brevo);
713
776
 
714
777
  // Send email with Brevo-specific options
715
- const result = await mail.message().to("user@example.com").from("sender@example.com").subject("Welcome").html("<h1>Welcome!</h1>").send();
778
+ const message = new MailMessage().to("user@example.com").from("sender@example.com").subject("Welcome").html("<h1>Welcome!</h1>");
779
+ const result = await mail.send(message);
716
780
 
717
781
  // Or use Brevo-specific features
718
782
  import type { BrevoEmailOptions } from "@visulima/email/providers/brevo";
@@ -728,7 +792,7 @@ const brevoOptions: BrevoEmailOptions = {
728
792
  scheduledAt: Math.floor(Date.now() / 1000) + 3600, // Schedule for 1 hour from now
729
793
  };
730
794
 
731
- await mail.sendEmail(brevoOptions);
795
+ await mail.send(brevoOptions);
732
796
  ```
733
797
 
734
798
  ### Postmark Provider
@@ -748,7 +812,8 @@ const postmark = postmarkProvider({
748
812
  const mail = createMail(postmark);
749
813
 
750
814
  // Send email with Postmark-specific options
751
- const result = await mail.message().to("user@example.com").from("sender@example.com").subject("Welcome").html("<h1>Welcome!</h1>").send();
815
+ const message = new MailMessage().to("user@example.com").from("sender@example.com").subject("Welcome").html("<h1>Welcome!</h1>");
816
+ const result = await mail.send(message);
752
817
 
753
818
  // Or use Postmark-specific features
754
819
  import type { PostmarkEmailOptions } from "@visulima/email/providers/postmark";
@@ -767,7 +832,7 @@ const postmarkOptions: PostmarkEmailOptions = {
767
832
  metadata: { userId: "123" }, // Custom metadata
768
833
  };
769
834
 
770
- await mail.sendEmail(postmarkOptions);
835
+ await mail.send(postmarkOptions);
771
836
  ```
772
837
 
773
838
  ### SendGrid Provider
@@ -787,7 +852,8 @@ const sendgrid = sendGridProvider({
787
852
  const mail = createMail(sendgrid);
788
853
 
789
854
  // Send email with SendGrid-specific options
790
- const result = await mail.message().to("user@example.com").from("sender@example.com").subject("Welcome").html("<h1>Welcome!</h1>").send();
855
+ const message = new MailMessage().to("user@example.com").from("sender@example.com").subject("Welcome").html("<h1>Welcome!</h1>");
856
+ const result = await mail.send(message);
791
857
 
792
858
  // Or use SendGrid-specific features
793
859
  import type { SendGridEmailOptions } from "@visulima/email/providers/sendgrid";
@@ -807,7 +873,7 @@ const sendGridOptions: SendGridEmailOptions = {
807
873
  },
808
874
  };
809
875
 
810
- await mail.sendEmail(sendGridOptions);
876
+ await mail.send(sendGridOptions);
811
877
  ```
812
878
 
813
879
  ### Plunk Provider
@@ -827,7 +893,8 @@ const plunk = plunkProvider({
827
893
  const mail = createMail(plunk);
828
894
 
829
895
  // Send email with Plunk-specific options
830
- const result = await mail.message().to("user@example.com").from("sender@example.com").subject("Welcome").html("<h1>Welcome!</h1>").send();
896
+ const message = new MailMessage().to("user@example.com").from("sender@example.com").subject("Welcome").html("<h1>Welcome!</h1>");
897
+ const result = await mail.send(message);
831
898
 
832
899
  // Or use Plunk-specific features
833
900
  import type { PlunkEmailOptions } from "@visulima/email/providers/plunk";
@@ -843,7 +910,7 @@ const plunkOptions: PlunkEmailOptions = {
843
910
  data: { name: "John" }, // Template data
844
911
  };
845
912
 
846
- await mail.sendEmail(plunkOptions);
913
+ await mail.send(plunkOptions);
847
914
  ```
848
915
 
849
916
  ### Mock Provider (for Testing)
@@ -864,7 +931,8 @@ const mock = mockProvider({
864
931
  const mail = createMail(mock);
865
932
 
866
933
  // Send email (stored in memory)
867
- const result = await mail.message().to("user@example.com").from("sender@example.com").subject("Test").html("<h1>Test</h1>").send();
934
+ const message = new MailMessage().to("user@example.com").from("sender@example.com").subject("Test").html("<h1>Test</h1>");
935
+ const result = await mail.send(message);
868
936
 
869
937
  // Access stored emails
870
938
  const sentEmails = mock.getSentEmails();
@@ -931,7 +999,8 @@ const customMailCrab = mailCrabProvider({
931
999
  // Use MailCrab provider
932
1000
  const mail = createMail(mailCrab);
933
1001
 
934
- const result = await mail.message().to("user@example.com").from("sender@example.com").subject("Test Email").html("<h1>Test</h1>").send();
1002
+ const message = new MailMessage().to("user@example.com").from("sender@example.com").subject("Test Email").html("<h1>Test</h1>");
1003
+ const result = await mail.send(message);
935
1004
  ```
936
1005
 
937
1006
  **Note:** Make sure MailCrab is running locally before using this provider. MailCrab can be installed via Docker or as a standalone application.
@@ -1054,6 +1123,263 @@ Template engines are optional peer dependencies and work where their underlying
1054
1123
 
1055
1124
  \* Runtime support depends on the wrapped providers. Works if all wrapped providers support the runtime.
1056
1125
 
1126
+ ## Disposable Email Detection
1127
+
1128
+ The package includes support for detecting disposable email addresses using the `@visulima/disposable-email-domains` package, which is included as a dependency.
1129
+
1130
+ ### Usage
1131
+
1132
+ ```typescript
1133
+ import { isDisposableEmail } from "@visulima/email/validation/disposable-email-domains";
1134
+
1135
+ // Check if an email is disposable
1136
+ if (isDisposableEmail("user@mailinator.com")) {
1137
+ console.log("Disposable email detected!");
1138
+ }
1139
+
1140
+ // With custom domains
1141
+ const customDomains = new Set(["my-disposable.com"]);
1142
+ if (isDisposableEmail("user@my-disposable.com", customDomains)) {
1143
+ console.log("Custom disposable email detected!");
1144
+ }
1145
+ ```
1146
+
1147
+ **Note:** The `@visulima/disposable-email-domains` package is included as a dependency, so no additional installation is required.
1148
+
1149
+ ## Email Verification
1150
+
1151
+ The package provides comprehensive email verification utilities including MX record checking, SMTP verification, and role account detection.
1152
+
1153
+ ### MX Record Checking
1154
+
1155
+ Check if a domain has valid MX (Mail Exchange) records:
1156
+
1157
+ ```typescript
1158
+ import { checkMxRecords } from "@visulima/email/validation/check-mx-records";
1159
+
1160
+ const result = await checkMxRecords("example.com");
1161
+
1162
+ if (result.valid) {
1163
+ console.log("MX records:", result.records);
1164
+ // Records are sorted by priority (lowest first)
1165
+ } else {
1166
+ console.error("No MX records found:", result.error);
1167
+ }
1168
+ ```
1169
+
1170
+ #### Caching MX Records
1171
+
1172
+ Use caching to improve performance and reduce DNS lookups:
1173
+
1174
+ ```typescript
1175
+ import { checkMxRecords } from "@visulima/email/validation/check-mx-records";
1176
+ import { InMemoryCache } from "@visulima/email/utils/cache";
1177
+
1178
+ // Create a cache instance
1179
+ const cache = new InMemoryCache();
1180
+
1181
+ // Use cache with default TTL (1 hour)
1182
+ const result1 = await checkMxRecords("example.com", { cache });
1183
+
1184
+ // Use cache with custom TTL (5 minutes)
1185
+ const result2 = await checkMxRecords("example.com", {
1186
+ cache,
1187
+ ttl: 5 * 60 * 1000, // 5 minutes in milliseconds
1188
+ });
1189
+
1190
+ // Clear cache when needed
1191
+ await cache.clear();
1192
+ ```
1193
+
1194
+ #### Custom Cache Implementation
1195
+
1196
+ You can implement your own cache using the `Cache` interface (e.g., for Redis, LRU cache, etc.):
1197
+
1198
+ ```typescript
1199
+ import type { Cache, MxCheckResult } from "@visulima/email/utils/cache";
1200
+ import { checkMxRecords } from "@visulima/email/validation/check-mx-records";
1201
+
1202
+ // Example: Custom Redis cache implementation
1203
+ const redisCache: Cache<MxCheckResult> = {
1204
+ get: async (key: string) => {
1205
+ const cached = await redis.get(`mx:${key}`);
1206
+ return cached ? JSON.parse(cached) : undefined;
1207
+ },
1208
+ set: async (key: string, value: MxCheckResult, ttl: number) => {
1209
+ await redis.setex(`mx:${key}`, Math.floor(ttl / 1000), JSON.stringify(value));
1210
+ },
1211
+ delete: async (key: string) => {
1212
+ await redis.del(`mx:${key}`);
1213
+ },
1214
+ clear: async () => {
1215
+ // Clear all MX cache keys
1216
+ const keys = await redis.keys("mx:*");
1217
+ if (keys.length > 0) {
1218
+ await redis.del(...keys);
1219
+ }
1220
+ },
1221
+ };
1222
+
1223
+ // Use custom cache
1224
+ const result = await checkMxRecords("example.com", {
1225
+ cache: redisCache,
1226
+ ttl: 10 * 60 * 1000, // 10 minutes
1227
+ });
1228
+ ```
1229
+
1230
+ ### Role Account Detection
1231
+
1232
+ Detect if an email address is a role account (non-personal email like `noreply@`, `support@`, etc.):
1233
+
1234
+ ```typescript
1235
+ import { isRoleAccount } from "@visulima/email/validation/role-accounts";
1236
+
1237
+ if (isRoleAccount("noreply@example.com")) {
1238
+ console.log("This is a role account");
1239
+ }
1240
+
1241
+ // With custom role prefixes
1242
+ const customPrefixes = new Set(["custom-role", "my-role"]);
1243
+ if (isRoleAccount("custom-role@example.com", customPrefixes)) {
1244
+ console.log("Custom role account detected");
1245
+ }
1246
+ ```
1247
+
1248
+ ### SMTP Verification
1249
+
1250
+ Verify if an email address exists by connecting to the mail server:
1251
+
1252
+ ```typescript
1253
+ import { verifySmtp } from "@visulima/email/validation/verify-smtp";
1254
+ import { InMemoryCache } from "@visulima/email/utils/cache";
1255
+ import type { MxCheckResult, SmtpVerificationResult } from "@visulima/email/validation/check-mx-records";
1256
+
1257
+ // Create separate caches for MX records and SMTP results
1258
+ const mxCache = new InMemoryCache<MxCheckResult>();
1259
+ const smtpCache = new InMemoryCache<SmtpVerificationResult>();
1260
+
1261
+ const result = await verifySmtp("user@example.com", {
1262
+ timeout: 5000,
1263
+ fromEmail: "test@example.com",
1264
+ port: 25,
1265
+ cache: mxCache, // Optional: cache MX records
1266
+ smtpCache, // Optional: cache SMTP verification results
1267
+ ttl: 5 * 60 * 1000, // Cache for 5 minutes
1268
+ });
1269
+
1270
+ if (result.valid) {
1271
+ console.log("Email address exists");
1272
+ } else {
1273
+ console.error("Verification failed:", result.error);
1274
+ }
1275
+ ```
1276
+
1277
+ **Note:** Many mail servers block SMTP verification to prevent email harvesting. This method may not work for all domains.
1278
+
1279
+ ### Comprehensive Email Verification
1280
+
1281
+ Combine all verification checks in a single function:
1282
+
1283
+ ```typescript
1284
+ import { verifyEmail } from "@visulima/email/validation/verify-email";
1285
+ import { InMemoryCache } from "@visulima/email/utils/cache";
1286
+ import type { MxCheckResult, SmtpVerificationResult } from "@visulima/email/validation/check-mx-records";
1287
+
1288
+ // Create separate caches for MX records and SMTP results
1289
+ const mxCache = new InMemoryCache<MxCheckResult>();
1290
+ const smtpCache = new InMemoryCache<SmtpVerificationResult>();
1291
+
1292
+ const result = await verifyEmail("user@example.com", {
1293
+ checkDisposable: true,
1294
+ checkRoleAccount: true,
1295
+ checkMx: true,
1296
+ checkSmtp: false, // Optional, many servers block this
1297
+ cache: mxCache, // Optional: cache MX records
1298
+ smtpCache, // Optional: cache SMTP verification results
1299
+ customDisposableDomains: new Set(["custom-disposable.com"]),
1300
+ customRolePrefixes: new Set(["custom-role"]),
1301
+ });
1302
+
1303
+ if (result.valid) {
1304
+ console.log("Email is valid!");
1305
+ } else {
1306
+ console.error("Errors:", result.errors);
1307
+ console.warn("Warnings:", result.warnings);
1308
+ }
1309
+
1310
+ // Access individual check results
1311
+ console.log("Format valid:", result.formatValid);
1312
+ console.log("Is disposable:", result.disposable);
1313
+ console.log("Is role account:", result.roleAccount);
1314
+ console.log("MX valid:", result.mxValid);
1315
+ console.log("SMTP valid:", result.smtpValid);
1316
+ ```
1317
+
1318
+ ### Email Utilities
1319
+
1320
+ The package also exports standalone utility functions that can be used independently:
1321
+
1322
+ #### Email Validation
1323
+
1324
+ ```typescript
1325
+ import { validateEmail } from "@visulima/email/validation/validate-email";
1326
+
1327
+ if (validateEmail("user@example.com")) {
1328
+ console.log("Valid email!");
1329
+ }
1330
+ ```
1331
+
1332
+ #### Parse Email Address
1333
+
1334
+ ```typescript
1335
+ import { parseAddress } from "@visulima/email/utils/parse-address";
1336
+
1337
+ // Parse email with name
1338
+ const address = parseAddress("John Doe <john@example.com>");
1339
+ // { name: "John Doe", email: "john@example.com" }
1340
+
1341
+ // Parse email without name
1342
+ const simple = parseAddress("jane@example.com");
1343
+ // { email: "jane@example.com" }
1344
+ ```
1345
+
1346
+ #### Format Email Address
1347
+
1348
+ ```typescript
1349
+ import { formatEmailAddress } from "@visulima/email/utils/format-email-address";
1350
+
1351
+ const formatted = formatEmailAddress({
1352
+ email: "user@example.com",
1353
+ name: "John Doe",
1354
+ });
1355
+ // "John Doe <user@example.com>"
1356
+
1357
+ const simple = formatEmailAddress({ email: "user@example.com" });
1358
+ // "user@example.com"
1359
+ ```
1360
+
1361
+ #### Normalize Email Aliases
1362
+
1363
+ Normalize email aliases for supported providers (Gmail, Yahoo, Outlook, etc.):
1364
+
1365
+ ```typescript
1366
+ import { normalizeEmailAliases } from "@visulima/email/utils/normalize-email-aliases";
1367
+
1368
+ // Gmail: removes dots and plus aliases
1369
+ normalizeEmailAliases("example+test@gmail.com"); // "example@gmail.com"
1370
+ normalizeEmailAliases("ex.ample@gmail.com"); // "example@gmail.com"
1371
+
1372
+ // Yahoo, Outlook, FastMail, Mail.com, GMX, etc.: removes plus aliases only
1373
+ normalizeEmailAliases("user+tag@yahoo.com"); // "user@yahoo.com"
1374
+ normalizeEmailAliases("user.name@yahoo.com"); // "user.name@yahoo.com" (dots preserved)
1375
+ normalizeEmailAliases("user+tag@fastmail.com"); // "user@fastmail.com"
1376
+ normalizeEmailAliases("user+tag@mail.com"); // "user@mail.com"
1377
+ normalizeEmailAliases("user+tag@gmx.com"); // "user@gmx.com"
1378
+
1379
+ // Unsupported domains return unchanged
1380
+ normalizeEmailAliases("user@example.com"); // "user@example.com"
1381
+ ```
1382
+
1057
1383
  ## Related
1058
1384
 
1059
1385
  ## Supported Node.js Versions
@@ -1072,13 +1398,23 @@ If you would like to help take a look at the [list of issues](https://github.com
1072
1398
  - [Daniel Bannert](https://github.com/prisis)
1073
1399
  - [All Contributors](https://github.com/visulima/visulima/graphs/contributors)
1074
1400
 
1401
+ ## Made with ❤️ at Anolilab
1402
+
1403
+ This is an open source project and will always remain free to use. If you think it's cool, please star it 🌟. [Anolilab](https://www.anolilab.com/open-source) is a Development and AI Studio. Contact us at [hello@anolilab.com](mailto:hello@anolilab.com) if you need any help with these technologies or just want to say hi!
1404
+
1075
1405
  ## License
1076
1406
 
1077
- The visulima email is open-sourced software licensed under the [MIT][license-url]
1407
+ The visulima email is open-sourced software licensed under the [MIT][license]
1408
+
1409
+ <!-- badges -->
1078
1410
 
1079
- [typescript-image]: https://img.shields.io/badge/Typescript-294E80.svg?style=for-the-badge&logo=typescript
1080
- [typescript-url]: https://www.typescriptlang.org/ "TypeScript"
1081
- [license-image]: https://img.shields.io/npm/l/@visulima/email?color=blueviolet&style=for-the-badge
1082
- [license-url]: LICENSE.md "license"
1083
- [npm-image]: https://img.shields.io/npm/v/@visulima/email/latest.svg?style=for-the-badge&logo=npm
1084
- [npm-url]: https://www.npmjs.com/package/@visulima/email/v/latest "npm"
1411
+ [license-badge]: https://img.shields.io/npm/l/@visulima/email?style=for-the-badge
1412
+ [license]: https://github.com/visulima/visulima/blob/main/LICENSE
1413
+ [npm-downloads-badge]: https://img.shields.io/npm/dm/@visulima/email?style=for-the-badge
1414
+ [npm-downloads]: https://www.npmjs.com/package/@visulima/email
1415
+ [prs-welcome-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=for-the-badge
1416
+ [prs-welcome]: https://github.com/visulima/visulima/blob/main/.github/CONTRIBUTING.md
1417
+ [chat-badge]: https://img.shields.io/discord/932323359193186354.svg?style=for-the-badge
1418
+ [chat]: https://discord.gg/TtFJY8xkFK
1419
+ [typescript-badge]: https://img.shields.io/badge/Typescript-294E80.svg?style=for-the-badge&logo=typescript
1420
+ [typescript-url]: https://www.typescriptlang.org/