@bumail/smtp 0.9.0 → 0.11.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.
- package/README.md +6 -4
- package/dist/chunks/{index-wc25ywta.js → index-byaw0g4k.js} +88 -3
- package/dist/chunks/{index-wc25ywta.js.map → index-byaw0g4k.js.map} +5 -3
- package/dist/client/dsn.d.ts +21 -0
- package/dist/client/dsn.d.ts.map +1 -0
- package/dist/client/index.js +98 -5
- package/dist/client/index.js.map +6 -5
- package/dist/client/options.d.ts +21 -0
- package/dist/client/options.d.ts.map +1 -1
- package/dist/client/settings.d.ts +2 -0
- package/dist/client/settings.d.ts.map +1 -1
- package/dist/client/transaction.d.ts +2 -0
- package/dist/client/transaction.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +120 -15
- package/dist/index.js.map +10 -8
- package/dist/protocol/command.d.ts +2 -0
- package/dist/protocol/command.d.ts.map +1 -1
- package/dist/protocol/orcpt.d.ts +27 -0
- package/dist/protocol/orcpt.d.ts.map +1 -0
- package/dist/protocol/xtext.d.ts +14 -0
- package/dist/protocol/xtext.d.ts.map +1 -0
- package/dist/server/commands.d.ts.map +1 -1
- package/dist/server/dsn-params.d.ts +21 -0
- package/dist/server/dsn-params.d.ts.map +1 -0
- package/dist/server/envelope.d.ts +5 -0
- package/dist/server/envelope.d.ts.map +1 -0
- package/dist/server/intake.d.ts.map +1 -1
- package/dist/server/options.d.ts +28 -0
- package/dist/server/options.d.ts.map +1 -1
- package/dist/server/state.d.ts +4 -1
- package/dist/server/state.d.ts.map +1 -1
- package/dist/server/transaction.d.ts +2 -2
- package/dist/server/transaction.d.ts.map +1 -1
- package/docs/guide.md +122 -5
- package/docs/roadmap.md +15 -5
- package/docs/troubleshooting.md +61 -6
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
# @bumail/smtp
|
|
2
2
|
|
|
3
3
|
An SMTP server for Bun, on `Bun.listen`: RFC 5321 with PIPELINING, SIZE,
|
|
4
|
-
8BITMIME, SMTPUTF8
|
|
4
|
+
8BITMIME, SMTPUTF8, DSN (RFC 3461 parameters, see
|
|
5
|
+
[the guide](./docs/guide.md#delivery-status-notifications-dsn)) and
|
|
6
|
+
ENHANCEDSTATUSCODES; STARTTLS or implicit TLS; AUTH
|
|
5
7
|
PLAIN and LOGIN, only once encrypted; hooks where your app accepts or
|
|
6
8
|
refuses a connection, a sender, a recipient or a message. It is never an
|
|
7
9
|
open relay. And, on `@bumail/smtp/client`, a client that delivers one
|
|
@@ -486,7 +488,7 @@ host; a 5xx stops. A null MX (RFC 7505) fails at once with `NULL_MX`.
|
|
|
486
488
|
| `SmtpHooks` | `onConnect`, `onMailFrom`, `onRcptTo`, `onData` |
|
|
487
489
|
| `HookResult` | what a hook returns: `undefined` to accept, a `Reply` to refuse |
|
|
488
490
|
| `Session` | `id`, `remoteAddress`, `secure`, `helo`, `esmtp`, `user`, and `data` for your own state |
|
|
489
|
-
| `ReceivedMessage`, `Envelope` | what `onData` receives: `id`, `envelope` (`from`, `to`, `smtputf8`, `body`), `content`, a `ReadableStream<Uint8Array>`, and `signal`, an `AbortSignal` aborted when the server refuses the message on `onData`'s behalf — a refusal `onData` returns leaves it alone, unless a later stream failure replaces that reply or the connection closes before it is sent, which abort it instead |
|
|
491
|
+
| `ReceivedMessage`, `Envelope`, `EnvelopeRecipient`, `DsnNotify` | what `onData` receives: `id`, `envelope` (`from`, `to`, `smtputf8`, `body`, and the DSN parameters: `ret`, `envid`, and `recipients` with each one's `notify` and `orcpt`), `content`, a `ReadableStream<Uint8Array>`, and `signal`, an `AbortSignal` aborted when the server refuses the message on `onData`'s behalf — a refusal `onData` returns leaves it alone, unless a later stream failure replaces that reply or the connection closes before it is sent, which abort it instead |
|
|
490
492
|
| `TlsOptions` | `key` and `cert`, as `Bun.listen` takes them |
|
|
491
493
|
| `Credentials` | what `authenticate` receives: `mechanism`, `username`, `password`, `authorizationId?` |
|
|
492
494
|
| `reply(code, status, text)`, `Reply` | a reply, for a hook to refuse with |
|
|
@@ -503,9 +505,9 @@ host; a 5xx stops. A null MX (RFC 7505) fails at once with `NULL_MX`.
|
|
|
503
505
|
| export | |
|
|
504
506
|
| --- | --- |
|
|
505
507
|
| `sendMail(message, options)` | delivers one message; resolves to a `SendMailResult`, rejects with an `SmtpError` |
|
|
506
|
-
| `SendMailOptions` | `from`, `to`, and `{ host, port? }` or `{ domain, resolver, port? }`; `helo`, `tls`, `secure`, `ca`, `auth`, `allowPlaintextAuth`, `size`, `smtputf8`, `normalizeLineEnds`, `timeouts`, `deadline` |
|
|
508
|
+
| `SendMailOptions` | `from`, `to`, and `{ host, port? }` or `{ domain, resolver, port? }`; `helo`, `tls`, `secure`, `ca`, `auth`, `allowPlaintextAuth`, `size`, `smtputf8`, `ret`, `envid`, `recipients` (DSN, see [Sending DSN parameters](./docs/guide.md#sending-dsn-parameters)), `normalizeLineEnds`, `timeouts`, `deadline` |
|
|
507
509
|
| `HostDestination`, `MxDestination`, `SendMailEnvelope` | the parts of `SendMailOptions` |
|
|
508
|
-
| `SendMailResult` | `accepted`, `rejected`, `reply`, `host`, `port`, `tls` (`false` or `{ verified }`), `authenticated` |
|
|
510
|
+
| `SendMailResult` | `accepted`, `rejected`, `reply`, `host`, `port`, `tls` (`false` or `{ verified }`), `authenticated`, `dsnOffered` (the server listed DSN in EHLO, so the DSN options were sent) |
|
|
509
511
|
| `SendMailAuth` | `username`, `password`, `mechanism?` (`PLAIN` or `LOGIN`) |
|
|
510
512
|
| `SendMailTimeouts` | seconds: `connect`, `greeting`, `command`, `mail`, `rcpt`, `dataStart`, `dataBlock`, `dataEnd` |
|
|
511
513
|
| `TlsMode` | `'opportunistic'`, `'required'` or `'none'` |
|
|
@@ -208,6 +208,91 @@ function concat(a, b) {
|
|
|
208
208
|
return out;
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
+
// src/protocol/orcpt.ts
|
|
212
|
+
var ESCAPE = /^\\x\{([0-9A-Fa-f]{2,6})\}/;
|
|
213
|
+
var plain = (code) => code >= 33 && code <= 126 && code !== 92 && code !== 43 && code !== 61;
|
|
214
|
+
var expressible = (point) => point >= 32 || point >= 1 && point <= 9 || point >= 16 && point <= 25;
|
|
215
|
+
function utf8OrcptLength(address) {
|
|
216
|
+
let length = 0;
|
|
217
|
+
for (const char of address) {
|
|
218
|
+
const code = char.codePointAt(0);
|
|
219
|
+
length += code > 127 ? new TextEncoder().encode(char).length : plain(code) ? 1 : 6;
|
|
220
|
+
}
|
|
221
|
+
return length;
|
|
222
|
+
}
|
|
223
|
+
function encodeUtf8Orcpt(address, unicode) {
|
|
224
|
+
let out = "";
|
|
225
|
+
for (const char of address) {
|
|
226
|
+
const code = char.codePointAt(0);
|
|
227
|
+
if (code >= 55296 && code <= 57343)
|
|
228
|
+
return;
|
|
229
|
+
if (!expressible(code))
|
|
230
|
+
return;
|
|
231
|
+
out += plain(code) || unicode && code > 127 ? char : `\\x{${code.toString(16).toUpperCase().padStart(2, "0")}}`;
|
|
232
|
+
}
|
|
233
|
+
return out;
|
|
234
|
+
}
|
|
235
|
+
function decodeUtf8Orcpt(value, unicode) {
|
|
236
|
+
let out = "";
|
|
237
|
+
for (let i = 0;i < value.length; ) {
|
|
238
|
+
const code = value.codePointAt(i);
|
|
239
|
+
if (code === 92) {
|
|
240
|
+
const hex = ESCAPE.exec(value.slice(i, i + 10));
|
|
241
|
+
if (!hex)
|
|
242
|
+
return;
|
|
243
|
+
const point = Number.parseInt(hex[1], 16);
|
|
244
|
+
if (!expressible(point))
|
|
245
|
+
return;
|
|
246
|
+
if (point > 1114111 || point >= 55296 && point <= 57343)
|
|
247
|
+
return;
|
|
248
|
+
out += String.fromCodePoint(point);
|
|
249
|
+
i += hex[0].length;
|
|
250
|
+
} else if (plain(code) || unicode && code > 127) {
|
|
251
|
+
if (code >= 55296 && code <= 57343)
|
|
252
|
+
return;
|
|
253
|
+
out += String.fromCodePoint(code);
|
|
254
|
+
i += code > 65535 ? 2 : 1;
|
|
255
|
+
} else {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return out === "" ? undefined : out;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// src/protocol/xtext.ts
|
|
263
|
+
var HEX = "0123456789ABCDEF";
|
|
264
|
+
function encodeXtext(text) {
|
|
265
|
+
let out = "";
|
|
266
|
+
for (const byte of new TextEncoder().encode(text)) {
|
|
267
|
+
out += byte >= 33 && byte <= 126 && byte !== 43 && byte !== 61 ? String.fromCharCode(byte) : `+${HEX[byte >> 4]}${HEX[byte & 15]}`;
|
|
268
|
+
}
|
|
269
|
+
return out;
|
|
270
|
+
}
|
|
271
|
+
function decodeXtext(value) {
|
|
272
|
+
const bytes = [];
|
|
273
|
+
for (let i = 0;i < value.length; i++) {
|
|
274
|
+
const code = value.charCodeAt(i);
|
|
275
|
+
if (code === 43) {
|
|
276
|
+
const pair = value.slice(i + 1, i + 3);
|
|
277
|
+
if (!/^[0-9A-F]{2}$/.test(pair))
|
|
278
|
+
return;
|
|
279
|
+
const high = HEX.indexOf(pair[0]);
|
|
280
|
+
const low = HEX.indexOf(pair[1]);
|
|
281
|
+
bytes.push(high * 16 + low);
|
|
282
|
+
i += 2;
|
|
283
|
+
} else if (code >= 33 && code <= 126 && code !== 61) {
|
|
284
|
+
bytes.push(code);
|
|
285
|
+
} else {
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
try {
|
|
290
|
+
return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(new Uint8Array(bytes));
|
|
291
|
+
} catch {
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
211
296
|
// src/io/outgoing.ts
|
|
212
297
|
class Outgoing {
|
|
213
298
|
#write;
|
|
@@ -255,7 +340,7 @@ class Outgoing {
|
|
|
255
340
|
}
|
|
256
341
|
}
|
|
257
342
|
|
|
258
|
-
export { SmtpError2, POSTMASTER, isHelloName, parsePath2, decodePlain2, decodeLoginStep2, encodePlain, encodeLoginStep, MAX_LINE, LineSplitter, Outgoing };
|
|
343
|
+
export { SmtpError2, POSTMASTER, isHelloName, parsePath2, decodePlain2, decodeLoginStep2, encodePlain, encodeLoginStep, MAX_LINE, LineSplitter, utf8OrcptLength, encodeUtf8Orcpt, decodeUtf8Orcpt, encodeXtext, decodeXtext, Outgoing };
|
|
259
344
|
|
|
260
|
-
//# debugId=
|
|
261
|
-
//# sourceMappingURL=index-
|
|
345
|
+
//# debugId=3801043D559F921564756E2164756E21
|
|
346
|
+
//# sourceMappingURL=index-byaw0g4k.js.map
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/errors.ts", "../src/protocol/path.ts", "../src/protocol/sasl.ts", "../src/protocol/lines.ts", "../src/io/outgoing.ts"],
|
|
3
|
+
"sources": ["../src/errors.ts", "../src/protocol/path.ts", "../src/protocol/sasl.ts", "../src/protocol/lines.ts", "../src/protocol/orcpt.ts", "../src/protocol/xtext.ts", "../src/io/outgoing.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"import type { Reply } from './protocol/reply';\n\n/** Why the server refused an option, why a message stream ended in error, or why `sendMail` failed. */\nexport type SmtpErrorCode =\n\t| 'INVALID_OPTION'\n\t| 'ALREADY_LISTENING'\n\t| 'STOPPED'\n\t| 'MESSAGE_TOO_BIG'\n\t| 'BARE_LINE_BREAK'\n\t| 'NUL_BYTE'\n\t| 'CONNECTION_LOST'\n\t| 'HOOK_TIMEOUT'\n\t| 'INVALID_HOOK_REPLY'\n\t| 'MESSAGE_NOT_READ'\n\t| 'CONNECTION_FAILED'\n\t| 'TIMEOUT'\n\t| 'BAD_REPLY'\n\t| 'REFUSED'\n\t| 'RECIPIENTS_REFUSED'\n\t| 'TLS_UNAVAILABLE'\n\t| 'TLS_FAILED'\n\t| 'AUTH_UNAVAILABLE'\n\t| 'EXTENSION_MISSING'\n\t| 'NULL_MX'\n\t| 'DNS_FAILED';\n\n/** One recipient and the server's reply to its `RCPT TO`. */\nexport interface RecipientReply {\n\treadonly recipient: string;\n\treadonly reply: Reply;\n}\n\n/** What `sendMail` adds to an error: whether to try again, and the reply behind it. */\nexport interface SmtpErrorDetails {\n\t/** Trying again later may succeed: a 4xx, the network, a timeout. */\n\treadonly temporary?: boolean;\n\t/** The server's reply that failed the delivery, enhanced status code included. */\n\treadonly reply?: Reply;\n\t/**\n\t * With `RECIPIENTS_REFUSED`, or `afterData`: each recipient, and why it was\n\t * refused at `RCPT TO`.\n\t */\n\treadonly rejected?: readonly RecipientReply[];\n\t/** With `afterData`: each recipient the server accepted at `RCPT TO`. */\n\treadonly accepted?: readonly RecipientReply[];\n\t/** The error behind this one, as `Error`'s `cause`. */\n\treadonly cause?: unknown;\n\t/**\n\t * The final dot of the message was written and no reply to it came (a\n\t * timeout, a lost connection, a reply that is not one): the server may\n\t * have taken the message. See `SmtpError.afterData`.\n\t */\n\treadonly afterData?: boolean;\n}\n\n/** The codes that are temporary unless a reply or `details` says otherwise. */\nconst TEMPORARY = new Set<SmtpErrorCode>([\n\t'CONNECTION_LOST',\n\t'CONNECTION_FAILED',\n\t'TIMEOUT',\n\t'BAD_REPLY',\n\t'TLS_UNAVAILABLE',\n\t'TLS_FAILED',\n]);\n\n/**\n * Thrown by `createSmtpServer` and `listen` for a wrong option or call; the\n * error a message's `content` stream ends with when the message must not be\n * delivered; what `onError` is given for a hook that broke a rule; and what\n * `sendMail` rejects with. `temporary` tells a failure worth trying again\n * later (a 4xx, the network, a timeout) from a permanent one (a 5xx, a null\n * MX, a message the server can never take).\n */\nexport class SmtpError extends Error {\n\toverride readonly name = 'SmtpError';\n\treadonly code: SmtpErrorCode;\n\t/** Trying again later may succeed. Meaningful for `sendMail`'s errors. */\n\treadonly temporary: boolean;\n\t/** The server reply behind a `sendMail` failure, enhanced status code included. */\n\treadonly reply?: Reply;\n\t/**\n\t * With `RECIPIENTS_REFUSED`, or `afterData`: each recipient, and the reply\n\t * that refused it at `RCPT TO`.\n\t */\n\treadonly rejected?: readonly RecipientReply[];\n\t/**\n\t * With `afterData`: each recipient the server accepted at `RCPT TO`, and\n\t * the reply that accepted it — the ones that may hold the message. Absent\n\t * from an error of an older version; then every recipient is in doubt.\n\t */\n\treadonly accepted?: readonly RecipientReply[];\n\t/**\n\t * `true` when `sendMail` wrote the message's final dot and then got no\n\t * reply to it (a `TIMEOUT`, a `CONNECTION_LOST`, a `BAD_REPLY`): the\n\t * server may already have taken the message (RFC 5321 §4.1.5), so a\n\t * retry, or a delivery by another route, can duplicate it. Absent for a\n\t * failure before the dot (the server drops a message with no dot) and for\n\t * a reply that refused the message (a 4xx or 5xx says it was not taken).\n\t */\n\treadonly afterData?: boolean;\n\n\tconstructor(\n\t\tcode: SmtpErrorCode,\n\t\tmessage: string,\n\t\tdetails: SmtpErrorDetails = {},\n\t) {\n\t\tsuper(\n\t\t\tmessage,\n\t\t\tdetails.cause === undefined ? undefined : { cause: details.cause },\n\t\t);\n\t\tthis.code = code;\n\t\tthis.temporary =\n\t\t\tdetails.temporary ??\n\t\t\t(details.reply ? details.reply.code < 500 : TEMPORARY.has(code));\n\t\tif (details.reply) this.reply = details.reply;\n\t\tif (details.rejected) this.rejected = details.rejected;\n\t\tif (details.accepted) this.accepted = details.accepted;\n\t\tif (details.afterData) this.afterData = true;\n\t}\n}\n",
|
|
6
6
|
"/** An envelope address, as `MAIL FROM` and `RCPT TO` give it. */\nexport interface Path {\n\t/**\n\t * `local@domain`; `''` for the null reverse-path `<>`; `'postmaster'`\n\t * for `RCPT TO:<postmaster>`, which has no domain.\n\t */\n\treadonly address: string;\n\treadonly local: string;\n\t/** Lower case; `''` for `<>` and for `<postmaster>`. */\n\treadonly domain: string;\n\t/**\n\t * `true` for `RCPT TO:<postmaster>`, in any case, with no domain (RFC\n\t * 5321 §4.5.1): the postmaster of this server, whatever domains it\n\t * hosts. Absent for every other path, `<postmaster@domain>` included.\n\t */\n\treadonly postmaster?: true;\n}\n\n/** The bare `<postmaster>` path `RCPT TO` takes (RFC 5321 §4.1.1.3, §4.5.1). */\nexport const POSTMASTER: Path = Object.freeze({\n\taddress: 'postmaster',\n\tlocal: 'postmaster',\n\tdomain: '',\n\tpostmaster: true,\n});\n\nconst ATOM = /^[A-Za-z0-9!#$%&'*+\\-/=?^_`{|}~\\u0080-\\u{10ffff}]+$/u;\nconst LABEL =\n\t/^(?:[A-Za-z0-9\\u0080-\\u{10ffff}](?:[A-Za-z0-9\\-\\u0080-\\u{10ffff}]*[A-Za-z0-9\\u0080-\\u{10ffff}])?)$/u;\n\n/**\n * C1 controls, Unicode format characters (zero-width, bidi, BOM), the\n * line and paragraph separators, and lone surrogates: none has a place in\n * an address, and each would land as it is in the Received field and the\n * app's records — a lone surrogate as U+FFFD, once encoded for the wire.\n */\nconst INVISIBLE = /[\\u0080-\\u009f\\u2028\\u2029\\p{Cf}\\p{Cs}]/u;\n\n/**\n * C0 controls (CR, LF and NUL among them), DEL and `>`, anywhere in the\n * path, quoted or not: a CR or an LF would end the command line and start\n * another, and a `>` would end the path where a reader of the line stops.\n */\nfunction hasControl(text: string): boolean {\n\tfor (let i = 0; i < text.length; i++) {\n\t\tconst code = text.charCodeAt(i);\n\t\tif (code < 0x20 || code === 0x7f || code === 0x3e) return true;\n\t}\n\treturn false;\n}\n\n/** One hop of a source route, `@domain`, and what follows it: `,` or `:`. */\nconst HOP = /^@(\\[[^\\]]*\\]|[^,:@[\\]]*)([,:])/;\n\nfunction isDotString(text: string): boolean {\n\treturn text.split('.').every((atom) => ATOM.test(atom));\n}\n\nfunction isQuotedString(text: string): boolean {\n\treturn /^\"(?:[\\x20\\x21\\x23-\\x5b\\x5d-\\x7e\\u0080-\\u{10ffff}]|\\\\[\\x20-\\x7e])*\"$/u.test(\n\t\ttext,\n\t);\n}\n\n/**\n * An address literal (§4.1.3): `[IPv6:…]`, its tag in any case (a quoted\n * string in RFC 5234 is), or `[a.b.c.d]` with each octet at most 255.\n */\nexport function isAddressLiteral(text: string): boolean {\n\tif (/^\\[IPv6:[0-9a-f:.]+\\]$/i.test(text)) return true;\n\tconst ipv4 = /^\\[(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\]$/.exec(text);\n\treturn ipv4?.slice(1).every((octet) => Number(octet) <= 255) === true;\n}\n\n/**\n * The argument of EHLO or HELO (RFC 5321 §4.1.1.1): a host name of\n * letters, digits and hyphens, or an address literal.\n */\nexport function isHelloName(text: string): boolean {\n\treturn (\n\t\t/^[A-Za-z0-9-]+(?:\\.[A-Za-z0-9-]+)*$/.test(text) || isAddressLiteral(text)\n\t);\n}\n\nfunction isDomain(domain: string): boolean {\n\tif (isAddressLiteral(domain)) return true;\n\treturn (\n\t\tdomain.length <= 255 &&\n\t\tdomain.split('.').every((label) => label.length <= 63 && LABEL.test(label))\n\t);\n}\n\n/**\n * What `parsePath` does with a source route (`<@a,@b:local@domain>`, RFC 5321\n * Appendix C): a server accepts and discards it (`'discard'`), a client\n * refuses it, as §4.1.1.3 says clients should not send one (`'refuse'`).\n */\nexport type SourceRoute = 'discard' | 'refuse';\n\n/**\n * The mailbox after a source route, each of whose hops must be\n * `@domain` with a valid domain; `undefined` for any other route.\n */\nfunction afterRoute(inner: string): string | undefined {\n\tlet rest = inner;\n\tfor (;;) {\n\t\tconst hop = HOP.exec(rest);\n\t\tif (!hop || !isDomain(hop[1] as string)) return undefined;\n\t\trest = rest.slice(hop[0].length);\n\t\tif (hop[2] === ':') return rest;\n\t}\n}\n\n/**\n * Parses the `<path>` of RFC 5321 §4.1.2: `<local@domain>`, or `<>` when\n * `allowNull`. A source route (`<@a,@b:local@domain>`, §C) is dropped when\n * `sourceRoute` is `'discard'`, the default, provided each hop is\n * `@domain`; with `'refuse'` the path is not one. A C0 control (CR, LF,\n * NUL…), DEL or `>` anywhere refuses the path, as do C1 controls,\n * U+2028 and U+2029, Unicode format characters and lone surrogates. An IPv4 address literal\n * takes octets up to 255.\n * Non-ASCII is allowed: whether the session may use it is SMTPUTF8's\n * question (RFC 6531), not the grammar's. `undefined` when it is not a path.\n *\n * The local part is kept as written, quotes included: `\"v@x.example\"` and\n * `v%x.example` are local parts of the domain after the last `@`, not\n * addresses elsewhere. Code that delivers must not split on the first `@`.\n */\nexport function parsePath(\n\ttext: string,\n\tallowNull: boolean,\n\tsourceRoute: SourceRoute = 'discard',\n): Path | undefined {\n\tif (!text.startsWith('<') || !text.endsWith('>')) return undefined;\n\tlet inner: string | undefined = text.slice(1, -1);\n\tif (hasControl(inner) || INVISIBLE.test(inner)) return undefined;\n\tif (inner === '')\n\t\treturn allowNull ? { address: '', local: '', domain: '' } : undefined;\n\tif (inner.startsWith('@')) {\n\t\tif (sourceRoute === 'refuse') return undefined;\n\t\tinner = afterRoute(inner);\n\t\tif (inner === undefined) return undefined;\n\t}\n\tconst at = inner.lastIndexOf('@');\n\tif (at <= 0) return undefined;\n\tconst local = inner.slice(0, at);\n\tconst domain = inner.slice(at + 1);\n\tif (local.length > 64 || !(isDotString(local) || isQuotedString(local)))\n\t\treturn undefined;\n\tif (!isDomain(domain)) return undefined;\n\treturn {\n\t\taddress: `${local}@${domain.toLowerCase()}`,\n\t\tlocal,\n\t\tdomain: domain.toLowerCase(),\n\t};\n}\n",
|
|
7
7
|
"/** Credentials a client gave with `AUTH`. */\nexport interface Credentials {\n\treadonly mechanism: 'PLAIN' | 'LOGIN';\n\treadonly username: string;\n\treadonly password: string;\n\t/**\n\t * PLAIN's authorization identity, when it differs from the username.\n\t * The server refuses such credentials before `authenticate` is asked.\n\t */\n\treadonly authorizationId?: string;\n}\n\nfunction base64ToText(text: string): string | undefined {\n\tif (!/^[A-Za-z0-9+/]*={0,2}$/.test(text) || text.length % 4 !== 0)\n\t\treturn undefined;\n\ttry {\n\t\treturn new TextDecoder('utf-8', { fatal: true }).decode(\n\t\t\tUint8Array.fromBase64(text),\n\t\t);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/** PLAIN (RFC 4616): `authzid NUL authcid NUL passwd`, in base64. */\nexport function decodePlain(response: string): Credentials | undefined {\n\tconst text = base64ToText(response);\n\tif (text === undefined) return undefined;\n\tconst parts = text.split('\\0');\n\tif (parts.length !== 3) return undefined;\n\tconst [authorizationId = '', username = '', password = ''] = parts;\n\tif (username === '' || password === '') return undefined;\n\treturn {\n\t\tmechanism: 'PLAIN',\n\t\tusername,\n\t\tpassword,\n\t\t...(authorizationId === '' || authorizationId === username\n\t\t\t? {}\n\t\t\t: { authorizationId }),\n\t};\n}\n\n/** One step of LOGIN: a base64 line to its text. */\nexport function decodeLoginStep(response: string): string | undefined {\n\treturn base64ToText(response);\n}\n\nconst base64 = (text: string) => new TextEncoder().encode(text).toBase64();\n\n/** A client's PLAIN response (RFC 4616): `NUL username NUL password`, in base64, no authorization identity. */\nexport function encodePlain(username: string, password: string): string {\n\treturn base64(`\\0${username}\\0${password}`);\n}\n\n/** One step of LOGIN, the username or the password, in base64. */\nexport function encodeLoginStep(text: string): string {\n\treturn base64(text);\n}\n",
|
|
8
8
|
"/**\n * The longest line taken, CRLF included: a command (RFC 5321 §4.5.3.1.4\n * asks for 512 at least) or a reply line (§4.5.3.1.5, 512 too).\n */\nexport const MAX_LINE = 2048;\n\n/** One line from the peer, or a line that was too long and was skipped. */\nexport type LineEvent = { line: string } | { tooLong: true };\n\n/**\n * Cuts a peer's bytes into lines — a client's commands, a server's\n * replies — ending at LF with or without CR. It holds one partial line at most: past `MAX_LINE`, the line is\n * skipped to its end and reported once.\n */\nexport class LineSplitter {\n\t#held: Uint8Array = new Uint8Array(0);\n\t#skipping = false;\n\t#rest: Uint8Array = new Uint8Array(0);\n\n\t/** Starts on a chunk; read its lines with `next`. */\n\tpush(chunk: Uint8Array): void {\n\t\tthis.#rest = this.#held.length > 0 ? concat(this.#held, chunk) : chunk;\n\t\tthis.#held = new Uint8Array(0);\n\t}\n\n\t/** The next line of the current chunk, or `undefined` when it has no more. */\n\tnext(): LineEvent | undefined {\n\t\tfor (;;) {\n\t\t\tconst data = this.#rest;\n\t\t\tconst lf = data.indexOf(0x0a);\n\t\t\tif (lf < 0) {\n\t\t\t\tthis.#rest = new Uint8Array(0);\n\t\t\t\tif (this.#skipping) return undefined;\n\t\t\t\tif (data.length > MAX_LINE) {\n\t\t\t\t\tthis.#skipping = true;\n\t\t\t\t\treturn { tooLong: true };\n\t\t\t\t}\n\t\t\t\tthis.#held = data.slice();\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tconst end = lf > 0 && data[lf - 1] === 0x0d ? lf - 1 : lf;\n\t\t\tthis.#rest = data.subarray(lf + 1);\n\t\t\tif (this.#skipping) {\n\t\t\t\tthis.#skipping = false;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (end > MAX_LINE) return { tooLong: true };\n\t\t\treturn { line: new TextDecoder().decode(data.subarray(0, end)) };\n\t\t}\n\t}\n\n\t/** Bytes are held or left: a line begun, or lines not yet read. */\n\tget holding(): boolean {\n\t\treturn this.#held.length > 0 || this.#rest.length > 0;\n\t}\n\n\t/** What is left of the current chunk: message content pipelined after DATA. */\n\ttakeRest(): Uint8Array {\n\t\tconst rest = this.#rest;\n\t\tthis.#rest = new Uint8Array(0);\n\t\treturn rest;\n\t}\n\n\t/** Forgets everything held: after STARTTLS, or after a refused DATA. */\n\tclear(): void {\n\t\tthis.#held = new Uint8Array(0);\n\t\tthis.#rest = new Uint8Array(0);\n\t\tthis.#skipping = false;\n\t}\n}\n\nfunction concat(a: Uint8Array, b: Uint8Array): Uint8Array {\n\tconst out = new Uint8Array(a.length + b.length);\n\tout.set(a, 0);\n\tout.set(b, a.length);\n\treturn out;\n}\n",
|
|
9
|
+
"// The `utf-8` address type of ORCPT (RFC 6533 §3): `utf-8-addr-xtext` and\n// `utf-8-addr-unitext`. `rfc822` is plain xtext (./xtext.ts).\n\n/**\n * An escape: `\\x{` and 2 to 6 hexadecimal digits (`EmbeddedUnicodeChar`, RFC\n * 6533 §3). Accepted leniently: leading zeros and escaped printable ASCII,\n * which RFC 6533's HEXPOINT does not produce.\n */\nconst ESCAPE = /^\\\\x\\{([0-9A-Fa-f]{2,6})\\}/;\n\n/**\n * Whether `code` may be written as itself (`QCHAR`): printable ASCII except\n * `\\`, `+` and `=`.\n */\nconst plain = (code: number): boolean =>\n\tcode >= 0x21 &&\n\tcode <= 0x7e &&\n\tcode !== 0x5c &&\n\tcode !== 0x2b &&\n\tcode !== 0x3d;\n\n/**\n * Whether the HEXPOINT grammar of RFC 6533 §3 can express `point` (2 to 6\n * digits): not NUL, `0A` to `0F`, nor `1A` to `1F`.\n */\nconst expressible = (point: number): boolean =>\n\tpoint >= 0x20 ||\n\t(point >= 0x01 && point <= 0x09) ||\n\t(point >= 0x10 && point <= 0x19);\n\n/**\n * The length of an address in its `utf-8-addr-unitext` form, the shortest\n * (raw UTF-8 octets for a non-ASCII character, `\\x{HH}` is 6): what a `utf-8`\n * ORCPT counts against the 500 characters of RFC 3461 §4.2 in the copies that\n * do not read the wire (AGENTS.md, Deliberate duplications).\n */\nexport function utf8OrcptLength(address: string): number {\n\tlet length = 0;\n\tfor (const char of address) {\n\t\tconst code = char.codePointAt(0) as number;\n\t\tlength +=\n\t\t\tcode > 0x7f ? new TextEncoder().encode(char).length : plain(code) ? 1 : 6;\n\t}\n\treturn length;\n}\n\n/**\n * Encodes an address as `utf-8-addr-xtext` (`unicode` false, 7-bit safe) or\n * `utf-8-addr-unitext` (`unicode` true, for a session with SMTPUTF8: the\n * non-ASCII characters stay raw UTF-8); every other character is\n * `\\x{HH}` (at least 2 digits). `undefined` when the text holds a lone\n * surrogate or a character the grammar cannot express (NUL, `0A` to `0F`, `1A`\n * to `1F`).\n */\nexport function encodeUtf8Orcpt(\n\taddress: string,\n\tunicode: boolean,\n): string | undefined {\n\tlet out = '';\n\tfor (const char of address) {\n\t\tconst code = char.codePointAt(0) as number;\n\t\tif (code >= 0xd800 && code <= 0xdfff) return undefined;\n\t\tif (!expressible(code)) return undefined;\n\t\tout +=\n\t\t\tplain(code) || (unicode && code > 0x7f)\n\t\t\t\t? char\n\t\t\t\t: `\\\\x{${code.toString(16).toUpperCase().padStart(2, '0')}}`;\n\t}\n\treturn out;\n}\n\n/**\n * Decodes the address of an `ORCPT=utf-8;` value (RFC 6533 §3): the\n * `utf-8-addr-xtext` form, plus, when `unicode` (the transaction uses\n * SMTPUTF8), raw UTF-8 as `utf-8-addr-unitext` allows. `undefined` when it is\n * neither: a character that must be escaped, a malformed or out-of-range\n * `\\x{…}`, an escaped NUL or control the grammar has no HEXPOINT for (`0A` to\n * `0F`, `1A` to `1F`: line breaks stay out of a DSN header), a raw non-ASCII character\n * without SMTPUTF8, or nothing.\n */\nexport function decodeUtf8Orcpt(\n\tvalue: string,\n\tunicode: boolean,\n): string | undefined {\n\tlet out = '';\n\tfor (let i = 0; i < value.length; ) {\n\t\tconst code = value.codePointAt(i) as number;\n\t\tif (code === 0x5c) {\n\t\t\tconst hex = ESCAPE.exec(value.slice(i, i + 10));\n\t\t\tif (!hex) return undefined;\n\t\t\tconst point = Number.parseInt(hex[1] as string, 16);\n\t\t\tif (!expressible(point)) return undefined;\n\t\t\tif (point > 0x10ffff || (point >= 0xd800 && point <= 0xdfff))\n\t\t\t\treturn undefined;\n\t\t\tout += String.fromCodePoint(point);\n\t\t\ti += (hex[0] as string).length;\n\t\t} else if (plain(code) || (unicode && code > 0x7f)) {\n\t\t\tif (code >= 0xd800 && code <= 0xdfff) return undefined;\n\t\t\tout += String.fromCodePoint(code);\n\t\t\ti += code > 0xffff ? 2 : 1;\n\t\t} else {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\treturn out === '' ? undefined : out;\n}\n",
|
|
10
|
+
"const HEX = '0123456789ABCDEF';\n\n/**\n * Encodes text as `xtext` (RFC 3461 §4), the form DSN parameter values take\n * on the wire: every byte of its UTF-8 form outside `!` to `~` (33 to 126),\n * and `+` and `=`, becomes `+` and two upper-case hex digits.\n */\nexport function encodeXtext(text: string): string {\n\tlet out = '';\n\tfor (const byte of new TextEncoder().encode(text)) {\n\t\tout +=\n\t\t\tbyte >= 33 && byte <= 126 && byte !== 0x2b && byte !== 0x3d\n\t\t\t\t? String.fromCharCode(byte)\n\t\t\t\t: `+${HEX[byte >> 4]}${HEX[byte & 15]}`;\n\t}\n\treturn out;\n}\n\n/**\n * Decodes `xtext` (RFC 3461 §4) read as UTF-8, or `undefined` when it is\n * not xtext: a `+` not followed by two upper-case hex digits, a character\n * outside `!` to `~` that is not encoded, a bare `=`, or bytes that are not\n * valid UTF-8.\n */\nexport function decodeXtext(value: string): string | undefined {\n\tconst bytes: number[] = [];\n\tfor (let i = 0; i < value.length; i++) {\n\t\tconst code = value.charCodeAt(i);\n\t\tif (code === 0x2b) {\n\t\t\tconst pair = value.slice(i + 1, i + 3);\n\t\t\tif (!/^[0-9A-F]{2}$/.test(pair)) return undefined;\n\t\t\tconst high = HEX.indexOf(pair[0] as string);\n\t\t\tconst low = HEX.indexOf(pair[1] as string);\n\t\t\tbytes.push(high * 16 + low);\n\t\t\ti += 2;\n\t\t} else if (code >= 33 && code <= 126 && code !== 0x3d) {\n\t\t\tbytes.push(code);\n\t\t} else {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\ttry {\n\t\treturn new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }).decode(\n\t\t\tnew Uint8Array(bytes),\n\t\t);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n",
|
|
9
11
|
"/**\n * What waits to leave a Bun socket. Bun's sockets do not buffer: `write`\n * takes what the kernel takes and says how much. The rest waits here for\n * the socket's `drain` event, so nothing written is lost to a peer that\n * reads slowly. The server's transport and the client's socket share it.\n */\nexport class Outgoing {\n\treadonly #write: (bytes: Uint8Array) => number;\n\t#queue: Uint8Array[] = [];\n\t#waiters: (() => void)[] = [];\n\n\tconstructor(write: (bytes: Uint8Array) => number) {\n\t\tthis.#write = write;\n\t}\n\n\t/** Nothing waits to leave. */\n\tget empty(): boolean {\n\t\treturn this.#queue.length === 0;\n\t}\n\n\t/** Writes what the socket takes now, and keeps the rest for `drain`. */\n\twrite(bytes: Uint8Array): void {\n\t\tif (this.#queue.length > 0) {\n\t\t\tthis.#queue.push(bytes);\n\t\t\treturn;\n\t\t}\n\t\tconst written = this.#write(bytes);\n\t\tif (written < bytes.length) {\n\t\t\tthis.#queue.push(bytes.subarray(Math.max(written, 0)));\n\t\t}\n\t}\n\n\t/** The socket's `drain`: it can take more. True once everything has left. */\n\tdrain(): boolean {\n\t\twhile (this.#queue.length > 0) {\n\t\t\tconst bytes = this.#queue[0] as Uint8Array;\n\t\t\tconst written = this.#write(bytes);\n\t\t\tif (written < bytes.length) {\n\t\t\t\tthis.#queue[0] = bytes.subarray(Math.max(written, 0));\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tthis.#queue.shift();\n\t\t}\n\t\tfor (const wake of this.#waiters.splice(0)) wake();\n\t\treturn true;\n\t}\n\n\t/** Resolves once everything written has left, or the socket closed. */\n\tdrained(): Promise<void> {\n\t\tif (this.#queue.length === 0) return Promise.resolve();\n\t\treturn new Promise((wake) => this.#waiters.push(wake));\n\t}\n\n\t/** The socket closed: nothing more will leave. */\n\tclear(): void {\n\t\tthis.#queue = [];\n\t\tfor (const wake of this.#waiters.splice(0)) wake();\n\t}\n}\n"
|
|
10
12
|
],
|
|
11
|
-
"mappings": "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
|
|
12
|
-
"debugId": "
|
|
13
|
+
"mappings": "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",
|
|
14
|
+
"debugId": "3801043D559F921564756E2164756E21",
|
|
13
15
|
"names": []
|
|
14
16
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { EnvelopeRecipient } from '../server/options';
|
|
2
|
+
/** The DSN parameters of the message and of its recipients (RFC 3461 §4), checked. */
|
|
3
|
+
export interface DsnSettings {
|
|
4
|
+
readonly ret?: 'FULL' | 'HDRS';
|
|
5
|
+
readonly envid?: string;
|
|
6
|
+
/** The recipients that carry `NOTIFY` or `ORCPT`, by address. */
|
|
7
|
+
readonly recipients: ReadonlyMap<string, EnvelopeRecipient>;
|
|
8
|
+
}
|
|
9
|
+
/** Checks `ret`, `envid` and `recipients`; `fail` throws the `INVALID_OPTION` for a message. */
|
|
10
|
+
export declare function dsnOf(given: {
|
|
11
|
+
ret?: unknown;
|
|
12
|
+
envid?: unknown;
|
|
13
|
+
recipients?: unknown;
|
|
14
|
+
}, to: readonly string[], fail: (message: string) => Error): DsnSettings;
|
|
15
|
+
/** Whether the options carry any DSN parameter. */
|
|
16
|
+
export declare const asksDsn: (dsn: DsnSettings) => boolean;
|
|
17
|
+
/** ` RET=… ENVID=…` for MAIL FROM, when the server lists DSN (RFC 3461 §4.3, §4.4). */
|
|
18
|
+
export declare function mailDsn(dsn: DsnSettings, offered: boolean): string;
|
|
19
|
+
/** ` NOTIFY=… ORCPT=…` for one RCPT TO, when the server lists DSN (RFC 3461 §4.1, §4.2). */
|
|
20
|
+
export declare function rcptDsn(dsn: DsnSettings, address: string, offered: boolean, smtputf8?: boolean): string;
|
|
21
|
+
//# sourceMappingURL=dsn.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dsn.d.ts","sourceRoot":"","sources":["../../src/client/dsn.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAa,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEtE,sFAAsF;AACtF,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,iEAAiE;IACjE,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;CAC5D;AAID,gGAAgG;AAChG,wBAAgB,KAAK,CACpB,KAAK,EAAE;IACN,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;CACrB,EACD,EAAE,EAAE,SAAS,MAAM,EAAE,EACrB,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,KAAK,GAC9B,WAAW,CAmCb;AAyCD,mDAAmD;AACnD,eAAO,MAAM,OAAO,GAAI,KAAK,WAAW,KAAG,OACiC,CAAC;AAE7E,uFAAuF;AACvF,wBAAgB,OAAO,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,CAMlE;AA+BD,4FAA4F;AAC5F,wBAAgB,OAAO,CACtB,GAAG,EAAE,WAAW,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,EAChB,QAAQ,UAAQ,GACd,MAAM,CASR"}
|
package/dist/client/index.js
CHANGED
|
@@ -6,8 +6,11 @@ import {
|
|
|
6
6
|
encodeLoginStep,
|
|
7
7
|
MAX_LINE,
|
|
8
8
|
LineSplitter,
|
|
9
|
+
utf8OrcptLength,
|
|
10
|
+
encodeUtf8Orcpt,
|
|
11
|
+
encodeXtext,
|
|
9
12
|
Outgoing
|
|
10
|
-
} from "../chunks/index-
|
|
13
|
+
} from "../chunks/index-byaw0g4k.js";
|
|
11
14
|
// src/client/address.ts
|
|
12
15
|
function isMailbox(address) {
|
|
13
16
|
return typeof address === "string" && parsePath2(`<${address}>`, false, "refuse") !== undefined;
|
|
@@ -407,6 +410,89 @@ async function open(socket, settings, tls) {
|
|
|
407
410
|
|
|
408
411
|
// src/client/settings.ts
|
|
409
412
|
import { hostname as machineName } from "node:os";
|
|
413
|
+
|
|
414
|
+
// src/client/dsn.ts
|
|
415
|
+
var EVENTS = ["SUCCESS", "FAILURE", "DELAY"];
|
|
416
|
+
function dsnOf(given, to, fail) {
|
|
417
|
+
const { ret, envid, recipients } = given;
|
|
418
|
+
if (ret !== undefined && ret !== "FULL" && ret !== "HDRS")
|
|
419
|
+
throw fail(`ret must be 'FULL' or 'HDRS', not ${String(ret)}`);
|
|
420
|
+
if (envid !== undefined && (typeof envid !== "string" || !/^[ -~]{1,100}$/.test(envid) || encodeXtext(envid).length > 100))
|
|
421
|
+
throw fail("envid must be 1 to 100 printable ASCII characters, at most 100 once encoded as xtext");
|
|
422
|
+
const byAddress = new Map;
|
|
423
|
+
if (recipients !== undefined) {
|
|
424
|
+
if (!Array.isArray(recipients))
|
|
425
|
+
throw fail("recipients must be an array of { address, notify, orcpt }");
|
|
426
|
+
for (const entry of recipients) {
|
|
427
|
+
const address = entry?.address;
|
|
428
|
+
if (typeof address !== "string" || !to.includes(address))
|
|
429
|
+
throw fail(`recipients names ${JSON.stringify(address)}, which is not in to`);
|
|
430
|
+
if (byAddress.has(address))
|
|
431
|
+
throw fail(`recipients names ${address} twice`);
|
|
432
|
+
checkRecipient(entry, fail);
|
|
433
|
+
byAddress.set(address, entry);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
return {
|
|
437
|
+
...ret ? { ret } : {},
|
|
438
|
+
...envid === undefined ? {} : { envid },
|
|
439
|
+
recipients: byAddress
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
function checkRecipient({ address, notify, orcpt }, fail) {
|
|
443
|
+
if (notify !== undefined && notify !== "NEVER") {
|
|
444
|
+
const events = Array.isArray(notify) ? notify : [];
|
|
445
|
+
if (events.length === 0 || events.some((e, i) => !EVENTS.includes(e) || events.indexOf(e) !== i))
|
|
446
|
+
throw fail(`notify of ${address} must be 'NEVER' or a list of 'SUCCESS', 'FAILURE', 'DELAY', each once`);
|
|
447
|
+
}
|
|
448
|
+
if (orcpt !== undefined) {
|
|
449
|
+
if (typeof orcpt !== "object" || orcpt === null || typeof orcpt.type !== "string" || !/^[A-Za-z0-9-]+$/.test(orcpt.type))
|
|
450
|
+
throw fail(`orcpt of ${address} must be { type, address }, the type a token`);
|
|
451
|
+
if (typeof orcpt.address !== "string" || orcpt.address === "")
|
|
452
|
+
throw fail(`orcpt.address of ${address} must be a non-empty string`);
|
|
453
|
+
const encoded = orcpt.type.toLowerCase() === "utf-8" ? utf8OrcptLength(orcpt.address) : encodeXtext(orcpt.address).length;
|
|
454
|
+
if (orcpt.type.length + 1 + encoded > 500)
|
|
455
|
+
throw fail(`orcpt of ${address} is over 500 characters once encoded`);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
function mailDsn(dsn, offered) {
|
|
459
|
+
if (!offered)
|
|
460
|
+
return "";
|
|
461
|
+
let out = "";
|
|
462
|
+
if (dsn.ret)
|
|
463
|
+
out += ` RET=${dsn.ret}`;
|
|
464
|
+
if (dsn.envid !== undefined)
|
|
465
|
+
out += ` ENVID=${encodeXtext(dsn.envid)}`;
|
|
466
|
+
return out;
|
|
467
|
+
}
|
|
468
|
+
function orcptParameter({ type, address }, smtputf8) {
|
|
469
|
+
const kind = type.toLowerCase();
|
|
470
|
+
if (kind === "rfc822")
|
|
471
|
+
return /^[\x20-\x7e]+$/.test(address) ? ` ORCPT=${type};${encodeXtext(address)}` : "";
|
|
472
|
+
if (kind !== "utf-8") {
|
|
473
|
+
const value = `${type};${encodeXtext(address)}`;
|
|
474
|
+
return address.isWellFormed() ? ` ORCPT=${value}` : "";
|
|
475
|
+
}
|
|
476
|
+
const encoded = encodeUtf8Orcpt(address, smtputf8);
|
|
477
|
+
if (encoded === undefined)
|
|
478
|
+
return "";
|
|
479
|
+
const value = `${type};${encoded}`;
|
|
480
|
+
return new TextEncoder().encode(value).length > 500 ? "" : ` ORCPT=${value}`;
|
|
481
|
+
}
|
|
482
|
+
function rcptDsn(dsn, address, offered, smtputf8 = false) {
|
|
483
|
+
const entry = dsn.recipients.get(address);
|
|
484
|
+
if (!offered || !entry)
|
|
485
|
+
return "";
|
|
486
|
+
let out = "";
|
|
487
|
+
const { notify, orcpt } = entry;
|
|
488
|
+
if (notify !== undefined)
|
|
489
|
+
out += ` NOTIFY=${notify === "NEVER" ? "NEVER" : notify.join(",")}`;
|
|
490
|
+
if (orcpt)
|
|
491
|
+
out += orcptParameter(orcpt, smtputf8);
|
|
492
|
+
return out;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// src/client/settings.ts
|
|
410
496
|
var MAX_SECONDS = Math.floor(2147483647 / 1000);
|
|
411
497
|
var TIMEOUTS = {
|
|
412
498
|
connect: 30,
|
|
@@ -506,6 +592,7 @@ function settingsOf(options) {
|
|
|
506
592
|
...auth ? { auth } : {},
|
|
507
593
|
allowPlaintextAuth,
|
|
508
594
|
...size === undefined ? {} : { size },
|
|
595
|
+
dsn: dsnOf(options, to, invalid),
|
|
509
596
|
smtputf8: options.smtputf8 === true || [from, ...to].some((text) => /[^ -~]/.test(text)),
|
|
510
597
|
normalizeLineEnds: options.normalizeLineEnds === true,
|
|
511
598
|
timeouts: timeoutsOf(options.timeouts),
|
|
@@ -795,9 +882,10 @@ function mailParameters(host, settings, content, extensions) {
|
|
|
795
882
|
async function envelope(socket, settings, content, ready) {
|
|
796
883
|
const { host } = socket;
|
|
797
884
|
const { timeouts } = settings;
|
|
798
|
-
const
|
|
885
|
+
const dsn = ready.extensions.has("DSN");
|
|
886
|
+
const mail = `MAIL FROM:<${settings.from}>${mailParameters(host, settings, content, ready.extensions)}${mailDsn(settings.dsn, dsn)}\r
|
|
799
887
|
`;
|
|
800
|
-
const rcpts = settings.to.map((to) => `RCPT TO:<${to}
|
|
888
|
+
const rcpts = settings.to.map((to) => `RCPT TO:<${to}>${rcptDsn(settings.dsn, to, dsn, settings.smtputf8)}\r
|
|
801
889
|
`);
|
|
802
890
|
const pipelining = ready.extensions.has("PIPELINING");
|
|
803
891
|
socket.write(pipelining ? mail + rcpts.join("") : mail);
|
|
@@ -871,7 +959,12 @@ async function transact(socket, settings, content, ready) {
|
|
|
871
959
|
accepted,
|
|
872
960
|
rejected
|
|
873
961
|
});
|
|
874
|
-
return {
|
|
962
|
+
return {
|
|
963
|
+
accepted,
|
|
964
|
+
rejected,
|
|
965
|
+
reply,
|
|
966
|
+
dsnOffered: ready.extensions.has("DSN")
|
|
967
|
+
};
|
|
875
968
|
}
|
|
876
969
|
|
|
877
970
|
// src/client/send.ts
|
|
@@ -973,5 +1066,5 @@ export {
|
|
|
973
1066
|
sendMail
|
|
974
1067
|
};
|
|
975
1068
|
|
|
976
|
-
//# debugId=
|
|
1069
|
+
//# debugId=3C3AEF3D2B40447E64756E2164756E21
|
|
977
1070
|
//# sourceMappingURL=index.js.map
|