@push.rocks/smartmta 9.6.0 → 10.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/changelog.md +29 -0
  2. package/dist_rust/mailer-bin_linux_amd64 +0 -0
  3. package/dist_rust/mailer-bin_linux_amd64.tsrust-build.json +5 -5
  4. package/dist_rust/mailer-bin_linux_arm64 +0 -0
  5. package/dist_rust/mailer-bin_linux_arm64.tsrust-build.json +5 -5
  6. package/dist_ts/00_commitinfo_data.js +2 -2
  7. package/dist_ts/mail/core/classes.email.d.ts +7 -2
  8. package/dist_ts/mail/core/classes.email.js +36 -118
  9. package/dist_ts/mail/core/classes.emailvalidator.js +2 -2
  10. package/dist_ts/plugins.d.ts +2 -2
  11. package/dist_ts/plugins.js +3 -3
  12. package/notices/aws-lc-sys-0.43.0-fiat-license.txt +22 -0
  13. package/notices/cargo-dependencies.html +4706 -0
  14. package/notices/compiler-builtins-license.txt +275 -0
  15. package/notices/crossbeam-channel-third-party.txt +593 -0
  16. package/notices/encoding-rs-copyright.txt +61 -0
  17. package/notices/glibc-copying-lesser.txt +502 -0
  18. package/notices/glibc-licenses.txt +412 -0
  19. package/notices/inventory.json +1226 -0
  20. package/notices/libgcc-gpl-3.0.txt +674 -0
  21. package/notices/libgcc-runtime-exception.txt +73 -0
  22. package/notices/mimalloc-license.txt +21 -0
  23. package/notices/moka-notice.txt +14 -0
  24. package/notices/ring-0.17.14-fiat-license.txt +15 -0
  25. package/notices/ring-0.17.14-license-boringssl.txt +272 -0
  26. package/notices/ring-0.17.14-license-other-bits.txt +13 -0
  27. package/notices/ring-0.17.14-license.txt +9 -0
  28. package/notices/ring-0.17.14-once-cell-license-apache.txt +201 -0
  29. package/notices/ring-0.17.14-once-cell-license-mit.txt +23 -0
  30. package/notices/rust-standard-library.html +8266 -0
  31. package/notices/rustversion-1.0.23-license-mit.txt +23 -0
  32. package/notices/source-attributions.txt +294 -0
  33. package/notices/wasm-bindgen-license-mit.txt +25 -0
  34. package/notices/zerocopy-derive-0.8.55-license-mit.txt +26 -0
  35. package/notices/zstd-license.txt +30 -0
  36. package/package.json +12 -11
  37. package/readme.md +28 -3
  38. package/third-party-notices.md +176 -0
  39. package/ts/00_commitinfo_data.ts +1 -1
  40. package/ts/mail/core/classes.email.ts +40 -129
  41. package/ts/mail/core/classes.emailvalidator.ts +2 -2
  42. package/ts/plugins.ts +2 -2
  43. /package/{license → license.md} +0 -0
@@ -0,0 +1,176 @@
1
+ # Third-party notices
2
+
3
+ These notices accompany SmartMTA's prebuilt `dist_rust/mailer-bin_linux_amd64`
4
+ and `dist_rust/mailer-bin_linux_arm64` executables, which ship inside the npm
5
+ package. SmartMTA's own TypeScript and Rust code is MIT-licensed under
6
+ [license](./license.md).
7
+
8
+ Both executables are statically linked: `pnpm run build:release` runs
9
+ `tsbuild tsfolders && tsrust --configured-targets && tsrust verify`, and
10
+ `@git.zone/tsrust` builds the `.smartconfig.json` targets `linux_amd64` and `linux_arm64` — the
11
+ `x86_64-unknown-linux-gnu` and `aarch64-unknown-linux-gnu` triples — with
12
+ `-C target-feature=+crt-static`, so the Cargo dependency graph, the Rust
13
+ standard library, the GNU C Library and libgcc are all compiled into the
14
+ shipped object code. Anyone redistributing those executables — including
15
+ inside a container image — redistributes those third-party works in binary
16
+ form and must pass these notices on with them.
17
+
18
+ ## Cargo dependencies
19
+
20
+ [Cargo dependency notices](./notices/cargo-dependencies.html) reproduce the
21
+ selected upstream license and copyright texts for 225 of the 232 third-party
22
+ packages in `rust/Cargo.lock`. The seven remaining packages are locked but
23
+ outside the resolved build graph (WebAssembly-only or feature-inactive), and
24
+ are covered by these supplemental notices:
25
+
26
+ - [js-sys 0.3.103, wasm-bindgen 0.2.126, wasm-bindgen-macro 0.2.126,
27
+ wasm-bindgen-macro-support 0.2.126 and wasm-bindgen-shared 0.2.126](./notices/wasm-bindgen-license-mit.txt),
28
+ from their identical published `LICENSE-MIT` files.
29
+ - [rustversion 1.0.23](./notices/rustversion-1.0.23-license-mit.txt), from the
30
+ published crate's `LICENSE-MIT`.
31
+ - [zerocopy-derive 0.8.55](./notices/zerocopy-derive-0.8.55-license-mit.txt),
32
+ from the published crate's `LICENSE-MIT`.
33
+
34
+ Together these cover all 232 locked external packages, conservatively including
35
+ build-only and target-inactive dependencies. Listing a package does not mean it
36
+ is linked into either executable. MIT is preferred where offered as an
37
+ alternative; other selected terms include Apache-2.0, ISC, 0BSD, BSD-2-Clause,
38
+ BSD-3-Clause, Unicode-3.0, Zlib, CC0-1.0, MIT-0, CDLA-Permissive-2.0 and
39
+ bzip2-1.0.6. The exact package versions and declared license expressions are
40
+ recorded in [inventory.json](./notices/inventory.json).
41
+
42
+ Several packages vendor or derive from third-party source whose attribution is
43
+ not carried by the crate-level license text. Those notices are reproduced
44
+ verbatim beside the generated inventory:
45
+
46
+ - ring 0.17.14: [its own ISC terms](./notices/ring-0.17.14-license.txt),
47
+ [the BoringSSL terms](./notices/ring-0.17.14-license-boringssl.txt),
48
+ [the ISC text for new files](./notices/ring-0.17.14-license-other-bits.txt),
49
+ [the fiat-crypto terms](./notices/ring-0.17.14-fiat-license.txt) and the
50
+ once_cell terms it sourced code from
51
+ ([Apache-2.0](./notices/ring-0.17.14-once-cell-license-apache.txt),
52
+ [MIT](./notices/ring-0.17.14-once-cell-license-mit.txt)).
53
+ - aws-lc-sys 0.43.0: the vendored AWS-LC notice — itself covering BoringSSL and
54
+ OpenSSL/SSLeay — is the crate's `LICENSE` file and is reproduced in the
55
+ generated inventory; its separately licensed
56
+ [fiat-crypto component](./notices/aws-lc-sys-0.43.0-fiat-license.txt) is
57
+ included here.
58
+ - libmimalloc-sys 0.1.49: [the vendored mimalloc terms](./notices/mimalloc-license.txt).
59
+ - zstd-sys 2.0.16+zstd.1.5.7: [the vendored Zstandard terms](./notices/zstd-license.txt)
60
+ (BSD-3-Clause is selected; upstream also offers GPL-2.0).
61
+ - moka 0.12.15: [its Apache-2.0 NOTICE file](./notices/moka-notice.txt), as
62
+ required by Apache-2.0 section 4(d).
63
+ - crossbeam-channel 0.5.16:
64
+ [its third-party notices](./notices/crossbeam-channel-third-party.txt).
65
+ - encoding_rs 0.8.35:
66
+ [its copyright and WHATWG attribution](./notices/encoding-rs-copyright.txt).
67
+ - [Additional source attributions](./notices/source-attributions.txt) retain the
68
+ copyright and attribution files shipped by charset, enum-as-inner,
69
+ linux-raw-sys, miniz_oxide, rand, rand_chacha, rand_core, regex-syntax, rustix
70
+ and utf8_iter.
71
+
72
+ ## Compiler and static runtime
73
+
74
+ Components supplied by the Rust compiler and by the C toolchain are outside
75
+ `rust/Cargo.lock` and have separate notices. The exact versions that produced
76
+ the shipped executables are recorded in
77
+ [inventory.json](./notices/inventory.json) under `rustc` and `staticRuntime`,
78
+ and `test/test.notices.node.ts` reads them back out of
79
+ `dist_rust/mailer-bin_linux_amd64` and `dist_rust/mailer-bin_linux_arm64`, so
80
+ these notices go stale loudly rather than silently.
81
+
82
+ - The Rust toolchain is the one `tsrust` resolves: the system `cargo`/`rustc`
83
+ when one is installed, otherwise its bundled `stable-<host-triple>` under
84
+ `/tmp/tsrust_toolchain`. This release was built with rustc 1.95.0
85
+ (commit `59807616e1fa2540724bfbac14d7976d7e4a3860`), which both executables
86
+ embed. The [Rust standard-library inventory](./notices/rust-standard-library.html)
87
+ is that toolchain's `share/doc/rust/COPYRIGHT-library.html`; the upstream
88
+ inventory covers other targets too.
89
+ - [Compiler-builtins license](./notices/compiler-builtins-license.txt), from
90
+ [Rust 1.95.0](https://github.com/rust-lang/rust/blob/1.95.0/library/compiler-builtins/LICENSE.txt),
91
+ retaining MIT and Apache-2.0 WITH LLVM-exception terms.
92
+ - The GNU C Library 2.39 is statically linked into both executables, in the
93
+ Ubuntu builds that produced them:
94
+ - amd64: `libc6-dev` 2.39-0ubuntu8.9, from Ubuntu source package
95
+ `glibc` 2.39-0ubuntu8.9 —
96
+ `apt-get source glibc=2.39-0ubuntu8.9`, or
97
+ <https://launchpad.net/ubuntu/+source/glibc/2.39-0ubuntu8.9>.
98
+ - arm64: `libc6-dev-arm64-cross` 2.39-0ubuntu8cross1, from Ubuntu source
99
+ package `cross-toolchain-base` 68ubuntu5, which repacks Ubuntu glibc
100
+ 2.39-0ubuntu8 —
101
+ `apt-get source cross-toolchain-base=68ubuntu5`, or
102
+ <https://launchpad.net/ubuntu/+source/cross-toolchain-base/68ubuntu5>.
103
+
104
+ Its [LGPL-2.1 terms](./notices/glibc-copying-lesser.txt) and the
105
+ [copying permission notices for its non-FSF parts](./notices/glibc-licenses.txt)
106
+ are reproduced from the upstream `glibc-2.39` tag, which those Ubuntu source
107
+ packages patch. The GNU C Library is free software licensed under the GNU
108
+ Lesser General Public License, version 2.1 or later; because it is linked
109
+ statically, redistributors must keep this notice and the license text with
110
+ the executables.
111
+ - libgcc supplies the unwinder and compiler intrinsics linked into both
112
+ executables: `libgcc-13-dev` 13.3.0-6ubuntu2~24.04.1 (source package `gcc-13`)
113
+ for amd64 and `libgcc-13-dev-arm64-cross` 13.3.0-6ubuntu2~24.04.1cross1
114
+ (source package `gcc-13-cross` 14ubuntu4.4) for arm64, both GCC 13.3.0. It is
115
+ distributed under [GPL-3.0-or-later](./notices/libgcc-gpl-3.0.txt) WITH the
116
+ [GCC Runtime Library Exception 3.1](./notices/libgcc-runtime-exception.txt),
117
+ which permits distributing the compiled runtime with this executable under
118
+ the executable's own terms.
119
+
120
+ ## Rebuilding and relinking
121
+
122
+ The executables are rebuilt from this repository with:
123
+
124
+ ```sh
125
+ pnpm install
126
+ pnpm run build:release # tsbuild tsfolders && tsrust --configured-targets && tsrust verify
127
+ ```
128
+
129
+ `tsrust --configured-targets` reads the `@git.zone/tsrust` block of
130
+ `.smartconfig.json` (`targets` `linux_amd64` and `linux_arm64`,
131
+ `static: true`), runs
132
+ `RUSTFLAGS='-C target-feature=+crt-static' cargo build --release --target
133
+ <triple>` in `rust/`, and copies the results to `dist_rust/`. The arm64 link
134
+ uses the `aarch64-linux-gnu-gcc` linker configured in `rust/.cargo/config.toml`.
135
+ `tsrust verify` then confirms that `dist_rust/` holds exactly that matrix,
136
+ built from a clean checkout of the current commit; a rebuild from modified
137
+ sources or against a modified library runs `pnpm exec tsrust
138
+ --configured-targets` without it.
139
+
140
+ That is also the relink route required by LGPL-2.1 section 6: the complete
141
+ corresponding source of the work that uses the library is this package's own
142
+ MIT-licensed source — `rust/` and `ts/` in
143
+ [the package repository](https://code.foss.global/push.rocks/smartmta) at the
144
+ tag matching this release — and glibc's sources are obtained with the
145
+ `apt-get source` commands above, so a recipient can modify the library, rebuild
146
+ it, and relink the executable with the command shown here.
147
+
148
+ The TypeScript dependency graph is installed independently through the npm
149
+ manifest; its packages are not bundled into these Rust executables.
150
+
151
+ ## Reproduction and review
152
+
153
+ From the repository root, with cargo-about 0.9.1:
154
+
155
+ ```sh
156
+ cargo about generate --manifest-path rust/Cargo.toml --config rust/about.toml \
157
+ --locked --fail --output-file notices/cargo-dependencies.html rust/about.hbs
158
+ ```
159
+
160
+ The configuration selects checksum-verified upstream notices when published
161
+ crates omit or misname them; network access is required for the pinned
162
+ `r-efi` Git source. Those commands regenerate the notices only, not the
163
+ executables; rebuilding and relinking is described above.
164
+ `notices/inventory.json` records the SHA-256 of every notice file and notice
165
+ input alongside the locked package list from `cargo metadata --locked`, the
166
+ rustc that built the executables, and the exact Ubuntu glibc and libgcc
167
+ package revisions linked into them; after a Cargo graph, compiler, C toolchain,
168
+ or notice-input change, regenerate the notices, refresh those digests and
169
+ values, and rerun `pnpm test`.
170
+ `test/test.notices.node.ts` rejects stale digests, packages missing from the
171
+ inventory or from the shipped notices, generic copyright placeholders and
172
+ missing npm notice paths.
173
+
174
+ Keep this index, `license` and the entire `notices/` directory beside any
175
+ separately distributed copy of `mailer-bin_linux_amd64` or
176
+ `mailer-bin_linux_arm64`.
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@push.rocks/smartmta',
6
- version: '9.6.0',
6
+ version: '10.0.0',
7
7
  description: 'A high-performance, enterprise-grade Mail Transfer Agent (MTA) built from scratch in TypeScript with Rust acceleration.'
8
8
  }
@@ -567,72 +567,24 @@ export class Email {
567
567
  * Convert this email to a smartmail instance
568
568
  * @returns A new Smartmail instance
569
569
  */
570
- public async toSmartmail(): Promise<plugins.smartmail.Smartmail<any>> {
571
- const smartmail = new plugins.smartmail.Smartmail({
570
+ public async toSmartmail(): Promise<plugins.smartmail.Smartmail<unknown>> {
571
+ const smartmail = new plugins.smartmail.Smartmail<unknown>({
572
572
  from: this.from,
573
573
  subject: this.subject,
574
- body: this.html || this.text
574
+ body: this.text,
575
+ htmlBody: this.html,
575
576
  });
576
-
577
- // Add recipients - ensure we're using the correct format
578
- // (newer version of smartmail expects objects with email property)
579
- for (const recipient of this.to) {
580
- // Use the proper addRecipient method for the current smartmail version
581
- if (typeof smartmail.addRecipient === 'function') {
582
- smartmail.addRecipient(recipient);
583
- } else {
584
- // Fallback for older versions or different interface
585
- (smartmail.options.to as any[]).push({
586
- email: recipient,
587
- name: recipient.split('@')[0] // Simple name extraction
588
- });
589
- }
590
- }
591
-
592
- // Handle CC recipients
593
- for (const ccRecipient of this.cc) {
594
- if (typeof smartmail.addRecipient === 'function') {
595
- smartmail.addRecipient(ccRecipient, 'cc');
596
- } else {
597
- // Fallback for older versions
598
- if (!smartmail.options.cc) smartmail.options.cc = [];
599
- (smartmail.options.cc as any[]).push({
600
- email: ccRecipient,
601
- name: ccRecipient.split('@')[0]
602
- });
603
- }
604
- }
605
-
606
- // Handle BCC recipients
607
- for (const bccRecipient of this.bcc) {
608
- if (typeof smartmail.addRecipient === 'function') {
609
- smartmail.addRecipient(bccRecipient, 'bcc');
610
- } else {
611
- // Fallback for older versions
612
- if (!smartmail.options.bcc) smartmail.options.bcc = [];
613
- (smartmail.options.bcc as any[]).push({
614
- email: bccRecipient,
615
- name: bccRecipient.split('@')[0]
616
- });
617
- }
618
- }
619
-
620
- // Add attachments
577
+ smartmail.addRecipients(this.to, 'to');
578
+ smartmail.addRecipients(this.cc, 'cc');
579
+ smartmail.addRecipients(this.bcc, 'bcc');
621
580
  for (const attachment of this.attachments) {
622
- const smartAttachment = new plugins.smartfile.SmartFile({
623
- path: attachment.filename,
624
- contentBuffer: attachment.content,
625
- base: '.',
581
+ smartmail.addAttachment({
582
+ filename: attachment.filename,
583
+ contentType: attachment.contentType,
584
+ content: attachment.content,
585
+ contentId: attachment.contentId,
626
586
  });
627
-
628
- // Set content type if available
629
- if (attachment.contentType) {
630
- (smartAttachment as any).contentType = attachment.contentType;
631
- }
632
-
633
- smartmail.addAttachment(smartAttachment);
634
587
  }
635
-
636
588
  return smartmail;
637
589
  }
638
590
 
@@ -869,80 +821,39 @@ export class Email {
869
821
  * @param smartmail The Smartmail instance to convert
870
822
  * @returns A new Email instance
871
823
  */
872
- public static fromSmartmail(smartmail: plugins.smartmail.Smartmail<any>): Email {
824
+ public static fromSmartmail(smartmail: plugins.smartmail.Smartmail<unknown>): Email {
873
825
  const options: IEmailOptions = {
874
826
  from: smartmail.options.from,
875
- to: [],
827
+ to: smartmail.options.to ?? [],
828
+ cc: smartmail.options.cc ?? [],
829
+ bcc: smartmail.options.bcc ?? [],
876
830
  subject: smartmail.getSubject(),
877
- text: smartmail.getBody(false), // Plain text version
878
- html: smartmail.getBody(true), // HTML version
879
- attachments: []
880
- };
881
-
882
- // Function to safely extract email address from recipient
883
- const extractEmail = (recipient: any): string => {
884
- // Handle string recipients
885
- if (typeof recipient === 'string') return recipient;
886
-
887
- // Handle object recipients
888
- if (recipient && typeof recipient === 'object') {
889
- const addressObj = recipient as any;
890
- // Try different property names that might contain the email address
891
- if ('address' in addressObj && typeof addressObj.address === 'string') {
892
- return addressObj.address;
893
- }
894
- if ('email' in addressObj && typeof addressObj.email === 'string') {
895
- return addressObj.email;
896
- }
897
- }
898
-
899
- // Fallback for invalid input
900
- return '';
901
- };
902
-
903
- // Filter out empty strings from the extracted emails
904
- const filterValidEmails = (emails: string[]): string[] => {
905
- return emails.filter(email => email && email.length > 0);
831
+ text: smartmail.getBody(),
832
+ html: smartmail.getHtmlBody() ?? undefined,
833
+ attachments: smartmail.attachments.map((attachment) => ({
834
+ filename: attachment.filename,
835
+ content: Email.attachmentContentToBuffer(attachment),
836
+ contentType: attachment.contentType || 'application/octet-stream',
837
+ contentId: attachment.contentId,
838
+ })),
906
839
  };
907
-
908
- // Convert recipients from Smartmail's optional arrays.
909
- const toRecipients = smartmail.options.to;
910
- if (toRecipients && toRecipients.length > 0) {
911
- options.to = filterValidEmails(toRecipients.map(extractEmail));
912
- }
913
-
914
- const ccRecipients = smartmail.options.cc;
915
- if (ccRecipients && ccRecipients.length > 0) {
916
- options.cc = filterValidEmails(ccRecipients.map(extractEmail));
917
- }
918
-
919
- const bccRecipients = smartmail.options.bcc;
920
- if (bccRecipients && bccRecipients.length > 0) {
921
- options.bcc = filterValidEmails(bccRecipients.map(extractEmail));
840
+ return new Email(options);
841
+ }
842
+
843
+ /**
844
+ * Email attachments hold their bytes in memory; a streamed Smartmail attachment
845
+ * (iterable or stream content) cannot be converted synchronously.
846
+ */
847
+ private static attachmentContentToBuffer(attachment: plugins.smartmail.IMailAttachment): Buffer {
848
+ const content = attachment.content;
849
+ if (typeof content === 'string') {
850
+ return Buffer.from(content, 'utf8');
922
851
  }
923
-
924
- // Convert attachments (note: this handles the synchronous case only)
925
- if (smartmail.attachments?.length > 0) {
926
- options.attachments = smartmail.attachments.map(attachment => {
927
- // For the test case, if the path is exactly "test.txt", use that as the filename
928
- let filename = 'attachment.bin';
929
-
930
- if (attachment.path === 'test.txt') {
931
- filename = 'test.txt';
932
- } else if (attachment.parsedPath?.base) {
933
- filename = attachment.parsedPath.base;
934
- } else if (typeof attachment.path === 'string') {
935
- filename = attachment.path.split('/').pop() || 'attachment.bin';
936
- }
937
-
938
- return {
939
- filename,
940
- content: Buffer.from(attachment.contentBuffer || Buffer.alloc(0)),
941
- contentType: (attachment as any)?.contentType || 'application/octet-stream'
942
- };
943
- });
852
+ if (content instanceof Uint8Array) {
853
+ return Buffer.from(content);
944
854
  }
945
-
946
- return new Email(options);
855
+ throw new Error(
856
+ `Attachment ${attachment.filename} has streamed content; Email.fromSmartmail() needs string or Uint8Array content`
857
+ );
947
858
  }
948
859
  }
@@ -22,14 +22,14 @@ export interface IEmailValidationResult {
22
22
  * Advanced email validator class using smartmail's capabilities
23
23
  */
24
24
  export class EmailValidator {
25
- private validator: plugins.smartmail.EmailAddressValidator;
25
+ private validator: plugins.smartmailValidation.EmailAddressValidator;
26
26
  private dnsCache: LRUCache<string, string[]>;
27
27
 
28
28
  constructor(options?: {
29
29
  maxCacheSize?: number;
30
30
  cacheTTL?: number;
31
31
  }) {
32
- this.validator = new plugins.smartmail.EmailAddressValidator();
32
+ this.validator = new plugins.smartmailValidation.EmailAddressValidator();
33
33
 
34
34
  // Initialize LRU cache for DNS records
35
35
  this.dnsCache = new LRUCache<string, string[]>({
package/ts/plugins.ts CHANGED
@@ -22,13 +22,13 @@ export {
22
22
  }
23
23
 
24
24
  // @push.rocks scope
25
- import * as smartfile from '@push.rocks/smartfile';
26
25
  import * as smartlog from '@push.rocks/smartlog';
27
26
  import * as smartmail from '@push.rocks/smartmail';
27
+ import * as smartmailValidation from '@push.rocks/smartmail/validation';
28
28
  import * as smartpath from '@push.rocks/smartpath';
29
29
  import * as smartrust from '@push.rocks/smartrust';
30
30
 
31
- export { smartfile, smartlog, smartmail, smartpath, smartrust };
31
+ export { smartlog, smartmail, smartmailValidation, smartpath, smartrust };
32
32
 
33
33
  // Define SmartLog types for use in error handling
34
34
  export type TLogLevel = 'error' | 'warn' | 'info' | 'success' | 'debug';
File without changes