@bumail/smtp 0.9.0 → 0.10.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-twt5myrr.js} +37 -3
- package/dist/chunks/{index-wc25ywta.js.map → index-twt5myrr.js.map} +4 -3
- package/dist/client/dsn.d.ts +21 -0
- package/dist/client/dsn.d.ts.map +1 -0
- package/dist/client/index.js +81 -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 +116 -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/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 +20 -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 +100 -5
- package/docs/roadmap.md +11 -5
- package/docs/troubleshooting.md +54 -6
- package/package.json +3 -3
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { DsnNotify, EnvelopeRecipient } from './options';
|
|
2
|
+
import type { Transaction } from './state';
|
|
3
|
+
/** The DSN parameters (RFC 3461 §4) MAIL FROM takes. */
|
|
4
|
+
export declare const MAIL_DSN: Set<string>;
|
|
5
|
+
/** The DSN parameters (RFC 3461 §4) RCPT TO takes. */
|
|
6
|
+
export declare const RCPT_DSN: Set<string>;
|
|
7
|
+
/**
|
|
8
|
+
* Reads one DSN parameter of MAIL FROM into the transaction under way.
|
|
9
|
+
* The text of the `501` to answer when the value is wrong, else `undefined`.
|
|
10
|
+
*/
|
|
11
|
+
export declare function readMailDsn(into: Pick<Transaction, 'ret' | 'envid'>, key: string, value: string, repeated: readonly string[]): string | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Reads one DSN parameter of RCPT TO into `into`. The text of the `501` to
|
|
14
|
+
* answer when the value is wrong, else `undefined`.
|
|
15
|
+
*/
|
|
16
|
+
export declare function readRcptDsn(into: {
|
|
17
|
+
notify?: 'NEVER' | readonly DsnNotify[];
|
|
18
|
+
orcpt?: EnvelopeRecipient['orcpt'];
|
|
19
|
+
}, key: string, value: string, repeated: readonly string[]): string | undefined;
|
|
20
|
+
//# sourceMappingURL=dsn-params.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dsn-params.d.ts","sourceRoot":"","sources":["../../src/server/dsn-params.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C,wDAAwD;AACxD,eAAO,MAAM,QAAQ,aAA4B,CAAC;AAClD,sDAAsD;AACtD,eAAO,MAAM,QAAQ,aAA+B,CAAC;AA0CrD;;;GAGG;AACH,wBAAgB,WAAW,CAC1B,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,KAAK,GAAG,OAAO,CAAC,EACxC,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,SAAS,MAAM,EAAE,GACzB,MAAM,GAAG,SAAS,CAYpB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAC1B,IAAI,EAAE;IACL,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,SAAS,EAAE,CAAC;IACxC,KAAK,CAAC,EAAE,iBAAiB,CAAC,OAAO,CAAC,CAAC;CACnC,EACD,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,SAAS,MAAM,EAAE,GACzB,MAAM,GAAG,SAAS,CAYpB"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ReceivedMessage } from './options';
|
|
2
|
+
import type { Transaction } from './state';
|
|
3
|
+
/** The envelope of a message as `onData` is told it, from the transaction that ended in DATA. */
|
|
4
|
+
export declare function envelopeOf(transaction: Transaction): ReceivedMessage['envelope'];
|
|
5
|
+
//# sourceMappingURL=envelope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../src/server/envelope.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C,iGAAiG;AACjG,wBAAgB,UAAU,CACzB,WAAW,EAAE,WAAW,GACtB,eAAe,CAAC,UAAU,CAAC,CAU7B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intake.d.ts","sourceRoot":"","sources":["../../src/server/intake.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,KAAK,EAAS,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"intake.d.ts","sourceRoot":"","sources":["../../src/server/intake.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,KAAK,EAAS,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAiB/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAK3C;;;;;;;;;;;;GAYG;AACH,qBAAa,MAAM;;IAClB,QAAQ,CAAC,EAAE,SAAsD;gBAoBrD,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW;IAqE5D,iEAAiE;IAC3D,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,UAAU,CAAA;KAAE,CAAC;IAmB5E,0CAA0C;IACpC,MAAM,IAAI,OAAO,CAAC,KAAK,CAAC;IAuB9B,uEAAuE;IACvE,KAAK,IAAI,IAAI;CA2Eb"}
|
package/dist/server/options.d.ts
CHANGED
|
@@ -20,6 +20,28 @@ export interface Session {
|
|
|
20
20
|
*/
|
|
21
21
|
readonly data: Record<string, unknown>;
|
|
22
22
|
}
|
|
23
|
+
/** What a recipient asked to be told (RFC 3461 §4.1): `NEVER`, or the events among these. */
|
|
24
|
+
export type DsnNotify = 'SUCCESS' | 'FAILURE' | 'DELAY';
|
|
25
|
+
/**
|
|
26
|
+
* One recipient of a message, with the DSN parameters of its `RCPT TO`
|
|
27
|
+
* (RFC 3461 §4.1, §4.2). The server only passes them on: the app honours
|
|
28
|
+
* them when it relays the message or generates a DSN.
|
|
29
|
+
*/
|
|
30
|
+
export interface EnvelopeRecipient {
|
|
31
|
+
/** The same address as the matching entry of `Envelope.to`. */
|
|
32
|
+
readonly address: string;
|
|
33
|
+
/**
|
|
34
|
+
* `NOTIFY=`: `'NEVER'`, or the events, in the order given, with no
|
|
35
|
+
* duplicate. Absent when the client sent none: the default is a DSN on
|
|
36
|
+
* failure, delay and success never (RFC 3461 §4.1).
|
|
37
|
+
*/
|
|
38
|
+
readonly notify?: 'NEVER' | readonly DsnNotify[];
|
|
39
|
+
/** `ORCPT=`: the original recipient, its `type` as sent (`rfc822`) and its `address` decoded from xtext. */
|
|
40
|
+
readonly orcpt?: {
|
|
41
|
+
readonly type: string;
|
|
42
|
+
readonly address: string;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
23
45
|
/** The sender and recipients of one message. */
|
|
24
46
|
export interface Envelope {
|
|
25
47
|
/** `''` for the null reverse-path `<>`: a bounce. */
|
|
@@ -30,6 +52,12 @@ export interface Envelope {
|
|
|
30
52
|
readonly smtputf8: boolean;
|
|
31
53
|
/** `7BIT` or `8BITMIME`, as MAIL FROM's BODY= said; `7BIT` when it said nothing. */
|
|
32
54
|
readonly body: '7BIT' | '8BITMIME';
|
|
55
|
+
/** `RET=` of MAIL FROM (RFC 3461 §4.3), upper case: whether a DSN returns the whole message or its headers. Absent when not sent. */
|
|
56
|
+
readonly ret?: 'FULL' | 'HDRS';
|
|
57
|
+
/** `ENVID=` of MAIL FROM (RFC 3461 §4.4), decoded from xtext: at most 100 printable ASCII characters. Absent when not sent. */
|
|
58
|
+
readonly envid?: string;
|
|
59
|
+
/** The recipients accepted, in the order of `to`, each with its `NOTIFY` and `ORCPT`. */
|
|
60
|
+
readonly recipients: readonly EnvelopeRecipient[];
|
|
33
61
|
}
|
|
34
62
|
/** A message on its way in, handed to `onData` as the client sends it. */
|
|
35
63
|
export interface ReceivedMessage {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../src/server/options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,sGAAsG;AACtG,MAAM,WAAW,OAAO;IACvB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,8CAA8C;IAC9C,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,gDAAgD;IAChD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,sCAAsC;IACtC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,gDAAgD;IAChD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACvC;AAED,gDAAgD;AAChD,MAAM,WAAW,QAAQ;IACxB,qDAAqD;IACrD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uFAAuF;IACvF,QAAQ,CAAC,EAAE,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,gDAAgD;IAChD,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,oFAAoF;IACpF,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../src/server/options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,sGAAsG;AACtG,MAAM,WAAW,OAAO;IACvB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,8CAA8C;IAC9C,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,gDAAgD;IAChD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,sCAAsC;IACtC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,gDAAgD;IAChD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACvC;AAED,6FAA6F;AAC7F,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAExD;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IACjC,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,SAAS,EAAE,CAAC;IACjD,4GAA4G;IAC5G,QAAQ,CAAC,KAAK,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CACrE;AAED,gDAAgD;AAChD,MAAM,WAAW,QAAQ;IACxB,qDAAqD;IACrD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uFAAuF;IACvF,QAAQ,CAAC,EAAE,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,gDAAgD;IAChD,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,oFAAoF;IACpF,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAAC;IACnC,qIAAqI;IACrI,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,+HAA+H;IAC/H,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,yFAAyF;IACzF,QAAQ,CAAC,UAAU,EAAE,SAAS,iBAAiB,EAAE,CAAC;CAClD;AAED,0EAA0E;AAC1E,MAAM,WAAW,eAAe;IAC/B,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IAC7C;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;CAC7B;AAED;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,SAAS,GAAG,IAAI,CAAC;AAElD,MAAM,WAAW,SAAS;IACzB;;;;;OAKG;IACH,SAAS,CAAC,CAAC,OAAO,EAAE,OAAO,GAAG,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/D,kDAAkD;IAClD,UAAU,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,GAAG,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC5E,mEAAmE;IACnE,QAAQ,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,GAAG,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC1E;;;;;OAKG;IACH,MAAM,CACL,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,OAAO,GACd,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CACpC;AAED,uEAAuE;AACvE,MAAM,WAAW,UAAU;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC;IAChD,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC;CACjD;AAED,kEAAkE;AAClE,MAAM,WAAW,oBAAoB;IACpC,sFAAsF;IACtF,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAED,MAAM,WAAW,iBAAkB,SAAQ,SAAS;IACnD,sFAAsF;IACtF,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,GAAG,YAAY,CAAC;IACpC;;;;;;OAMG;IACH,QAAQ,CAAC,YAAY,EAClB,SAAS,MAAM,EAAE,GACjB,CAAC,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;IACpD,wEAAwE;IACxE,QAAQ,CAAC,GAAG,CAAC,EAAE,UAAU,CAAC;IAC1B,iEAAiE;IACjE,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B;;;;;OAKG;IACH,YAAY,CAAC,CACZ,WAAW,EAAE,WAAW,EACxB,OAAO,EAAE,OAAO,GACd,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9B,qFAAqF;IACrF,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,kGAAkG;IAClG,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,8CAA8C;IAC9C,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC;;;;;;;OAOG;IACH,QAAQ,CAAC,uBAAuB,CAAC,EAAE,MAAM,CAAC;IAC1C,iEAAiE;IACjE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,sIAAsI;IACtI,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,oBAAoB,CAAC;IAC9C;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC;;;;;;OAMG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;OAIG;IACH,OAAO,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;CACjD"}
|
package/dist/server/state.d.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import type { Envelope } from './options';
|
|
1
|
+
import type { Envelope, EnvelopeRecipient } from './options';
|
|
2
2
|
/** A mail transaction in progress (RFC 5321 §3.3). */
|
|
3
3
|
export interface Transaction {
|
|
4
4
|
from?: string;
|
|
5
5
|
to: string[];
|
|
6
|
+
recipients: EnvelopeRecipient[];
|
|
7
|
+
ret?: Envelope['ret'];
|
|
8
|
+
envid?: string;
|
|
6
9
|
smtputf8: boolean;
|
|
7
10
|
body: Envelope['body'];
|
|
8
11
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/server/state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/server/state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAE7D,sDAAsD;AACtD,MAAM,WAAW,WAAW;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,EAAE,CAAC;IACb,UAAU,EAAE,iBAAiB,EAAE,CAAC;IAChC,GAAG,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;CACvB;AAED,6CAA6C;AAC7C,MAAM,MAAM,OAAO,GAChB,SAAS,GACT,MAAM,GACN,YAAY,GACZ,iBAAiB,GACjB,qBAAqB,CAAC;AAEzB,kDAAkD;AAClD,MAAM,WAAW,KAAK;IACrB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,WAAW,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,gBAAgB,QAAO,WAKlC,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Connection } from './connection';
|
|
2
|
-
/** `MAIL FROM:<path> [SIZE=] [BODY=] [SMTPUTF8] [AUTH=]` (RFC 5321 §4.1.1.2). */
|
|
2
|
+
/** `MAIL FROM:<path> [SIZE=] [BODY=] [SMTPUTF8] [AUTH=] [RET=] [ENVID=]` (RFC 5321 §4.1.1.2, RFC 3461 §4.3, §4.4). */
|
|
3
3
|
export declare function mail(connection: Connection, argument: string): Promise<void>;
|
|
4
|
-
/** `RCPT TO:<path
|
|
4
|
+
/** `RCPT TO:<path> [NOTIFY=] [ORCPT=]` (RFC 5321 §4.1.1.3, RFC 3461 §4.1, §4.2), where relaying is refused without AUTH. */
|
|
5
5
|
export declare function rcpt(connection: Connection, argument: string): Promise<void>;
|
|
6
6
|
//# sourceMappingURL=transaction.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transaction.d.ts","sourceRoot":"","sources":["../../src/server/transaction.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"transaction.d.ts","sourceRoot":"","sources":["../../src/server/transaction.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAY/C,sHAAsH;AACtH,wBAAsB,IAAI,CACzB,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC,CAkEf;AAED,4HAA4H;AAC5H,wBAAsB,IAAI,CACzB,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC,CAoDf"}
|
package/docs/guide.md
CHANGED
|
@@ -192,7 +192,9 @@ Every reply the server sends of its own:
|
|
|
192
192
|
| `503 5.5.1 Send MAIL first` | RCPT or DATA before MAIL |
|
|
193
193
|
| `554 5.5.1 No valid recipients` | DATA with no recipient accepted; what the client pipelined behind it in the same write is dropped, not run as commands |
|
|
194
194
|
| `501 5.5.4 Syntax: MAIL FROM:<address>` / `RCPT TO:<address>` / `DATA` | the command's syntax is wrong |
|
|
195
|
-
| `555 5.5.4 <PARAM> is not supported` | an ESMTP parameter other than SIZE, BODY, SMTPUTF8 and
|
|
195
|
+
| `555 5.5.4 <PARAM> is not supported` | an ESMTP parameter other than SIZE, BODY, SMTPUTF8, AUTH, RET and ENVID on MAIL, or other than NOTIFY and ORCPT on RCPT |
|
|
196
|
+
| `501 5.5.4 Syntax: RET=…` / `ENVID=…` / `NOTIFY=…` / `ORCPT=…` | a DSN parameter with a malformed value (RFC 3461 §4) |
|
|
197
|
+
| `501 5.5.4 <PARAM> given twice` | a DSN parameter repeated on one command |
|
|
196
198
|
| `555 5.5.4 <PARAM> needs EHLO` | a parameter after HELO |
|
|
197
199
|
| `501 5.5.4 Syntax: SIZE=<bytes>` | SIZE is not a number |
|
|
198
200
|
| `501 5.5.4 BODY is 7BIT or 8BITMIME` | another BODY value |
|
|
@@ -463,6 +465,20 @@ export interface Envelope {
|
|
|
463
465
|
readonly smtputf8: boolean;
|
|
464
466
|
/** `7BIT` or `8BITMIME`, as MAIL FROM's BODY= said; `7BIT` when it said nothing. */
|
|
465
467
|
readonly body: '7BIT' | '8BITMIME';
|
|
468
|
+
/** MAIL FROM's RET= (RFC 3461 §4.3); absent when not sent. */
|
|
469
|
+
readonly ret?: 'FULL' | 'HDRS';
|
|
470
|
+
/** MAIL FROM's ENVID=, decoded from xtext (RFC 3461 §4.4); absent when not sent. */
|
|
471
|
+
readonly envid?: string;
|
|
472
|
+
/** The recipients accepted, in the order of `to`, with their DSN parameters. */
|
|
473
|
+
readonly recipients: readonly EnvelopeRecipient[];
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
export interface EnvelopeRecipient {
|
|
477
|
+
readonly address: string; // the matching entry of `to`
|
|
478
|
+
/** NOTIFY= (RFC 3461 §4.1): `'NEVER'` or the events given; absent when not sent. */
|
|
479
|
+
readonly notify?: 'NEVER' | readonly ('SUCCESS' | 'FAILURE' | 'DELAY')[];
|
|
480
|
+
/** ORCPT= (RFC 3461 §4.2): the type as sent and the address decoded from xtext. */
|
|
481
|
+
readonly orcpt?: { readonly type: string; readonly address: string };
|
|
466
482
|
}
|
|
467
483
|
```
|
|
468
484
|
|
|
@@ -636,6 +652,83 @@ const server = createSmtpServer({
|
|
|
636
652
|
await server.listen({ port: 25 });
|
|
637
653
|
```
|
|
638
654
|
|
|
655
|
+
## Delivery status notifications (DSN)
|
|
656
|
+
|
|
657
|
+
The server advertises `DSN` (RFC 3461) in its EHLO reply, always (no option to
|
|
658
|
+
turn it off). A client may then send `RET=FULL|HDRS` and `ENVID=<xtext>` on
|
|
659
|
+
`MAIL FROM`, and `NOTIFY=NEVER` (or a comma list of `SUCCESS`, `FAILURE`,
|
|
660
|
+
`DELAY`) and `ORCPT=<addr-type>;<xtext>` on `RCPT TO`. The server checks
|
|
661
|
+
their syntax, decodes the xtext and puts them on the `Envelope` `onData`
|
|
662
|
+
receives: `ret` and `envid`, and for each accepted recipient `notify` and
|
|
663
|
+
`orcpt` in `recipients`. `to` is unchanged.
|
|
664
|
+
|
|
665
|
+
The server does nothing else with them. Once it advertises DSN, the app that
|
|
666
|
+
receives these parameters must honour them, or the client is told something
|
|
667
|
+
untrue:
|
|
668
|
+
|
|
669
|
+
- An app that **relays** the message (a queue, a smarthost) passes them on
|
|
670
|
+
to the next hop, or generates the DSN itself when the next hop does not
|
|
671
|
+
advertise DSN.
|
|
672
|
+
- An app that **delivers locally** generates a DSN for a recipient that asked
|
|
673
|
+
for `SUCCESS` and was delivered, returning the message or only its
|
|
674
|
+
headers as `ret` says, and puts `envid` and `orcpt` in the report.
|
|
675
|
+
- `NOTIFY=NEVER` means no DSN for that recipient, a bounce included.
|
|
676
|
+
|
|
677
|
+
```ts
|
|
678
|
+
import { createSmtpServer } from '@bumail/smtp';
|
|
679
|
+
|
|
680
|
+
createSmtpServer({
|
|
681
|
+
hostname: 'mx.example.com',
|
|
682
|
+
localDomains: ['example.com'],
|
|
683
|
+
async onData({ envelope }) {
|
|
684
|
+
for (const { address, notify, orcpt } of envelope.recipients) {
|
|
685
|
+
if (notify === 'NEVER') continue; // no DSN for this one, ever
|
|
686
|
+
// deliver to `address`; report to `envelope.from` as `notify` asks,
|
|
687
|
+
// quoting `envelope.envid` and `orcpt?.address`
|
|
688
|
+
}
|
|
689
|
+
},
|
|
690
|
+
});
|
|
691
|
+
```
|
|
692
|
+
|
|
693
|
+
A malformed or repeated DSN parameter is answered `501 5.5.4`; a parameter
|
|
694
|
+
after `HELO` gets `555 <PARAM> needs EHLO`.
|
|
695
|
+
|
|
696
|
+
### Sending DSN parameters
|
|
697
|
+
|
|
698
|
+
`sendMail` takes `ret`, `envid` and `recipients` (the shape of
|
|
699
|
+
`Envelope.recipients`: `address`, `notify`, `orcpt`, matched to `to` by
|
|
700
|
+
address), so a received envelope can be passed through when a relay hands the
|
|
701
|
+
message on. They are written only when the next hop's EHLO lists `DSN`, with
|
|
702
|
+
`envid` and the `orcpt` address xtext-encoded (RFC 3461 §4). An `orcpt` whose
|
|
703
|
+
type is not `rfc822`, or whose address is not ASCII (RFC 6533), is left out of
|
|
704
|
+
the command, not refused, so a relay never fails on what a received envelope
|
|
705
|
+
carries. When the next hop lists no `DSN` nothing is sent, the delivery goes
|
|
706
|
+
through as usual, and the result says `dsnOffered: false`: the relay must then
|
|
707
|
+
generate the DSNs itself (RFC 3461 §5.2.2).
|
|
708
|
+
|
|
709
|
+
```ts
|
|
710
|
+
import { sendMail } from '@bumail/smtp/client';
|
|
711
|
+
|
|
712
|
+
const result = await sendMail(message, {
|
|
713
|
+
host: 'smtp.relay.example',
|
|
714
|
+
from: 'a@example.com',
|
|
715
|
+
to: ['b@example.net'],
|
|
716
|
+
ret: 'HDRS',
|
|
717
|
+
envid: 'q-1042',
|
|
718
|
+
recipients: [{ address: 'b@example.net', notify: ['FAILURE', 'DELAY'] }],
|
|
719
|
+
});
|
|
720
|
+
if (!result.dsnOffered) {
|
|
721
|
+
// the next hop never saw NOTIFY: send the 'relayed' DSN here
|
|
722
|
+
}
|
|
723
|
+
```
|
|
724
|
+
|
|
725
|
+
`dsnOffered` is the server listing `DSN` in EHLO; it does not prove the next
|
|
726
|
+
hop will send a DSN. These are `INVALID_OPTION`: a wrong `ret`, `notify` or
|
|
727
|
+
`orcpt` shape; an `envid` over 100 characters once xtext-encoded (RFC 3461
|
|
728
|
+
§4.4); an `orcpt` over 500 characters once encoded (§4.2), whose type is not a
|
|
729
|
+
token, or whose address is empty; a `recipients` entry not in `to`, or named
|
|
730
|
+
twice.
|
|
731
|
+
|
|
639
732
|
## Delivering into @bumail/store
|
|
640
733
|
|
|
641
734
|
[`@bumail/store`](https://github.com/softistx/bumail/tree/develop/packages/store) keeps
|
|
@@ -1893,6 +1986,7 @@ console.log(chunk.done, reader.bareLineBreaks);
|
|
|
1893
1986
|
| SIZE | RFC 1870 |
|
|
1894
1987
|
| PIPELINING | RFC 2920 |
|
|
1895
1988
|
| 8BITMIME | RFC 6152 |
|
|
1989
|
+
| DSN parameters (`RET`, `ENVID`, `NOTIFY`, `ORCPT`) and xtext | RFC 3461 §4 |
|
|
1896
1990
|
| SMTPUTF8 | RFC 6531 |
|
|
1897
1991
|
| ENHANCEDSTATUSCODES and the codes themselves | RFC 2034, RFC 3463 |
|
|
1898
1992
|
| STARTTLS | RFC 3207 |
|
|
@@ -1914,9 +2008,9 @@ each one comes from.
|
|
|
1914
2008
|
|
|
1915
2009
|
## What is not implemented
|
|
1916
2010
|
|
|
1917
|
-
- **
|
|
1918
|
-
`
|
|
1919
|
-
|
|
2011
|
+
- **Generating DSNs.** The server advertises DSN and hands the parameters to
|
|
2012
|
+
`onData` (see [Delivery status notifications](#delivery-status-notifications-dsn)),
|
|
2013
|
+
but it never writes a notification: honouring them is the app's job.
|
|
1920
2014
|
- **CHUNKING** (RFC 3030). `BDAT` is answered `500 5.5.2 Command
|
|
1921
2015
|
unrecognized`; a client sends DATA instead.
|
|
1922
2016
|
- **A queue.** The client tries a destination once and reports;
|
|
@@ -1924,7 +2018,8 @@ each one comes from.
|
|
|
1924
2018
|
- **Connection reuse.** The client opens one connection per message, and
|
|
1925
2019
|
sends no `RSET`. Several messages to one destination over one session is
|
|
1926
2020
|
on the [roadmap](roadmap.md).
|
|
1927
|
-
-
|
|
2021
|
+
- **`ORCPT` of an RFC 6533 type (`utf-8`) or with a non-ASCII address in the
|
|
2022
|
+
client**: it is left out of `RCPT TO`, not sent.
|
|
1928
2023
|
- **CHUNKING in the client.** It sends DATA, never `BDAT`.
|
|
1929
2024
|
- **DANE and MTA-STS.** By MX, TLS is opportunistic; a policy that makes
|
|
1930
2025
|
it required for a domain is for later.
|
package/docs/roadmap.md
CHANGED
|
@@ -6,22 +6,23 @@ number on it.
|
|
|
6
6
|
|
|
7
7
|
## Now
|
|
8
8
|
|
|
9
|
-
Nothing
|
|
9
|
+
Nothing is under way besides what is marked shipped below.
|
|
10
10
|
|
|
11
11
|
## Next
|
|
12
12
|
|
|
13
13
|
- **Connection reuse in the client** — several messages to one
|
|
14
14
|
destination over one session (`RSET` between them), for a queue that
|
|
15
15
|
delivers in batches. Today each `sendMail` opens its own connection.
|
|
16
|
-
- **DSN** (RFC 3461) — `RET`, `ENVID`, `NOTIFY` and `ORCPT` accepted and
|
|
17
|
-
handed to the app, so a sender can ask for delivery status
|
|
18
|
-
notifications. Today they are refused with `555 5.5.4`, and the client
|
|
19
|
-
sends none.
|
|
20
16
|
- **Delivery into `@bumail/store`, ready-made** — an `onData` that puts
|
|
21
17
|
each message in its recipients' inboxes, instead of the few lines the
|
|
22
18
|
[guide](guide.md#delivering-into-bumailstore) shows today. The store
|
|
23
19
|
itself has landed; only the helper is to come.
|
|
24
20
|
|
|
21
|
+
## Later
|
|
22
|
+
|
|
23
|
+
- **UTF-8 address types in DSNs** (RFC 6533) — internationalized addresses
|
|
24
|
+
in the `ORCPT` parameter and in the reports built from it.
|
|
25
|
+
|
|
25
26
|
## Not planned
|
|
26
27
|
|
|
27
28
|
- **Relaying without AUTH** — not as a default, not as an option. A
|
|
@@ -34,6 +35,11 @@ Nothing in progress.
|
|
|
34
35
|
|
|
35
36
|
### Unreleased — merged, not yet published
|
|
36
37
|
|
|
38
|
+
- **DSN requests (RFC 3461)**: the server accepts `RET`, `ENVID`, `NOTIFY`
|
|
39
|
+
and `ORCPT` and hands them to the app, and always lists `DSN` in its
|
|
40
|
+
`EHLO` reply, so these parameters are no longer refused with `555 5.5.4`
|
|
41
|
+
(a client that relied on that refusal has to adapt). The client sends
|
|
42
|
+
them when the next hop lists `DSN`, and its result reports `dsnOffered`.
|
|
37
43
|
- **The envelope on an `afterData` error**: `SmtpError.accepted` and
|
|
38
44
|
`rejected` list the recipients the server took and refused at `RCPT TO`
|
|
39
45
|
when the session failed after the final dot.
|
package/docs/troubleshooting.md
CHANGED
|
@@ -63,6 +63,8 @@ A reply carries its enhanced status code (`5.7.1`, RFC 3463) only after
|
|
|
63
63
|
- [`503 5.5.1 TLS already active`](#503-551-tls-already-active)
|
|
64
64
|
- [`501 5.5.4 BODY is 7BIT or 8BITMIME`](#501-554-body-is-7bit-or-8bitmime)
|
|
65
65
|
- [`555 5.5.4 … is not supported`](#555-554--is-not-supported)
|
|
66
|
+
- [`501 5.5.4 Syntax: RET=…`, `ENVID=…`, `NOTIFY=…`, `ORCPT=…`](#501-554-syntax-ret-envid-notify-orcpt)
|
|
67
|
+
- [`501 5.5.4 … given twice`](#501-554--given-twice)
|
|
66
68
|
- [`555 … needs EHLO`](#555--needs-ehlo)
|
|
67
69
|
- [`553 5.6.7 A non-ASCII address needs SMTPUTF8`](#553-567-a-non-ascii-address-needs-smtputf8)
|
|
68
70
|
- [`500 5.5.6 Line too long`](#500-556-line-too-long)
|
|
@@ -1136,14 +1138,60 @@ S: 250 2.1.0 OK
|
|
|
1136
1138
|
### `555 5.5.4 … is not supported`
|
|
1137
1139
|
|
|
1138
1140
|
**When**: `MAIL FROM` with a parameter other than `SIZE`, `BODY`,
|
|
1139
|
-
`SMTPUTF8
|
|
1140
|
-
|
|
1141
|
+
`SMTPUTF8`, `AUTH`, `RET` and `ENVID`; or `RCPT TO` with one other than
|
|
1142
|
+
`NOTIFY` and `ORCPT`; or `SMTPUTF8` given a value.
|
|
1141
1143
|
|
|
1142
|
-
**Why**: the server supports only the extensions its EHLO lists.
|
|
1143
|
-
|
|
1144
|
+
**Why**: the server supports only the extensions its EHLO lists. The DSN
|
|
1145
|
+
parameters (RFC 3461) are accepted, each on its own command: `RET` on
|
|
1146
|
+
`RCPT TO`, or `NOTIFY` on `MAIL FROM`, is refused here.
|
|
1144
1147
|
|
|
1145
|
-
**Fix**, as a client: send only the parameters the EHLO reply announces
|
|
1146
|
-
|
|
1148
|
+
**Fix**, as a client: send only the parameters the EHLO reply announces,
|
|
1149
|
+
each on the command it belongs to.
|
|
1150
|
+
|
|
1151
|
+
### `INVALID_OPTION` from `sendMail`: `envid …` or `orcpt …`
|
|
1152
|
+
|
|
1153
|
+
**When**: `sendMail` is given a DSN option it refuses, before any connection.
|
|
1154
|
+
The messages: `envid must be 1 to 100 printable ASCII characters, at most 100
|
|
1155
|
+
once encoded as xtext`; `orcpt of <address> must be { type, address }, the type
|
|
1156
|
+
a token`; `orcpt.address of <address> must be a non-empty string`; `orcpt of
|
|
1157
|
+
<address> is over 500 characters once encoded`.
|
|
1158
|
+
|
|
1159
|
+
**Why**: RFC 3461 §4.4 and §4.2 cap the parameters as sent, so a character that
|
|
1160
|
+
xtext writes as `+XX` counts three.
|
|
1161
|
+
|
|
1162
|
+
**Fix**: shorten the value, or give the type as letters, digits and hyphens.
|
|
1163
|
+
|
|
1164
|
+
```ts
|
|
1165
|
+
await sendMail(message, { host, from, to, envid: 'q-1042' }); // not 'q 1042 …' past 100 encoded
|
|
1166
|
+
```
|
|
1167
|
+
|
|
1168
|
+
### `501 5.5.4 Syntax: RET=…`, `ENVID=…`, `NOTIFY=…`, `ORCPT=…`
|
|
1169
|
+
|
|
1170
|
+
**When**: a DSN parameter has a value the RFC does not allow: `RET` other
|
|
1171
|
+
than `FULL` or `HDRS`; `ENVID` empty, longer than 100 characters as sent,
|
|
1172
|
+
not printable ASCII or not xtext; `NOTIFY` mixing `NEVER` with another
|
|
1173
|
+
event, naming an event twice or an unknown one; `ORCPT` with no
|
|
1174
|
+
`addr-type;` prefix, an address that is not xtext, or more than 500
|
|
1175
|
+
characters as sent (RFC 3461 §4.2).
|
|
1176
|
+
|
|
1177
|
+
**Why**: RFC 3461 §4. The server refuses the command rather than hand a
|
|
1178
|
+
wrong value to `onData`.
|
|
1179
|
+
|
|
1180
|
+
**Fix**, as a client: encode the value as xtext (`+` and `=`, spaces and
|
|
1181
|
+
non-ASCII bytes as `+XX`), and send `NOTIFY=NEVER` alone.
|
|
1182
|
+
|
|
1183
|
+
```text
|
|
1184
|
+
C: RCPT TO:<bob@example.com> NOTIFY=SUCCESS,FAILURE ORCPT=rfc822;bob+2Btag@example.com
|
|
1185
|
+
S: 250 2.1.5 OK
|
|
1186
|
+
```
|
|
1187
|
+
|
|
1188
|
+
### `501 5.5.4 … given twice`
|
|
1189
|
+
|
|
1190
|
+
**When**: `RET`, `ENVID`, `NOTIFY` or `ORCPT` appears twice on one command.
|
|
1191
|
+
|
|
1192
|
+
**Why**: each DSN parameter may be given once (RFC 3461 §4).
|
|
1193
|
+
|
|
1194
|
+
**Fix**, as a client: send it once; join `NOTIFY` events in one list.
|
|
1147
1195
|
|
|
1148
1196
|
### `555 … needs EHLO`
|
|
1149
1197
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bumail/smtp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "An SMTP server on Bun.listen — RFC 5321 with PIPELINING, SIZE, 8BITMIME, SMTPUTF8, STARTTLS and AUTH after TLS, policy hooks, and no open relay — and a client that delivers a message to a smarthost or by MX",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -47,9 +47,9 @@
|
|
|
47
47
|
]
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@bumail/auth": "^0.
|
|
50
|
+
"@bumail/auth": "^0.5.0",
|
|
51
51
|
"@bumail/dns": "^0.2.1",
|
|
52
|
-
"@bumail/store": "^0.
|
|
52
|
+
"@bumail/store": "^0.6.0",
|
|
53
53
|
"@types/bun": "^1.4.2"
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|