@nocobase/plugin-workflow-mailer 2.4.0-alpha.1 → 2.4.0-alpha.11

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 (187) hide show
  1. package/dist/externalVersion.js +6 -6
  2. package/dist/node_modules/joi/dist/joi-browser.min.js +1 -1
  3. package/dist/node_modules/joi/lib/index.js +1 -1
  4. package/dist/node_modules/joi/lib/messages.js +35 -6
  5. package/dist/node_modules/joi/lib/types/keys.js +18 -1
  6. package/dist/node_modules/joi/lib/types/link.js +18 -2
  7. package/dist/node_modules/joi/lib/types/string.js +2 -2
  8. package/dist/node_modules/joi/package.json +1 -1
  9. package/dist/node_modules/nodemailer/dist/cjs/addressparser/index.d.ts +59 -0
  10. package/dist/node_modules/nodemailer/dist/cjs/addressparser/index.js +790 -0
  11. package/dist/node_modules/nodemailer/dist/cjs/base64/index.d.ts +36 -0
  12. package/dist/node_modules/nodemailer/dist/cjs/base64/index.js +119 -0
  13. package/dist/node_modules/nodemailer/dist/cjs/dkim/index.d.ts +52 -0
  14. package/dist/node_modules/nodemailer/dist/cjs/dkim/index.js +228 -0
  15. package/dist/node_modules/nodemailer/dist/cjs/dkim/message-parser.d.ts +48 -0
  16. package/dist/node_modules/nodemailer/dist/cjs/dkim/message-parser.js +180 -0
  17. package/dist/node_modules/nodemailer/dist/cjs/dkim/relaxed-body.d.ts +36 -0
  18. package/dist/node_modules/nodemailer/dist/cjs/dkim/relaxed-body.js +148 -0
  19. package/dist/node_modules/nodemailer/dist/cjs/dkim/sign.d.ts +52 -0
  20. package/dist/node_modules/nodemailer/dist/cjs/dkim/sign.js +165 -0
  21. package/dist/node_modules/nodemailer/dist/cjs/errors.d.ts +96 -0
  22. package/dist/node_modules/nodemailer/dist/cjs/errors.js +70 -0
  23. package/dist/node_modules/nodemailer/dist/cjs/fetch/cookies.d.ts +107 -0
  24. package/dist/node_modules/nodemailer/dist/cjs/fetch/cookies.js +282 -0
  25. package/dist/node_modules/nodemailer/dist/cjs/fetch/index.d.ts +65 -0
  26. package/dist/node_modules/nodemailer/dist/cjs/fetch/index.js +384 -0
  27. package/dist/node_modules/nodemailer/dist/cjs/json-transport/index.d.ts +64 -0
  28. package/dist/node_modules/nodemailer/dist/cjs/json-transport/index.js +99 -0
  29. package/dist/node_modules/nodemailer/dist/cjs/mail-composer/index.d.ts +174 -0
  30. package/dist/node_modules/nodemailer/dist/cjs/mail-composer/index.js +613 -0
  31. package/dist/node_modules/nodemailer/dist/cjs/mailer/index.d.ts +237 -0
  32. package/dist/node_modules/nodemailer/dist/cjs/mailer/index.js +415 -0
  33. package/dist/node_modules/nodemailer/dist/cjs/mailer/mail-message.d.ts +97 -0
  34. package/dist/node_modules/nodemailer/dist/cjs/mailer/mail-message.js +342 -0
  35. package/dist/node_modules/nodemailer/dist/cjs/mime-funcs/index.d.ts +161 -0
  36. package/dist/node_modules/nodemailer/dist/cjs/mime-funcs/index.js +787 -0
  37. package/dist/node_modules/nodemailer/dist/cjs/mime-funcs/mime-types.d.ts +2 -0
  38. package/dist/node_modules/nodemailer/dist/cjs/mime-funcs/mime-types.js +2103 -0
  39. package/dist/node_modules/nodemailer/dist/cjs/mime-node/index.d.ts +333 -0
  40. package/dist/node_modules/nodemailer/dist/cjs/mime-node/index.js +1493 -0
  41. package/dist/node_modules/nodemailer/dist/cjs/mime-node/last-newline.d.ts +5 -0
  42. package/dist/node_modules/nodemailer/dist/cjs/mime-node/last-newline.js +32 -0
  43. package/dist/node_modules/nodemailer/dist/cjs/mime-node/le-unix.d.ts +9 -0
  44. package/dist/node_modules/nodemailer/dist/cjs/mime-node/le-unix.js +40 -0
  45. package/dist/node_modules/nodemailer/dist/cjs/mime-node/le-windows.d.ts +10 -0
  46. package/dist/node_modules/nodemailer/dist/cjs/mime-node/le-windows.js +47 -0
  47. package/dist/node_modules/nodemailer/dist/cjs/nodemailer.d.ts +124 -0
  48. package/dist/node_modules/nodemailer/dist/cjs/nodemailer.js +1 -0
  49. package/dist/node_modules/nodemailer/dist/cjs/package-info.d.ts +3 -0
  50. package/dist/node_modules/nodemailer/dist/cjs/package-info.js +7 -0
  51. package/dist/node_modules/nodemailer/dist/cjs/package.json +3 -0
  52. package/dist/node_modules/nodemailer/dist/cjs/punycode/index.d.ts +73 -0
  53. package/dist/node_modules/nodemailer/{lib → dist/cjs}/punycode/index.js +63 -112
  54. package/dist/node_modules/nodemailer/dist/cjs/qp/index.d.ts +32 -0
  55. package/dist/node_modules/nodemailer/dist/cjs/qp/index.js +207 -0
  56. package/dist/node_modules/nodemailer/dist/cjs/sendmail-transport/index.d.ts +69 -0
  57. package/dist/node_modules/nodemailer/dist/cjs/sendmail-transport/index.js +210 -0
  58. package/dist/node_modules/nodemailer/dist/cjs/ses-transport/index.d.ts +112 -0
  59. package/dist/node_modules/nodemailer/dist/cjs/ses-transport/index.js +252 -0
  60. package/dist/node_modules/nodemailer/dist/cjs/shared/index.d.ts +260 -0
  61. package/dist/node_modules/nodemailer/dist/cjs/shared/index.js +680 -0
  62. package/dist/node_modules/nodemailer/dist/cjs/shared/objects.d.ts +23 -0
  63. package/dist/node_modules/nodemailer/dist/cjs/shared/objects.js +43 -0
  64. package/dist/node_modules/nodemailer/dist/cjs/shared/url.d.ts +21 -0
  65. package/dist/node_modules/nodemailer/dist/cjs/shared/url.js +255 -0
  66. package/dist/node_modules/nodemailer/dist/cjs/smtp-connection/data-stream.d.ts +15 -0
  67. package/dist/node_modules/nodemailer/dist/cjs/smtp-connection/data-stream.js +108 -0
  68. package/dist/node_modules/nodemailer/dist/cjs/smtp-connection/http-proxy-client.d.ts +47 -0
  69. package/dist/node_modules/nodemailer/dist/cjs/smtp-connection/http-proxy-client.js +189 -0
  70. package/dist/node_modules/nodemailer/dist/cjs/smtp-connection/index.d.ts +416 -0
  71. package/dist/node_modules/nodemailer/dist/cjs/smtp-connection/index.js +1837 -0
  72. package/dist/node_modules/nodemailer/dist/cjs/smtp-pool/index.d.ts +133 -0
  73. package/dist/node_modules/nodemailer/dist/cjs/smtp-pool/index.js +569 -0
  74. package/dist/node_modules/nodemailer/dist/cjs/smtp-pool/pool-resource.d.ts +62 -0
  75. package/dist/node_modules/nodemailer/dist/cjs/smtp-pool/pool-resource.js +257 -0
  76. package/dist/node_modules/nodemailer/dist/cjs/smtp-transport/index.d.ts +156 -0
  77. package/dist/node_modules/nodemailer/dist/cjs/smtp-transport/index.js +371 -0
  78. package/dist/node_modules/nodemailer/dist/cjs/stream-transport/index.d.ts +65 -0
  79. package/dist/node_modules/nodemailer/dist/cjs/stream-transport/index.js +146 -0
  80. package/dist/node_modules/nodemailer/dist/cjs/well-known/index.d.ts +35 -0
  81. package/dist/node_modules/nodemailer/dist/cjs/well-known/index.js +41 -0
  82. package/dist/node_modules/nodemailer/dist/cjs/well-known/services.d.ts +2 -0
  83. package/dist/node_modules/nodemailer/dist/cjs/well-known/services.js +674 -0
  84. package/dist/node_modules/nodemailer/dist/cjs/xoauth2/index.d.ts +201 -0
  85. package/dist/node_modules/nodemailer/dist/cjs/xoauth2/index.js +426 -0
  86. package/dist/node_modules/nodemailer/dist/esm/addressparser/index.d.ts +59 -0
  87. package/dist/node_modules/nodemailer/dist/esm/addressparser/index.js +786 -0
  88. package/dist/node_modules/nodemailer/dist/esm/base64/index.d.ts +36 -0
  89. package/dist/node_modules/nodemailer/{lib → dist/esm}/base64/index.js +39 -68
  90. package/dist/node_modules/nodemailer/dist/esm/dkim/index.d.ts +52 -0
  91. package/dist/node_modules/nodemailer/{lib → dist/esm}/dkim/index.js +62 -92
  92. package/dist/node_modules/nodemailer/dist/esm/dkim/message-parser.d.ts +48 -0
  93. package/dist/node_modules/nodemailer/dist/esm/dkim/message-parser.js +176 -0
  94. package/dist/node_modules/nodemailer/dist/esm/dkim/relaxed-body.d.ts +36 -0
  95. package/dist/node_modules/nodemailer/dist/esm/dkim/relaxed-body.js +141 -0
  96. package/dist/node_modules/nodemailer/dist/esm/dkim/sign.d.ts +52 -0
  97. package/dist/node_modules/nodemailer/dist/esm/dkim/sign.js +125 -0
  98. package/dist/node_modules/nodemailer/dist/esm/errors.d.ts +96 -0
  99. package/dist/node_modules/nodemailer/dist/esm/errors.js +67 -0
  100. package/dist/node_modules/nodemailer/dist/esm/fetch/cookies.d.ts +107 -0
  101. package/dist/node_modules/nodemailer/dist/esm/fetch/cookies.js +242 -0
  102. package/dist/node_modules/nodemailer/dist/esm/fetch/index.d.ts +65 -0
  103. package/dist/node_modules/nodemailer/dist/esm/fetch/index.js +344 -0
  104. package/dist/node_modules/nodemailer/dist/esm/json-transport/index.d.ts +64 -0
  105. package/dist/node_modules/nodemailer/dist/esm/json-transport/index.js +62 -0
  106. package/dist/node_modules/nodemailer/dist/esm/mail-composer/index.d.ts +174 -0
  107. package/dist/node_modules/nodemailer/{lib → dist/esm}/mail-composer/index.js +283 -275
  108. package/dist/node_modules/nodemailer/dist/esm/mailer/index.d.ts +237 -0
  109. package/dist/node_modules/nodemailer/{lib → dist/esm}/mailer/index.js +151 -205
  110. package/dist/node_modules/nodemailer/dist/esm/mailer/mail-message.d.ts +97 -0
  111. package/dist/node_modules/nodemailer/{lib → dist/esm}/mailer/mail-message.js +111 -125
  112. package/dist/node_modules/nodemailer/dist/esm/mime-funcs/index.d.ts +161 -0
  113. package/dist/node_modules/nodemailer/dist/esm/mime-funcs/index.js +738 -0
  114. package/dist/node_modules/nodemailer/dist/esm/mime-funcs/mime-types.d.ts +2 -0
  115. package/dist/node_modules/nodemailer/{lib → dist/esm}/mime-funcs/mime-types.js +43 -49
  116. package/dist/node_modules/nodemailer/dist/esm/mime-node/index.d.ts +333 -0
  117. package/dist/node_modules/nodemailer/{lib → dist/esm}/mime-node/index.js +576 -437
  118. package/dist/node_modules/nodemailer/dist/esm/mime-node/last-newline.d.ts +5 -0
  119. package/dist/node_modules/nodemailer/{lib → dist/esm}/mime-node/last-newline.js +4 -10
  120. package/dist/node_modules/nodemailer/dist/esm/mime-node/le-unix.d.ts +9 -0
  121. package/dist/node_modules/nodemailer/{lib → dist/esm}/mime-node/le-unix.js +7 -15
  122. package/dist/node_modules/nodemailer/dist/esm/mime-node/le-windows.d.ts +10 -0
  123. package/dist/node_modules/nodemailer/{lib → dist/esm}/mime-node/le-windows.js +6 -16
  124. package/dist/node_modules/nodemailer/dist/esm/nodemailer.d.ts +124 -0
  125. package/dist/node_modules/nodemailer/dist/esm/nodemailer.js +166 -0
  126. package/dist/node_modules/nodemailer/dist/esm/package-info.d.ts +3 -0
  127. package/dist/node_modules/nodemailer/dist/esm/package-info.js +4 -0
  128. package/dist/node_modules/nodemailer/dist/esm/package.json +3 -0
  129. package/dist/node_modules/nodemailer/dist/esm/punycode/index.d.ts +73 -0
  130. package/dist/node_modules/nodemailer/dist/esm/punycode/index.js +405 -0
  131. package/dist/node_modules/nodemailer/dist/esm/qp/index.d.ts +32 -0
  132. package/dist/node_modules/nodemailer/{lib → dist/esm}/qp/index.js +59 -77
  133. package/dist/node_modules/nodemailer/dist/esm/sendmail-transport/index.d.ts +69 -0
  134. package/dist/node_modules/nodemailer/dist/esm/sendmail-transport/index.js +170 -0
  135. package/dist/node_modules/nodemailer/dist/esm/ses-transport/index.d.ts +112 -0
  136. package/dist/node_modules/nodemailer/dist/esm/ses-transport/index.js +212 -0
  137. package/dist/node_modules/nodemailer/dist/esm/shared/index.d.ts +260 -0
  138. package/dist/node_modules/nodemailer/dist/esm/shared/index.js +631 -0
  139. package/dist/node_modules/nodemailer/dist/esm/shared/objects.d.ts +23 -0
  140. package/dist/node_modules/nodemailer/dist/esm/shared/objects.js +38 -0
  141. package/dist/node_modules/nodemailer/dist/esm/shared/url.d.ts +21 -0
  142. package/dist/node_modules/nodemailer/dist/esm/shared/url.js +214 -0
  143. package/dist/node_modules/nodemailer/dist/esm/smtp-connection/data-stream.d.ts +15 -0
  144. package/dist/node_modules/nodemailer/dist/esm/smtp-connection/data-stream.js +103 -0
  145. package/dist/node_modules/nodemailer/dist/esm/smtp-connection/http-proxy-client.d.ts +47 -0
  146. package/dist/node_modules/nodemailer/dist/esm/smtp-connection/http-proxy-client.js +149 -0
  147. package/dist/node_modules/nodemailer/dist/esm/smtp-connection/index.d.ts +416 -0
  148. package/dist/node_modules/nodemailer/dist/esm/smtp-connection/index.js +1797 -0
  149. package/dist/node_modules/nodemailer/dist/esm/smtp-pool/index.d.ts +133 -0
  150. package/dist/node_modules/nodemailer/{lib → dist/esm}/smtp-pool/index.js +195 -314
  151. package/dist/node_modules/nodemailer/dist/esm/smtp-pool/pool-resource.d.ts +62 -0
  152. package/dist/node_modules/nodemailer/{lib → dist/esm}/smtp-pool/pool-resource.js +70 -107
  153. package/dist/node_modules/nodemailer/dist/esm/smtp-transport/index.d.ts +156 -0
  154. package/dist/node_modules/nodemailer/dist/esm/smtp-transport/index.js +331 -0
  155. package/dist/node_modules/nodemailer/dist/esm/stream-transport/index.d.ts +65 -0
  156. package/dist/node_modules/nodemailer/dist/esm/stream-transport/index.js +106 -0
  157. package/dist/node_modules/nodemailer/dist/esm/well-known/index.d.ts +35 -0
  158. package/dist/node_modules/nodemailer/{lib → dist/esm}/well-known/index.js +12 -23
  159. package/dist/node_modules/nodemailer/dist/esm/well-known/services.d.ts +2 -0
  160. package/dist/node_modules/nodemailer/dist/esm/well-known/services.js +671 -0
  161. package/dist/node_modules/nodemailer/dist/esm/xoauth2/index.d.ts +201 -0
  162. package/dist/node_modules/nodemailer/dist/esm/xoauth2/index.js +386 -0
  163. package/dist/node_modules/nodemailer/dist/well-known/services.json +640 -0
  164. package/dist/node_modules/nodemailer/package.json +1 -1
  165. package/package.json +4 -4
  166. package/dist/node_modules/nodemailer/.gitattributes +0 -6
  167. package/dist/node_modules/nodemailer/.ncurc.js +0 -7
  168. package/dist/node_modules/nodemailer/.prettierrc.js +0 -8
  169. package/dist/node_modules/nodemailer/lib/addressparser/index.js +0 -313
  170. package/dist/node_modules/nodemailer/lib/dkim/message-parser.js +0 -155
  171. package/dist/node_modules/nodemailer/lib/dkim/relaxed-body.js +0 -154
  172. package/dist/node_modules/nodemailer/lib/dkim/sign.js +0 -117
  173. package/dist/node_modules/nodemailer/lib/fetch/cookies.js +0 -281
  174. package/dist/node_modules/nodemailer/lib/fetch/index.js +0 -274
  175. package/dist/node_modules/nodemailer/lib/json-transport/index.js +0 -82
  176. package/dist/node_modules/nodemailer/lib/mime-funcs/index.js +0 -625
  177. package/dist/node_modules/nodemailer/lib/nodemailer.js +0 -1
  178. package/dist/node_modules/nodemailer/lib/sendmail-transport/index.js +0 -210
  179. package/dist/node_modules/nodemailer/lib/ses-transport/index.js +0 -349
  180. package/dist/node_modules/nodemailer/lib/shared/index.js +0 -688
  181. package/dist/node_modules/nodemailer/lib/smtp-connection/data-stream.js +0 -108
  182. package/dist/node_modules/nodemailer/lib/smtp-connection/http-proxy-client.js +0 -143
  183. package/dist/node_modules/nodemailer/lib/smtp-connection/index.js +0 -1825
  184. package/dist/node_modules/nodemailer/lib/smtp-transport/index.js +0 -416
  185. package/dist/node_modules/nodemailer/lib/stream-transport/index.js +0 -135
  186. package/dist/node_modules/nodemailer/lib/well-known/services.json +0 -343
  187. package/dist/node_modules/nodemailer/lib/xoauth2/index.js +0 -376
@@ -0,0 +1,176 @@
1
+ import { Transform } from 'node:stream';
2
+ /**
3
+ * Drops the SP and HTAB from both ends of a field name.
4
+ *
5
+ * An index scan rather than `/^[ \t]+|[ \t]+$/g`, which retries the trailing branch at
6
+ * every offset of a blank run that is followed by other text: the run is consumed greedily,
7
+ * `$` fails, and the engine gives the characters back one at a time before moving on to
8
+ * start the same walk one offset further in. A field name carrying a 128 KiB run of spaces
9
+ * between two atoms took about 6.7 seconds to trim, and the cost grows with its square.
10
+ *
11
+ * Not `.trim()`, which takes the other Unicode spaces along: an NBSP in front of a field
12
+ * name would come off and select the name into the signed set, where the relaxed
13
+ * canonicalization in sign.ts deliberately leaves everything but SP and HTAB alone.
14
+ *
15
+ * @param str Field name to trim
16
+ * @return The field name without the surrounding SP and HTAB
17
+ */
18
+ function _trimFieldName(str) {
19
+ let start = 0;
20
+ let end = str.length;
21
+ while (start < end && (str.charCodeAt(start) === 0x20 || str.charCodeAt(start) === 0x09)) {
22
+ start++;
23
+ }
24
+ while (end > start && (str.charCodeAt(end - 1) === 0x20 || str.charCodeAt(end - 1) === 0x09)) {
25
+ end--;
26
+ }
27
+ return str.slice(start, end);
28
+ }
29
+ /**
30
+ * MessageParser instance is a transform stream that separates message headers
31
+ * from the rest of the body. Headers are emitted with the 'headers' event. Message
32
+ * body is passed on as the resulting stream.
33
+ */
34
+ class MessageParser extends Transform {
35
+ constructor(options) {
36
+ super(options);
37
+ this.lastBytes = Buffer.alloc(4);
38
+ this.headersParsed = false;
39
+ this.headerBytes = 0;
40
+ this.headerChunks = [];
41
+ this.rawHeaders = false;
42
+ this.bodySize = 0;
43
+ }
44
+ /**
45
+ * Keeps count of the last 4 bytes in order to detect line breaks on chunk boundaries
46
+ *
47
+ * @param data Next data chunk from the stream
48
+ */
49
+ updateLastBytes(data) {
50
+ const lblen = this.lastBytes.length;
51
+ const nblen = Math.min(data.length, lblen);
52
+ // shift existing bytes
53
+ for (let i = 0, len = lblen - nblen; i < len; i++) {
54
+ this.lastBytes[i] = this.lastBytes[i + nblen];
55
+ }
56
+ // add new bytes
57
+ for (let i = 1; i <= nblen; i++) {
58
+ this.lastBytes[lblen - i] = data[data.length - i];
59
+ }
60
+ }
61
+ /**
62
+ * Finds and removes message headers from the remaining body. We want to keep
63
+ * headers separated until final delivery to be able to modify these
64
+ *
65
+ * @param data Next chunk of data
66
+ * @return Returns true if headers are already found or false otherwise
67
+ */
68
+ checkHeaders(data) {
69
+ if (this.headersParsed) {
70
+ return true;
71
+ }
72
+ const lblen = this.lastBytes.length;
73
+ let headerPos = 0;
74
+ for (let i = 0, len = this.lastBytes.length + data.length; i < len; i++) {
75
+ let chr;
76
+ if (i < lblen) {
77
+ chr = this.lastBytes[i];
78
+ }
79
+ else {
80
+ chr = data[i - lblen];
81
+ }
82
+ if (chr === 0x0a && i) {
83
+ const pr1 = i - 1 < lblen ? this.lastBytes[i - 1] : data[i - 1 - lblen];
84
+ const pr2 = i > 1 ? (i - 2 < lblen ? this.lastBytes[i - 2] : data[i - 2 - lblen]) : false;
85
+ if (pr1 === 0x0a) {
86
+ this.headersParsed = true;
87
+ headerPos = i - lblen + 1;
88
+ this.headerBytes += headerPos;
89
+ break;
90
+ }
91
+ else if (pr1 === 0x0d && pr2 === 0x0a) {
92
+ this.headersParsed = true;
93
+ headerPos = i - lblen + 1;
94
+ this.headerBytes += headerPos;
95
+ break;
96
+ }
97
+ }
98
+ }
99
+ if (this.headersParsed) {
100
+ this.headerChunks.push(data.slice(0, headerPos));
101
+ this.rawHeaders = Buffer.concat(this.headerChunks, this.headerBytes);
102
+ this.headerChunks = null;
103
+ this.emit('headers', this.parseHeaders());
104
+ if (data.length > headerPos) {
105
+ const chunk = data.slice(headerPos);
106
+ this.bodySize += chunk.length;
107
+ // this would be the first chunk of data sent downstream
108
+ setImmediate(() => this.push(chunk));
109
+ }
110
+ return false;
111
+ }
112
+ this.headerBytes += data.length;
113
+ this.headerChunks.push(data);
114
+ // store last 4 bytes to catch header break
115
+ this.updateLastBytes(data);
116
+ return false;
117
+ }
118
+ /** @internal */
119
+ _transform(chunk, encoding, callback) {
120
+ if (!chunk || !chunk.length) {
121
+ return callback();
122
+ }
123
+ if (typeof chunk === 'string') {
124
+ chunk = Buffer.from(chunk, encoding);
125
+ }
126
+ let headersFound;
127
+ try {
128
+ headersFound = this.checkHeaders(chunk);
129
+ }
130
+ catch (E) {
131
+ return callback(E);
132
+ }
133
+ if (headersFound) {
134
+ this.bodySize += chunk.length;
135
+ this.push(chunk);
136
+ }
137
+ setImmediate(callback);
138
+ }
139
+ /** @internal */
140
+ _flush(callback) {
141
+ if (this.headerChunks) {
142
+ // no empty line was seen, so the message consists of headers only
143
+ this.rawHeaders = Buffer.concat(this.headerChunks, this.headerBytes);
144
+ this.headerChunks = null;
145
+ this.emit('headers', this.parseHeaders());
146
+ }
147
+ callback();
148
+ }
149
+ parseHeaders() {
150
+ // the header bytes are kept as they are, one character per byte, so the
151
+ // signature covers exactly the bytes the receiving side canonicalizes
152
+ // Only SP and HTAB fold a line, and only they are trimmed from the field name, the
153
+ // same whitespace the relaxed canonicalization in sign.ts works with
154
+ const rawLines = (this.rawHeaders || Buffer.alloc(0)).toString('binary').split(/\r?\n/);
155
+ // Unfold in a single forward pass and only ever test a freshly split line for the
156
+ // continuation prefix. Testing an already merged line instead would rescan a string
157
+ // that grows with every continuation line, so a header folded into many continuation
158
+ // lines (a large recipient list, for example) would take quadratic time to unfold
159
+ const lines = [];
160
+ for (const rawLine of rawLines) {
161
+ if (lines.length && /^[ \t]/.test(rawLine)) {
162
+ lines[lines.length - 1] += '\n' + rawLine;
163
+ }
164
+ else {
165
+ lines.push(rawLine);
166
+ }
167
+ }
168
+ return lines
169
+ .filter(line => /[^ \t\r]/.test(line))
170
+ .map(line => ({
171
+ key: _trimFieldName(line.substr(0, line.indexOf(':'))).toLowerCase(),
172
+ line
173
+ }));
174
+ }
175
+ }
176
+ export default MessageParser;
@@ -0,0 +1,36 @@
1
+ import { Transform } from 'node:stream';
2
+ import crypto from 'node:crypto';
3
+ /**
4
+ * Options for the relaxed body hash stream
5
+ */
6
+ export interface RelaxedBodyOptions {
7
+ /** Hash algorithm for the body hash, defaults to sha256 */
8
+ hashAlgo?: string | undefined;
9
+ /** Collect the canonicalized body and emit it with the 'hash' event */
10
+ debug?: boolean | undefined;
11
+ }
12
+ /**
13
+ * Passes the message body through unchanged and hashes its relaxed
14
+ * canonicalization (RFC 6376 section 3.4.4) on the side: whitespace at the end
15
+ * of a line is dropped, runs of whitespace within a line become a single space,
16
+ * every line ends with CRLF, empty lines at the end of the body are ignored and
17
+ * a non-empty body always ends with CRLF. Bytes are canonicalized as they arrive,
18
+ * so a line of any length costs constant memory.
19
+ */
20
+ declare class RelaxedBody extends Transform {
21
+ bodyHash: crypto.Hash;
22
+ /** Bytes of the original body seen so far */
23
+ byteLength: number;
24
+ debug: boolean | undefined;
25
+ constructor(options?: RelaxedBodyOptions);
26
+ updateHash(chunk: Buffer, final?: boolean): void;
27
+ }
28
+ /**
29
+ * Type aliases in the layout of @types/nodemailer, so `RelaxedBody.Options` style references keep working
30
+ */
31
+ declare namespace RelaxedBody {
32
+ type Options = RelaxedBodyOptions;
33
+ }
34
+ /** The same alias as a module level export, for `import * as RelaxedBody` and `import RelaxedBody = require()` */
35
+ export type { RelaxedBodyOptions as Options };
36
+ export default RelaxedBody;
@@ -0,0 +1,141 @@
1
+ // streams through a message body and calculates relaxed body hash
2
+ import { Transform } from 'node:stream';
3
+ import crypto from 'node:crypto';
4
+ const CHAR_CR = 0x0d;
5
+ const CHAR_LF = 0x0a;
6
+ const CHAR_SPACE = 0x20;
7
+ const CHAR_TAB = 0x09;
8
+ const CRLF = Buffer.from('\r\n');
9
+ // a run of empty lines is hashed from this buffer in slices
10
+ const EMPTY_LINES = Buffer.alloc(4096, CRLF);
11
+ /**
12
+ * Passes the message body through unchanged and hashes its relaxed
13
+ * canonicalization (RFC 6376 section 3.4.4) on the side: whitespace at the end
14
+ * of a line is dropped, runs of whitespace within a line become a single space,
15
+ * every line ends with CRLF, empty lines at the end of the body are ignored and
16
+ * a non-empty body always ends with CRLF. Bytes are canonicalized as they arrive,
17
+ * so a line of any length costs constant memory.
18
+ */
19
+ class RelaxedBody extends Transform {
20
+ constructor(options) {
21
+ super();
22
+ options = options || {};
23
+ this.bodyHash = crypto.createHash(options.hashAlgo || 'sha256');
24
+ this.byteLength = 0;
25
+ this.debug = options.debug;
26
+ this._debugBody = options.debug ? [] : false;
27
+ this._lineHasContent = false;
28
+ this._pendingWsp = false;
29
+ this._pendingCr = false;
30
+ this._pendingEmptyLines = 0;
31
+ }
32
+ /** @internal */
33
+ _hashCanonical(data) {
34
+ if (!data.length) {
35
+ return;
36
+ }
37
+ this.bodyHash.update(data);
38
+ if (this._debugBody) {
39
+ this._debugBody.push(Buffer.from(data));
40
+ }
41
+ }
42
+ /** @internal */
43
+ _hashEmptyLines() {
44
+ while (this._pendingEmptyLines > 0) {
45
+ const count = Math.min(this._pendingEmptyLines, EMPTY_LINES.length / 2);
46
+ this._hashCanonical(EMPTY_LINES.subarray(0, count * 2));
47
+ this._pendingEmptyLines -= count;
48
+ }
49
+ }
50
+ /**
51
+ * Writes a content byte, with the space a pending run of whitespace collapses to,
52
+ * into the output buffer and returns the new write position. Kept a method rather
53
+ * than a closure so the write position stays a plain local in the byte loop
54
+ * @internal
55
+ */
56
+ _emitContent(out, outPos, c) {
57
+ if (!this._lineHasContent) {
58
+ if (this._pendingEmptyLines) {
59
+ // the first content byte of a line is where the empty lines before it
60
+ // become part of the body, so hash what is in the buffer before them
61
+ this._hashCanonical(out.subarray(0, outPos));
62
+ outPos = 0;
63
+ this._hashEmptyLines();
64
+ }
65
+ this._lineHasContent = true;
66
+ }
67
+ if (this._pendingWsp) {
68
+ out[outPos++] = CHAR_SPACE;
69
+ this._pendingWsp = false;
70
+ }
71
+ out[outPos++] = c;
72
+ return outPos;
73
+ }
74
+ updateHash(chunk, final) {
75
+ // every byte contributes itself at most once, plus a CR for a bare LF
76
+ // and, once per chunk, a pending space and CR carried over from before
77
+ const out = Buffer.allocUnsafe(chunk.length * 2 + 2);
78
+ let outPos = 0;
79
+ for (let i = 0; i < chunk.length; i++) {
80
+ const c = chunk[i];
81
+ if (c === CHAR_LF) {
82
+ // end of line, a CR right before it and any trailing whitespace are dropped
83
+ if (this._lineHasContent) {
84
+ out[outPos++] = CHAR_CR;
85
+ out[outPos++] = CHAR_LF;
86
+ this._lineHasContent = false;
87
+ }
88
+ else {
89
+ this._pendingEmptyLines++;
90
+ }
91
+ this._pendingWsp = false;
92
+ this._pendingCr = false;
93
+ continue;
94
+ }
95
+ if (this._pendingCr) {
96
+ // not followed by LF, so the CR is content
97
+ outPos = this._emitContent(out, outPos, CHAR_CR);
98
+ this._pendingCr = false;
99
+ }
100
+ if (c === CHAR_CR) {
101
+ this._pendingCr = true;
102
+ }
103
+ else if (c === CHAR_SPACE || c === CHAR_TAB) {
104
+ this._pendingWsp = true;
105
+ }
106
+ else {
107
+ outPos = this._emitContent(out, outPos, c);
108
+ }
109
+ }
110
+ if (final && this._pendingCr) {
111
+ // a CR at the very end of the body is content
112
+ outPos = this._emitContent(out, outPos, CHAR_CR);
113
+ this._pendingCr = false;
114
+ }
115
+ this._hashCanonical(out.subarray(0, outPos));
116
+ }
117
+ /** @internal */
118
+ _transform(chunk, encoding, callback) {
119
+ if (!chunk || !chunk.length) {
120
+ return callback();
121
+ }
122
+ if (typeof chunk === 'string') {
123
+ chunk = Buffer.from(chunk, encoding);
124
+ }
125
+ this.updateHash(chunk);
126
+ this.byteLength += chunk.length;
127
+ this.push(chunk);
128
+ callback();
129
+ }
130
+ /** @internal */
131
+ _flush(callback) {
132
+ this.updateHash(Buffer.alloc(0), true);
133
+ if (this._lineHasContent) {
134
+ // the body does not end with a line break, add one
135
+ this._hashCanonical(CRLF);
136
+ }
137
+ this.emit('hash', this.bodyHash.digest('base64'), this.debug ? Buffer.concat(this._debugBody) : false);
138
+ callback();
139
+ }
140
+ }
141
+ export default RelaxedBody;
@@ -0,0 +1,52 @@
1
+ import crypto from 'node:crypto';
2
+ import type { NodemailerError } from '../errors.js';
3
+ import type { MessageParserHeaderLine } from './message-parser.js';
4
+ /**
5
+ * Private key accepted by crypto.Sign#sign: a PEM string, a Buffer, a KeyObject or an
6
+ * object with the key and its passphrase
7
+ */
8
+ export type DKIMPrivateKey = crypto.KeyLike | crypto.SignKeyObjectInput | crypto.SignPrivateKeyInput;
9
+ /**
10
+ * Options for the DKIM signature header generator
11
+ */
12
+ export interface DKIMKey {
13
+ /** Domain name to be signed for */
14
+ domainName?: string | undefined;
15
+ /** DKIM key selector to use */
16
+ keySelector?: string | undefined;
17
+ /** DKIM private key to use */
18
+ privateKey?: DKIMPrivateKey | undefined;
19
+ }
20
+ export interface DKIMSignOptions extends DKIMKey {
21
+ /** Colon separated list of header field names to sign, defaults to the RFC4871 list */
22
+ headerFieldNames?: string | undefined;
23
+ /** Colon separated list of header field names to leave out of the signature */
24
+ skipFields?: string | undefined;
25
+ }
26
+ /**
27
+ * Canonicalized headers and the list of field names that went into them
28
+ */
29
+ export interface DKIMRelaxedHeaders {
30
+ /** Relaxed header lines, each terminated with CRLF, one character per byte ('binary' encoding) */
31
+ headers: string;
32
+ /** Colon separated list of the field names that were included */
33
+ fieldNames: string;
34
+ }
35
+ /**
36
+ * Returns DKIM signature header line
37
+ *
38
+ * @param headers Parsed headers object from MessageParser
39
+ * @param hashAlgo Hash algorithm the body hash was calculated with, for example "sha256"
40
+ * @param bodyHash Base64 encoded hash of the message
41
+ * @param options DKIM options
42
+ * @param options.domainName Domain name to be signed for
43
+ * @param options.keySelector DKIM key selector to use
44
+ * @param options.privateKey DKIM private key to use
45
+ * @return Complete header line
46
+ */
47
+ declare function sign(headers: MessageParserHeaderLine[], hashAlgo: string, bodyHash: string, options?: DKIMSignOptions): string | false;
48
+ declare namespace sign {
49
+ var relaxedHeaders: (headers: MessageParserHeaderLine[], fieldNames?: string, skipFields?: string) => DKIMRelaxedHeaders;
50
+ var unsupportedHashAlgoError: (hashAlgo: string) => NodemailerError;
51
+ }
52
+ export default sign;
@@ -0,0 +1,125 @@
1
+ import * as punycode from '../punycode/index.js';
2
+ import * as mimeFuncs from '../mime-funcs/index.js';
3
+ import crypto from 'node:crypto';
4
+ import * as errors from '../errors.js';
5
+ /**
6
+ * Error for a hashAlgo value the crypto module does not know
7
+ */
8
+ function unsupportedHashAlgoError(hashAlgo) {
9
+ const err = new Error('Unsupported DKIM hash algorithm "' + hashAlgo + '"');
10
+ err.code = errors.ECONFIG;
11
+ return err;
12
+ }
13
+ /**
14
+ * Returns DKIM signature header line
15
+ *
16
+ * @param headers Parsed headers object from MessageParser
17
+ * @param hashAlgo Hash algorithm the body hash was calculated with, for example "sha256"
18
+ * @param bodyHash Base64 encoded hash of the message
19
+ * @param options DKIM options
20
+ * @param options.domainName Domain name to be signed for
21
+ * @param options.keySelector DKIM key selector to use
22
+ * @param options.privateKey DKIM private key to use
23
+ * @return Complete header line
24
+ */
25
+ function sign(headers, hashAlgo, bodyHash, options) {
26
+ options = options || {};
27
+ // all listed fields from RFC4871 #5.5
28
+ const defaultFieldNames = 'From:Sender:Reply-To:Subject:Date:Message-ID:To:' +
29
+ 'Cc:MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID:' +
30
+ 'Content-Description:Resent-Date:Resent-From:Resent-Sender:' +
31
+ 'Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:' +
32
+ 'List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post:' +
33
+ 'List-Owner:List-Archive';
34
+ const fieldNames = options.headerFieldNames || defaultFieldNames;
35
+ const canonicalizedHeaderData = relaxedHeaders(headers, fieldNames, options.skipFields);
36
+ const dkimHeader = generateDKIMHeader(options.domainName, options.keySelector, canonicalizedHeaderData.fieldNames, hashAlgo, bodyHash);
37
+ canonicalizedHeaderData.headers += 'dkim-signature:' + relaxedHeaderLine(dkimHeader);
38
+ let signer;
39
+ try {
40
+ signer = crypto.createSign(('rsa-' + hashAlgo).toUpperCase());
41
+ }
42
+ catch (_E) {
43
+ throw unsupportedHashAlgoError(hashAlgo);
44
+ }
45
+ // the header lines are 'binary' strings, so this reproduces the original header bytes
46
+ signer.update(canonicalizedHeaderData.headers, 'latin1');
47
+ let signature;
48
+ try {
49
+ signature = signer.sign(options.privateKey, 'base64');
50
+ }
51
+ catch (_E) {
52
+ return false;
53
+ }
54
+ return dkimHeader + signature.replace(/(^.{73}|.{75}(?!\r?\n|\r))/g, '$&\r\n ').trim();
55
+ }
56
+ sign.relaxedHeaders = relaxedHeaders;
57
+ sign.unsupportedHashAlgoError = unsupportedHashAlgoError;
58
+ export default sign;
59
+ function generateDKIMHeader(domainName, keySelector, fieldNames, hashAlgo, bodyHash) {
60
+ // the caller supplied tag values are interpolated straight into the tag list, and none of
61
+ // them has any way to carry a control char, DEL, or one of the delimiters that would close
62
+ // the value and open a tag of its own
63
+ const cleanTagValue = (value) => (value || '').toString().replace(/[\x00-\x1f\x7f;=]/g, '');
64
+ const dkim = [
65
+ 'v=1',
66
+ 'a=rsa-' + hashAlgo,
67
+ 'c=relaxed/relaxed',
68
+ 'd=' + punycode.toASCII(cleanTagValue(domainName)),
69
+ 'q=dns/txt',
70
+ 's=' + cleanTagValue(keySelector),
71
+ 'bh=' + bodyHash,
72
+ 'h=' + cleanTagValue(fieldNames)
73
+ ].join('; ');
74
+ return mimeFuncs.foldLines('DKIM-Signature: ' + dkim, 76) + ';\r\n b=';
75
+ }
76
+ function relaxedHeaders(headers, fieldNames, skipFields) {
77
+ const includedFields = new Set();
78
+ const skip = new Set();
79
+ const headerFields = new Map();
80
+ (skipFields || '')
81
+ .toLowerCase()
82
+ .split(':')
83
+ .forEach(field => {
84
+ skip.add(field.trim());
85
+ });
86
+ (fieldNames || '')
87
+ .toLowerCase()
88
+ .split(':')
89
+ .filter(field => !skip.has(field.trim()))
90
+ .forEach(field => {
91
+ includedFields.add(field.trim());
92
+ });
93
+ for (let i = headers.length - 1; i >= 0; i--) {
94
+ const line = headers[i];
95
+ // only include the first value from bottom to top
96
+ if (includedFields.has(line.key) && !headerFields.has(line.key)) {
97
+ headerFields.set(line.key, relaxedHeaderLine(line.line));
98
+ }
99
+ }
100
+ const headersList = [];
101
+ const fields = [];
102
+ includedFields.forEach(field => {
103
+ if (headerFields.has(field)) {
104
+ fields.push(field);
105
+ headersList.push(field + ':' + headerFields.get(field));
106
+ }
107
+ });
108
+ return {
109
+ headers: headersList.join('\r\n') + '\r\n',
110
+ fieldNames: fields.join(':')
111
+ };
112
+ }
113
+ /**
114
+ * Relaxed canonicalization of a header field value (RFC 6376 section 3.4.2): unfold, turn
115
+ * every run of SP and HTAB into a single SP and drop the whitespace next to the colon and
116
+ * at the end. Only SP and HTAB count as whitespace, so bytes that decode to other space
117
+ * characters, such as a non-breaking space in a UTF-8 header, stay as they are
118
+ */
119
+ function relaxedHeaderLine(line) {
120
+ return line
121
+ .substr(line.indexOf(':') + 1)
122
+ .replace(/\r?\n/g, '')
123
+ .replace(/[ \t]+/g, ' ')
124
+ .replace(/^ | $/g, '');
125
+ }
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Nodemailer Error Codes
3
+ *
4
+ * Centralized error code definitions for consistent error handling.
5
+ *
6
+ * Usage:
7
+ * import * as errors from './errors.js';
8
+ * const err: NodemailerError = new Error('Connection closed');
9
+ * err.code = errors.ECONNECTION;
10
+ */
11
+ /**
12
+ * Error code descriptions for documentation and debugging
13
+ */
14
+ export declare const ERROR_CODES: {
15
+ readonly ECONNECTION: "Connection closed unexpectedly";
16
+ readonly ETIMEDOUT: "Connection or operation timed out";
17
+ readonly ESOCKET: "Socket-level error";
18
+ readonly EDNS: "DNS resolution failed";
19
+ readonly ETLS: "TLS handshake or STARTTLS failed";
20
+ readonly EREQUIRETLS: "REQUIRETLS not supported by server (RFC 8689)";
21
+ readonly EPROTOCOL: "Invalid SMTP server response";
22
+ readonly EENVELOPE: "Invalid mail envelope (sender or recipients)";
23
+ readonly EMESSAGE: "Message delivery error";
24
+ readonly ESTREAM: "Stream processing error";
25
+ readonly EAUTH: "Authentication failed";
26
+ readonly ENOAUTH: "Authentication credentials not provided";
27
+ readonly EOAUTH2: "OAuth2 token generation or refresh error";
28
+ readonly EMAXLIMIT: "Pool resource limit reached (max messages per connection)";
29
+ readonly EMAXRECIPIENTS: "Recipient count exceeds maxRecipients";
30
+ readonly ESENDMAIL: "Sendmail command error";
31
+ readonly ESES: "AWS SES transport error";
32
+ readonly ECONFIG: "Invalid configuration";
33
+ readonly EPROXY: "Proxy connection error";
34
+ readonly EFILEACCESS: "File access rejected (disableFileAccess is set)";
35
+ readonly EURLACCESS: "URL access rejected (disableUrlAccess is set)";
36
+ readonly EFETCH: "HTTP fetch error";
37
+ };
38
+ /**
39
+ * Union of all known Nodemailer error codes
40
+ */
41
+ export type ErrorCode = keyof typeof ERROR_CODES;
42
+ export declare const ECONNECTION = "ECONNECTION";
43
+ export declare const ETIMEDOUT = "ETIMEDOUT";
44
+ export declare const ESOCKET = "ESOCKET";
45
+ export declare const EDNS = "EDNS";
46
+ export declare const ETLS = "ETLS";
47
+ export declare const EREQUIRETLS = "EREQUIRETLS";
48
+ export declare const EPROTOCOL = "EPROTOCOL";
49
+ export declare const EENVELOPE = "EENVELOPE";
50
+ export declare const EMESSAGE = "EMESSAGE";
51
+ export declare const ESTREAM = "ESTREAM";
52
+ export declare const EAUTH = "EAUTH";
53
+ export declare const ENOAUTH = "ENOAUTH";
54
+ export declare const EOAUTH2 = "EOAUTH2";
55
+ export declare const EMAXLIMIT = "EMAXLIMIT";
56
+ export declare const EMAXRECIPIENTS = "EMAXRECIPIENTS";
57
+ export declare const ESENDMAIL = "ESENDMAIL";
58
+ export declare const ESES = "ESES";
59
+ export declare const ECONFIG = "ECONFIG";
60
+ export declare const EPROXY = "EPROXY";
61
+ export declare const EFILEACCESS = "EFILEACCESS";
62
+ export declare const EURLACCESS = "EURLACCESS";
63
+ export declare const EFETCH = "EFETCH";
64
+ /**
65
+ * An Error together with the properties Nodemailer attaches to the errors it
66
+ * hands to callers. Every property is optional, the set that is present
67
+ * depends on where the error originated. Socket level errors keep the errno
68
+ * and syscall fields Node.js sets on them.
69
+ */
70
+ export interface NodemailerError extends NodeJS.ErrnoException {
71
+ /** Nodemailer error code, see ERROR_CODES */
72
+ code?: string | undefined;
73
+ /** SMTP command that was in flight when the server replied with an error */
74
+ command?: string | undefined;
75
+ /** Raw SMTP server response */
76
+ response?: string | undefined;
77
+ /** Numeric SMTP response code */
78
+ responseCode?: number | undefined;
79
+ /** URL of the resource that could not be fetched */
80
+ sourceUrl?: string | undefined;
81
+ /** Recipient address the error applies to */
82
+ recipient?: string | undefined;
83
+ /** Recipient addresses rejected by the server */
84
+ rejected?: string[] | undefined;
85
+ /** Per-recipient errors for the rejected addresses */
86
+ rejectedErrors?: NodemailerError[] | undefined;
87
+ }
88
+ /**
89
+ * Node style callback: called with an error, or with null and the result
90
+ */
91
+ export type Callback<T> = (err: NodemailerError | null, result: T) => void;
92
+ /**
93
+ * Callback as the library calls it on its error paths: with an error alone, or with null and
94
+ * the result. The public signatures use Callback, internally the error paths cast to this
95
+ */
96
+ export type ResultCallback<T> = (err: NodemailerError | null, result?: T) => void;