@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.
Files changed (138) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +377 -60
  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-pFd4c3fZ.js} +1 -1
  10. package/dist/packem_shared/Mail-6Bltpy_p.js +1 -0
  11. package/dist/packem_shared/MailMessage-B76GPBBA.js +1 -0
  12. package/dist/packem_shared/{SmimeSigner-02aXVi90.js → SmimeSigner-CObA4jzT.js} +1 -1
  13. package/dist/packem_shared/ahaSendProvider-DlFKEQ6D.js +1 -0
  14. package/dist/packem_shared/{awsSesProvider-CkuFOzb0.js → awsSesProvider-Ba-eVJxZ.js} +6 -6
  15. package/dist/packem_shared/azureProvider-CQYAkgVF.js +1 -0
  16. package/dist/packem_shared/brevoProvider-5p6jjiK9.js +1 -0
  17. package/dist/packem_shared/build-mime-message-IYaUqqPJ.js +2 -0
  18. package/dist/packem_shared/create-logger-BiWdqFNg.js +1 -0
  19. package/dist/packem_shared/failoverProvider-CAHQQueo.js +1 -0
  20. package/dist/packem_shared/{generateBoundary-CZ8kJuY6.js → generate-boundary-Cx8nXYS0.js} +1 -1
  21. package/dist/packem_shared/{generateMessageId-11Ls5JsR.js → generate-message-id-D4uA8gkj.js} +1 -1
  22. package/dist/packem_shared/headers-to-record-Qo124ImV.js +1 -0
  23. package/dist/packem_shared/httpProvider-CZD6LZX3.js +1 -0
  24. package/dist/packem_shared/infobipProvider-CtLwrUaP.js +1 -0
  25. package/dist/packem_shared/{mailCrabProvider-BEwRjB3F.js → mailCrabProvider-CM_CFDca.js} +1 -1
  26. package/dist/packem_shared/mailPaceProvider-B6yKvh6z.js +1 -0
  27. package/dist/packem_shared/mailerSendProvider-CeeIXFnW.js +1 -0
  28. package/dist/packem_shared/mailgunProvider-mmjKzouh.js +1 -0
  29. package/dist/packem_shared/mailjetProvider-DwN6i0VA.js +1 -0
  30. package/dist/packem_shared/mailomatProvider-DMQmjKHT.js +1 -0
  31. package/dist/packem_shared/mailtrapProvider-BN3UBEQw.js +1 -0
  32. package/dist/packem_shared/{makeRequest-DwxHX0xo.js → make-request-BDzF9W9D.js} +1 -1
  33. package/dist/packem_shared/mandrillProvider-370y7CLu.js +1 -0
  34. package/dist/packem_shared/mockProvider-DN5ZwutD.js +1 -0
  35. package/dist/packem_shared/nodemailerProvider-_w8QXMU-.js +1 -0
  36. package/dist/packem_shared/opentelemetryProvider-C_ZXOLSd.js +1 -0
  37. package/dist/packem_shared/plunkProvider-DfJumQ4U.js +1 -0
  38. package/dist/packem_shared/postalProvider-Bavx2FcH.js +1 -0
  39. package/dist/packem_shared/postmarkProvider-DFC0uvjO.js +1 -0
  40. package/dist/packem_shared/provider-base-Cmzx6BTO.js +1 -0
  41. package/dist/packem_shared/resendProvider-CfqU7UdE.js +1 -0
  42. package/dist/packem_shared/roundRobinProvider-1WQnuKR8.js +1 -0
  43. package/dist/packem_shared/scalewayProvider-be1HPimL.js +1 -0
  44. package/dist/packem_shared/sendGridProvider-BVI1sq3n.js +1 -0
  45. package/dist/packem_shared/smtpProvider-BV-ufR53.js +23 -0
  46. package/dist/packem_shared/sweegoProvider-7419CSAq.js +1 -0
  47. package/dist/packem_shared/validate-email-options-DfJ7llf8.js +1 -0
  48. package/dist/packem_shared/zeptomailProvider-C2lh0Xmo.js +1 -0
  49. package/dist/providers/ahasend/index.js +1 -1
  50. package/dist/providers/aws-ses/index.js +1 -1
  51. package/dist/providers/azure/index.js +1 -1
  52. package/dist/providers/brevo/index.js +1 -1
  53. package/dist/providers/brevo/types.d.ts +10 -3
  54. package/dist/providers/failover/index.js +1 -1
  55. package/dist/providers/http/index.js +1 -1
  56. package/dist/providers/infobip/index.js +1 -1
  57. package/dist/providers/mailcrab/index.js +1 -1
  58. package/dist/providers/mailersend/index.js +1 -1
  59. package/dist/providers/mailgun/index.js +1 -1
  60. package/dist/providers/mailjet/index.js +1 -1
  61. package/dist/providers/mailomat/index.js +1 -1
  62. package/dist/providers/mailpace/index.js +1 -1
  63. package/dist/providers/mailtrap/index.js +1 -1
  64. package/dist/providers/mandrill/index.js +1 -1
  65. package/dist/providers/mock/index.js +1 -1
  66. package/dist/providers/nodemailer/index.js +1 -1
  67. package/dist/providers/opentelemetry/index.js +1 -1
  68. package/dist/providers/plunk/index.js +1 -1
  69. package/dist/providers/postal/index.js +1 -1
  70. package/dist/providers/postmark/index.js +1 -1
  71. package/dist/providers/resend/index.js +1 -1
  72. package/dist/providers/roundrobin/index.js +1 -1
  73. package/dist/providers/scaleway/index.js +1 -1
  74. package/dist/providers/sendgrid/index.js +1 -1
  75. package/dist/providers/smtp/index.js +1 -1
  76. package/dist/providers/sweego/index.js +1 -1
  77. package/dist/providers/zeptomail/index.js +1 -1
  78. package/dist/types.d.ts +18 -0
  79. package/dist/utils/cache.d.ts +54 -0
  80. package/dist/utils/cache.js +1 -0
  81. package/dist/utils/create-logger.d.ts +2 -4
  82. package/dist/utils/format-email-address.js +1 -0
  83. package/dist/utils/normalize-email-aliases.d.ts +22 -0
  84. package/dist/utils/normalize-email-aliases.js +1 -0
  85. package/dist/utils/parse-address.js +1 -0
  86. package/dist/utils/validation/check-mx-records.d.ts +42 -0
  87. package/dist/utils/validation/check-mx-records.js +1 -0
  88. package/dist/utils/validation/disposable-email-domains.d.ts +13 -0
  89. package/dist/utils/validation/disposable-email-domains.js +1 -0
  90. package/dist/utils/validation/role-accounts.d.ts +21 -0
  91. package/dist/utils/validation/role-accounts.js +1 -0
  92. package/dist/utils/{validate-email-options.d.ts → validation/validate-email-options.d.ts} +1 -1
  93. package/dist/utils/validation/verify-email.d.ts +47 -0
  94. package/dist/utils/validation/verify-email.js +1 -0
  95. package/dist/utils/validation/verify-smtp.d.ts +39 -0
  96. package/dist/utils/validation/verify-smtp.js +4 -0
  97. package/package.json +47 -1
  98. package/dist/packem_shared/MailMessage-Hdgowmvi.js +0 -1
  99. package/dist/packem_shared/ahaSendProvider-NUD_kwyT.js +0 -1
  100. package/dist/packem_shared/azureProvider-Ckdrpmw9.js +0 -1
  101. package/dist/packem_shared/brevoProvider-CB3IYW4n.js +0 -1
  102. package/dist/packem_shared/buildMimeMessage-BPtd0pno.js +0 -2
  103. package/dist/packem_shared/comparePriority-BfiwjVsV.js +0 -1
  104. package/dist/packem_shared/createLogger-DlElSVQP.js +0 -1
  105. package/dist/packem_shared/failoverProvider-sam9n1AG.js +0 -1
  106. package/dist/packem_shared/formatEmailAddress-CHeME3Vk.js +0 -1
  107. package/dist/packem_shared/formatEmailAddresses-UegVOe5A.js +0 -1
  108. package/dist/packem_shared/headersToRecord-BKUTr40L.js +0 -1
  109. package/dist/packem_shared/httpProvider-BhN0RrK-.js +0 -1
  110. package/dist/packem_shared/infobipProvider-D8vYTHV4.js +0 -1
  111. package/dist/packem_shared/isPortAvailable-5kfsfo8u.js +0 -1
  112. package/dist/packem_shared/mailPaceProvider-C47Izgaj.js +0 -1
  113. package/dist/packem_shared/mailerSendProvider-C4uAo-fc.js +0 -1
  114. package/dist/packem_shared/mailgunProvider-B7upu_OV.js +0 -1
  115. package/dist/packem_shared/mailjetProvider-ReErm08u.js +0 -1
  116. package/dist/packem_shared/mailomatProvider-OlCT_O2i.js +0 -1
  117. package/dist/packem_shared/mailtrapProvider-hVMV3h6r.js +0 -1
  118. package/dist/packem_shared/mandrillProvider-DdnbkHZI.js +0 -1
  119. package/dist/packem_shared/mockProvider-BDWZJpea.js +0 -1
  120. package/dist/packem_shared/nodemailerProvider-BV21eRGX.js +0 -1
  121. package/dist/packem_shared/opentelemetryProvider-kAz62mKm.js +0 -1
  122. package/dist/packem_shared/parseAddress-CATTKGe_.js +0 -1
  123. package/dist/packem_shared/plunkProvider-Bs6K51lT.js +0 -1
  124. package/dist/packem_shared/postalProvider-Bcsxp-z6.js +0 -1
  125. package/dist/packem_shared/postmarkProvider-BUq3wuYD.js +0 -1
  126. package/dist/packem_shared/provider-base-_hbWXBdK.js +0 -1
  127. package/dist/packem_shared/resendProvider-D-_HQpN_.js +0 -1
  128. package/dist/packem_shared/retry-D1MBqS49.js +0 -1
  129. package/dist/packem_shared/roundRobinProvider-CejLM1rZ.js +0 -1
  130. package/dist/packem_shared/scalewayProvider-1n6ePiGl.js +0 -1
  131. package/dist/packem_shared/sendGridProvider-B1T62dyX.js +0 -1
  132. package/dist/packem_shared/smtpProvider-CcAoRrkt.js +0 -23
  133. package/dist/packem_shared/sweegoProvider-CxFmEUh6.js +0 -1
  134. package/dist/packem_shared/validateEmailOptions-BzlJECG5.js +0 -1
  135. package/dist/packem_shared/zeptomailProvider-CWYQPAJk.js +0 -1
  136. package/dist/utils/compare-priority.d.ts +0 -16
  137. /package/dist/utils/{validate-email.d.ts → validation/validate-email.d.ts} +0 -0
  138. /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 result = await mail.message().to("user@example.com").from("sender@example.com").subject("Hello").html("<h1>Hello World</h1>").send();
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
- ### Using Different Providers
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, smtpProvider, resendProvider } from "@visulima/email";
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
- 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
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
- ```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" }));
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.sendEmail(emailOptions);
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 result = await mail.message().to("user@example.com").from("sender@example.com").subject("Hello").html("<h1>Hello World</h1>").send();
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
- await mail.message().to("user1@example.com").from("sender@example.com").subject("Email 1").html("<h1>Email 1</h1>").send();
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
- await mail.message().to("user2@example.com").from("sender@example.com").subject("Email 2").html("<h1>Email 2</h1>").send();
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
- await mail.message().to("user3@example.com").from("sender@example.com").subject("Email 3").html("<h1>Email 3</h1>").send();
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 result = await mail.message().to("user@example.com").from("sender@example.com").subject("Welcome").html("<h1>Welcome!</h1>").send();
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.sendEmail(mailgunOptions);
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 result = await mail.message().to("user@example.com").from("sender@example.com").subject("Welcome").html("<h1>Welcome!</h1>").send();
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.sendEmail(mailjetOptions);
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.sendEmail(mailerSendOptions);
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.sendEmail(mandrillOptions);
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.sendEmail(postalOptions);
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.sendEmail(mailtrapOptions);
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.sendEmail(mailPaceOptions);
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.sendEmail(azureOptions);
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.sendEmail(infobipOptions);
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.sendEmail(scalewayOptions);
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.sendEmail(ahaSendOptions);
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.sendEmail(mailomatOptions);
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.sendEmail(sweegoOptions);
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 result = await mail.message().to("user@example.com").from("sender@example.com").subject("Welcome").html("<h1>Welcome!</h1>").send();
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.sendEmail(brevoOptions);
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 result = await mail.message().to("user@example.com").from("sender@example.com").subject("Welcome").html("<h1>Welcome!</h1>").send();
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.sendEmail(postmarkOptions);
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 result = await mail.message().to("user@example.com").from("sender@example.com").subject("Welcome").html("<h1>Welcome!</h1>").send();
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.sendEmail(sendGridOptions);
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 result = await mail.message().to("user@example.com").from("sender@example.com").subject("Welcome").html("<h1>Welcome!</h1>").send();
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.sendEmail(plunkOptions);
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 result = await mail.message().to("user@example.com").from("sender@example.com").subject("Test").html("<h1>Test</h1>").send();
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 result = await mail.message().to("user@example.com").from("sender@example.com").subject("Test Email").html("<h1>Test</h1>").send();
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
+ ````
@@ -1 +1 @@
1
- import{DkimSigner as m,createDkimSigner as i}from"../packem_shared/DkimSigner-Z8D4Il10.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-02aXVi90.js";export{m as DkimSigner,S as SmimeEncrypter,c as SmimeSigner,i as createDkimSigner,n as createSmimeEncrypter,p as createSmimeSigner};
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};