mikromail 0.0.6 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,6 +3,7 @@
3
3
  **Lightweight replacement for Nodemailer, supporting HTML, international symbols, and more**.
4
4
 
5
5
  ![Build Status](https://github.com/mikaelvesavuori/mikromail/workflows/main/badge.svg)
6
+ [![License](https://img.shields.io/badge/license-MIT-green.svg)](https://opensource.org/licenses/MIT)
6
7
 
7
8
  ---
8
9
 
@@ -14,7 +15,7 @@
14
15
 
15
16
  ## Usage
16
17
 
17
- ### Basic importing and usage
18
+ ### Quick Start
18
19
 
19
20
  ```typescript
20
21
  import { MikroMail } from 'MikroMail';
@@ -29,7 +30,7 @@ const emailOptions = {
29
30
  from: 'me@mydomain.com',
30
31
  subject: 'Test Email',
31
32
  text: 'Hello!',
32
- to: 'you@yourdomain.com'
33
+ to: 'you@yourdomain.com' // You can also send to multiple recipients: ['sam@acmecorp.cloud', 'sammy@acmecorp.cloud']
33
34
  };
34
35
 
35
36
  await new MikroMail({ config }).send(emailOptions);
@@ -98,4 +99,4 @@ Some of the tests require faking an SMTP server. Here we use [Mailpit](https://g
98
99
 
99
100
  ## License
100
101
 
101
- MIT
102
+ MIT. See the `LICENSE` file.
package/lib/MikroMail.js CHANGED
@@ -546,10 +546,10 @@ var SMTPClient = class {
546
546
  const messageId = this.generateMessageId();
547
547
  const date = (/* @__PURE__ */ new Date()).toUTCString();
548
548
  const from = options.from || this.config.user;
549
- const { to } = options;
549
+ const recipients = Array.isArray(options.to) ? options.to.join(", ") : options.to;
550
550
  const headers = [
551
551
  `From: ${this.sanitizeHeader(from)}`,
552
- `To: ${this.sanitizeHeader(to)}`,
552
+ `To: ${this.sanitizeHeader(recipients)}`,
553
553
  `Subject: ${this.sanitizeHeader(options.subject)}`,
554
554
  `Message-ID: ${messageId}`,
555
555
  `Date: ${date}`,
@@ -559,9 +559,8 @@ var SMTPClient = class {
559
559
  const cc = Array.isArray(options.cc) ? options.cc.join(", ") : options.cc;
560
560
  headers.push(`Cc: ${this.sanitizeHeader(cc)}`);
561
561
  }
562
- if (options.replyTo) {
562
+ if (options.replyTo)
563
563
  headers.push(`Reply-To: ${this.sanitizeHeader(options.replyTo)}`);
564
- }
565
564
  if (options.headers) {
566
565
  for (const [name, value] of Object.entries(options.headers)) {
567
566
  if (!/^[a-zA-Z0-9-]+$/.test(name)) continue;
@@ -643,12 +642,21 @@ ${text || ""}`;
643
642
  error: "Missing required email parameters (from, to, subject, and either text or html)"
644
643
  };
645
644
  }
646
- if (!validateEmail(from) || !validateEmail(to)) {
645
+ if (!validateEmail(from)) {
647
646
  return {
648
647
  success: false,
649
648
  error: "Invalid email address format"
650
649
  };
651
650
  }
651
+ const recipients = Array.isArray(options.to) ? options.to : [options.to];
652
+ for (const recipient of recipients) {
653
+ if (!validateEmail(recipient)) {
654
+ return {
655
+ success: false,
656
+ error: `Invalid recipient email address format: ${recipient}`
657
+ };
658
+ }
659
+ }
652
660
  for (this.retryCount = 0; this.retryCount <= this.config.maxRetries; this.retryCount++) {
653
661
  try {
654
662
  if (this.retryCount > 0) {
@@ -664,21 +672,20 @@ ${text || ""}`;
664
672
  await this.smtpHandshake();
665
673
  }
666
674
  await this.sendCommand(`MAIL FROM:<${from}>`, 250);
667
- await this.sendCommand(`RCPT TO:<${to}>`, 250);
675
+ for (const recipient of recipients)
676
+ await this.sendCommand(`RCPT TO:<${recipient}>`, 250);
668
677
  if (options.cc) {
669
678
  const ccList = Array.isArray(options.cc) ? options.cc : [options.cc];
670
679
  for (const cc of ccList) {
671
- if (validateEmail(cc)) {
680
+ if (validateEmail(cc))
672
681
  await this.sendCommand(`RCPT TO:<${cc}>`, 250);
673
- }
674
682
  }
675
683
  }
676
684
  if (options.bcc) {
677
685
  const bccList = Array.isArray(options.bcc) ? options.bcc : [options.bcc];
678
686
  for (const bcc of bccList) {
679
- if (validateEmail(bcc)) {
687
+ if (validateEmail(bcc))
680
688
  await this.sendCommand(`RCPT TO:<${bcc}>`, 250);
681
- }
682
689
  }
683
690
  }
684
691
  await this.sendCommand("DATA", 354);
@@ -757,9 +764,14 @@ var MikroMail = class {
757
764
  */
758
765
  async send(emailOptions) {
759
766
  try {
760
- const hasMXRecords = await verifyEmailDomain(emailOptions.to);
761
- if (!hasMXRecords)
762
- console.error("Warning: No MX records found for recipient domain");
767
+ const recipients = Array.isArray(emailOptions.to) ? emailOptions.to : [emailOptions.to];
768
+ for (const recipient of recipients) {
769
+ const hasMXRecords = await verifyEmailDomain(recipient);
770
+ if (!hasMXRecords)
771
+ console.error(
772
+ `Warning: No MX records found for recipient domain: ${recipient}`
773
+ );
774
+ }
763
775
  const result = await this.smtpClient.sendEmail(emailOptions);
764
776
  if (result.success) console.log(`Message ID: ${result.messageId}`);
765
777
  else console.error(`Failed to send email: ${result.error}`);
package/lib/MikroMail.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  MikroMail
3
- } from "./chunk-FP3YCQBU.mjs";
3
+ } from "./chunk-422R3NOG.mjs";
4
4
  import "./chunk-YVXB6HCK.mjs";
5
- import "./chunk-HZ3BDGTE.mjs";
5
+ import "./chunk-NGT3KX7A.mjs";
6
6
  import "./chunk-47VXJTWV.mjs";
7
7
  import "./chunk-UDLJWUFN.mjs";
8
8
  export {
package/lib/SMTPClient.js CHANGED
@@ -402,10 +402,10 @@ var SMTPClient = class {
402
402
  const messageId = this.generateMessageId();
403
403
  const date = (/* @__PURE__ */ new Date()).toUTCString();
404
404
  const from = options.from || this.config.user;
405
- const { to } = options;
405
+ const recipients = Array.isArray(options.to) ? options.to.join(", ") : options.to;
406
406
  const headers = [
407
407
  `From: ${this.sanitizeHeader(from)}`,
408
- `To: ${this.sanitizeHeader(to)}`,
408
+ `To: ${this.sanitizeHeader(recipients)}`,
409
409
  `Subject: ${this.sanitizeHeader(options.subject)}`,
410
410
  `Message-ID: ${messageId}`,
411
411
  `Date: ${date}`,
@@ -415,9 +415,8 @@ var SMTPClient = class {
415
415
  const cc = Array.isArray(options.cc) ? options.cc.join(", ") : options.cc;
416
416
  headers.push(`Cc: ${this.sanitizeHeader(cc)}`);
417
417
  }
418
- if (options.replyTo) {
418
+ if (options.replyTo)
419
419
  headers.push(`Reply-To: ${this.sanitizeHeader(options.replyTo)}`);
420
- }
421
420
  if (options.headers) {
422
421
  for (const [name, value] of Object.entries(options.headers)) {
423
422
  if (!/^[a-zA-Z0-9-]+$/.test(name)) continue;
@@ -499,12 +498,21 @@ ${text || ""}`;
499
498
  error: "Missing required email parameters (from, to, subject, and either text or html)"
500
499
  };
501
500
  }
502
- if (!validateEmail(from) || !validateEmail(to)) {
501
+ if (!validateEmail(from)) {
503
502
  return {
504
503
  success: false,
505
504
  error: "Invalid email address format"
506
505
  };
507
506
  }
507
+ const recipients = Array.isArray(options.to) ? options.to : [options.to];
508
+ for (const recipient of recipients) {
509
+ if (!validateEmail(recipient)) {
510
+ return {
511
+ success: false,
512
+ error: `Invalid recipient email address format: ${recipient}`
513
+ };
514
+ }
515
+ }
508
516
  for (this.retryCount = 0; this.retryCount <= this.config.maxRetries; this.retryCount++) {
509
517
  try {
510
518
  if (this.retryCount > 0) {
@@ -520,21 +528,20 @@ ${text || ""}`;
520
528
  await this.smtpHandshake();
521
529
  }
522
530
  await this.sendCommand(`MAIL FROM:<${from}>`, 250);
523
- await this.sendCommand(`RCPT TO:<${to}>`, 250);
531
+ for (const recipient of recipients)
532
+ await this.sendCommand(`RCPT TO:<${recipient}>`, 250);
524
533
  if (options.cc) {
525
534
  const ccList = Array.isArray(options.cc) ? options.cc : [options.cc];
526
535
  for (const cc of ccList) {
527
- if (validateEmail(cc)) {
536
+ if (validateEmail(cc))
528
537
  await this.sendCommand(`RCPT TO:<${cc}>`, 250);
529
- }
530
538
  }
531
539
  }
532
540
  if (options.bcc) {
533
541
  const bccList = Array.isArray(options.bcc) ? options.bcc : [options.bcc];
534
542
  for (const bcc of bccList) {
535
- if (validateEmail(bcc)) {
543
+ if (validateEmail(bcc))
536
544
  await this.sendCommand(`RCPT TO:<${bcc}>`, 250);
537
- }
538
545
  }
539
546
  }
540
547
  await this.sendCommand("DATA", 354);
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  SMTPClient
3
- } from "./chunk-HZ3BDGTE.mjs";
3
+ } from "./chunk-NGT3KX7A.mjs";
4
4
  import "./chunk-UDLJWUFN.mjs";
5
5
  export {
6
6
  SMTPClient
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-YVXB6HCK.mjs";
4
4
  import {
5
5
  SMTPClient
6
- } from "./chunk-HZ3BDGTE.mjs";
6
+ } from "./chunk-NGT3KX7A.mjs";
7
7
  import {
8
8
  verifyEmailDomain
9
9
  } from "./chunk-UDLJWUFN.mjs";
@@ -21,9 +21,14 @@ var MikroMail = class {
21
21
  */
22
22
  async send(emailOptions) {
23
23
  try {
24
- const hasMXRecords = await verifyEmailDomain(emailOptions.to);
25
- if (!hasMXRecords)
26
- console.error("Warning: No MX records found for recipient domain");
24
+ const recipients = Array.isArray(emailOptions.to) ? emailOptions.to : [emailOptions.to];
25
+ for (const recipient of recipients) {
26
+ const hasMXRecords = await verifyEmailDomain(recipient);
27
+ if (!hasMXRecords)
28
+ console.error(
29
+ `Warning: No MX records found for recipient domain: ${recipient}`
30
+ );
31
+ }
27
32
  const result = await this.smtpClient.sendEmail(emailOptions);
28
33
  if (result.success) console.log(`Message ID: ${result.messageId}`);
29
34
  else console.error(`Failed to send email: ${result.error}`);
@@ -339,10 +339,10 @@ var SMTPClient = class {
339
339
  const messageId = this.generateMessageId();
340
340
  const date = (/* @__PURE__ */ new Date()).toUTCString();
341
341
  const from = options.from || this.config.user;
342
- const { to } = options;
342
+ const recipients = Array.isArray(options.to) ? options.to.join(", ") : options.to;
343
343
  const headers = [
344
344
  `From: ${this.sanitizeHeader(from)}`,
345
- `To: ${this.sanitizeHeader(to)}`,
345
+ `To: ${this.sanitizeHeader(recipients)}`,
346
346
  `Subject: ${this.sanitizeHeader(options.subject)}`,
347
347
  `Message-ID: ${messageId}`,
348
348
  `Date: ${date}`,
@@ -352,9 +352,8 @@ var SMTPClient = class {
352
352
  const cc = Array.isArray(options.cc) ? options.cc.join(", ") : options.cc;
353
353
  headers.push(`Cc: ${this.sanitizeHeader(cc)}`);
354
354
  }
355
- if (options.replyTo) {
355
+ if (options.replyTo)
356
356
  headers.push(`Reply-To: ${this.sanitizeHeader(options.replyTo)}`);
357
- }
358
357
  if (options.headers) {
359
358
  for (const [name, value] of Object.entries(options.headers)) {
360
359
  if (!/^[a-zA-Z0-9-]+$/.test(name)) continue;
@@ -436,12 +435,21 @@ ${text || ""}`;
436
435
  error: "Missing required email parameters (from, to, subject, and either text or html)"
437
436
  };
438
437
  }
439
- if (!validateEmail(from) || !validateEmail(to)) {
438
+ if (!validateEmail(from)) {
440
439
  return {
441
440
  success: false,
442
441
  error: "Invalid email address format"
443
442
  };
444
443
  }
444
+ const recipients = Array.isArray(options.to) ? options.to : [options.to];
445
+ for (const recipient of recipients) {
446
+ if (!validateEmail(recipient)) {
447
+ return {
448
+ success: false,
449
+ error: `Invalid recipient email address format: ${recipient}`
450
+ };
451
+ }
452
+ }
445
453
  for (this.retryCount = 0; this.retryCount <= this.config.maxRetries; this.retryCount++) {
446
454
  try {
447
455
  if (this.retryCount > 0) {
@@ -457,21 +465,20 @@ ${text || ""}`;
457
465
  await this.smtpHandshake();
458
466
  }
459
467
  await this.sendCommand(`MAIL FROM:<${from}>`, 250);
460
- await this.sendCommand(`RCPT TO:<${to}>`, 250);
468
+ for (const recipient of recipients)
469
+ await this.sendCommand(`RCPT TO:<${recipient}>`, 250);
461
470
  if (options.cc) {
462
471
  const ccList = Array.isArray(options.cc) ? options.cc : [options.cc];
463
472
  for (const cc of ccList) {
464
- if (validateEmail(cc)) {
473
+ if (validateEmail(cc))
465
474
  await this.sendCommand(`RCPT TO:<${cc}>`, 250);
466
- }
467
475
  }
468
476
  }
469
477
  if (options.bcc) {
470
478
  const bccList = Array.isArray(options.bcc) ? options.bcc : [options.bcc];
471
479
  for (const bcc of bccList) {
472
- if (validateEmail(bcc)) {
480
+ if (validateEmail(bcc))
473
481
  await this.sendCommand(`RCPT TO:<${bcc}>`, 250);
474
- }
475
482
  }
476
483
  }
477
484
  await this.sendCommand("DATA", 354);
package/lib/index.js CHANGED
@@ -546,10 +546,10 @@ var SMTPClient = class {
546
546
  const messageId = this.generateMessageId();
547
547
  const date = (/* @__PURE__ */ new Date()).toUTCString();
548
548
  const from = options.from || this.config.user;
549
- const { to } = options;
549
+ const recipients = Array.isArray(options.to) ? options.to.join(", ") : options.to;
550
550
  const headers = [
551
551
  `From: ${this.sanitizeHeader(from)}`,
552
- `To: ${this.sanitizeHeader(to)}`,
552
+ `To: ${this.sanitizeHeader(recipients)}`,
553
553
  `Subject: ${this.sanitizeHeader(options.subject)}`,
554
554
  `Message-ID: ${messageId}`,
555
555
  `Date: ${date}`,
@@ -559,9 +559,8 @@ var SMTPClient = class {
559
559
  const cc = Array.isArray(options.cc) ? options.cc.join(", ") : options.cc;
560
560
  headers.push(`Cc: ${this.sanitizeHeader(cc)}`);
561
561
  }
562
- if (options.replyTo) {
562
+ if (options.replyTo)
563
563
  headers.push(`Reply-To: ${this.sanitizeHeader(options.replyTo)}`);
564
- }
565
564
  if (options.headers) {
566
565
  for (const [name, value] of Object.entries(options.headers)) {
567
566
  if (!/^[a-zA-Z0-9-]+$/.test(name)) continue;
@@ -643,12 +642,21 @@ ${text || ""}`;
643
642
  error: "Missing required email parameters (from, to, subject, and either text or html)"
644
643
  };
645
644
  }
646
- if (!validateEmail(from) || !validateEmail(to)) {
645
+ if (!validateEmail(from)) {
647
646
  return {
648
647
  success: false,
649
648
  error: "Invalid email address format"
650
649
  };
651
650
  }
651
+ const recipients = Array.isArray(options.to) ? options.to : [options.to];
652
+ for (const recipient of recipients) {
653
+ if (!validateEmail(recipient)) {
654
+ return {
655
+ success: false,
656
+ error: `Invalid recipient email address format: ${recipient}`
657
+ };
658
+ }
659
+ }
652
660
  for (this.retryCount = 0; this.retryCount <= this.config.maxRetries; this.retryCount++) {
653
661
  try {
654
662
  if (this.retryCount > 0) {
@@ -664,21 +672,20 @@ ${text || ""}`;
664
672
  await this.smtpHandshake();
665
673
  }
666
674
  await this.sendCommand(`MAIL FROM:<${from}>`, 250);
667
- await this.sendCommand(`RCPT TO:<${to}>`, 250);
675
+ for (const recipient of recipients)
676
+ await this.sendCommand(`RCPT TO:<${recipient}>`, 250);
668
677
  if (options.cc) {
669
678
  const ccList = Array.isArray(options.cc) ? options.cc : [options.cc];
670
679
  for (const cc of ccList) {
671
- if (validateEmail(cc)) {
680
+ if (validateEmail(cc))
672
681
  await this.sendCommand(`RCPT TO:<${cc}>`, 250);
673
- }
674
682
  }
675
683
  }
676
684
  if (options.bcc) {
677
685
  const bccList = Array.isArray(options.bcc) ? options.bcc : [options.bcc];
678
686
  for (const bcc of bccList) {
679
- if (validateEmail(bcc)) {
687
+ if (validateEmail(bcc))
680
688
  await this.sendCommand(`RCPT TO:<${bcc}>`, 250);
681
- }
682
689
  }
683
690
  }
684
691
  await this.sendCommand("DATA", 354);
@@ -757,9 +764,14 @@ var MikroMail = class {
757
764
  */
758
765
  async send(emailOptions) {
759
766
  try {
760
- const hasMXRecords = await verifyEmailDomain(emailOptions.to);
761
- if (!hasMXRecords)
762
- console.error("Warning: No MX records found for recipient domain");
767
+ const recipients = Array.isArray(emailOptions.to) ? emailOptions.to : [emailOptions.to];
768
+ for (const recipient of recipients) {
769
+ const hasMXRecords = await verifyEmailDomain(recipient);
770
+ if (!hasMXRecords)
771
+ console.error(
772
+ `Warning: No MX records found for recipient domain: ${recipient}`
773
+ );
774
+ }
763
775
  const result = await this.smtpClient.sendEmail(emailOptions);
764
776
  if (result.success) console.log(`Message ID: ${result.messageId}`);
765
777
  else console.error(`Failed to send email: ${result.error}`);
package/lib/index.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  MikroMail
3
- } from "./chunk-FP3YCQBU.mjs";
3
+ } from "./chunk-422R3NOG.mjs";
4
4
  import "./chunk-YVXB6HCK.mjs";
5
- import "./chunk-HZ3BDGTE.mjs";
5
+ import "./chunk-NGT3KX7A.mjs";
6
6
  import "./chunk-47VXJTWV.mjs";
7
7
  import "./chunk-UDLJWUFN.mjs";
8
8
  export {
@@ -19,7 +19,7 @@ interface SMTPConfiguration {
19
19
  */
20
20
  interface EmailOptions {
21
21
  from?: string;
22
- to: string;
22
+ to: string | string[];
23
23
  cc?: string | string[];
24
24
  bcc?: string | string[];
25
25
  replyTo?: string;
@@ -19,7 +19,7 @@ interface SMTPConfiguration {
19
19
  */
20
20
  interface EmailOptions {
21
21
  from?: string;
22
- to: string;
22
+ to: string | string[];
23
23
  cc?: string | string[];
24
24
  bcc?: string | string[];
25
25
  replyTo?: string;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mikromail",
3
3
  "description": "Lightweight replacement for Nodemailer, supporting HTML, international symbols, and more.",
4
- "version": "0.0.6",
4
+ "version": "0.0.7",
5
5
  "author": "Mikael Vesavuori",
6
6
  "license": "MIT",
7
7
  "keywords": [
@@ -41,7 +41,8 @@
41
41
  "clean": "rm -rf lib && rm -rf dist",
42
42
  "lint": "npx @biomejs/biome check --write ./src ./tests",
43
43
  "package": "npm pack",
44
- "prepublishOnly": "npm run build"
44
+ "prepublishOnly": "npm run build",
45
+ "prepare": "husky"
45
46
  },
46
47
  "devDependencies": {
47
48
  "@biomejs/biome": "1",