Skip to content

Commit 288ec6b

Browse files
committed
test: get (mostly) working
1 parent ff606d2 commit 288ec6b

File tree

9 files changed

+441
-402
lines changed

9 files changed

+441
-402
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
"scripts": {
5353
"build": "rollup -c rollup.config.ts",
5454
"lint": "eslint *.ts \"+(smtp|test)/*.ts\"",
55-
"test": "ava",
55+
"test": "ava --serial",
5656
"test:rollup": "ava --file rollup/email.bundle.test.js"
5757
},
5858
"license": "MIT",

smtp/client.ts

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ export class Client {
8686
clearTimeout(this.timer);
8787
}
8888

89-
if (this.queue.length > 0) {
89+
if (this.queue.length) {
9090
if (this.smtp.state() == SMTPState.NOTCONNECTED) {
9191
this._connect(this.queue[0]);
9292
} else if (
@@ -129,10 +129,10 @@ export class Client {
129129
}
130130
};
131131

132-
if (this.smtp.authorized()) {
133-
this.smtp.ehlo_or_helo_if_needed(begin);
134-
} else {
132+
if (!this.smtp.authorized()) {
135133
this.smtp.login(begin);
134+
} else {
135+
this.smtp.ehlo_or_helo_if_needed(begin);
136136
}
137137
} else {
138138
stack.callback(err, stack.message);
@@ -152,8 +152,8 @@ export class Client {
152152
* @param {MessageStack} msg message stack
153153
* @returns {boolean} can make message
154154
*/
155-
_canMakeMessage(msg: import('./message').MessageHeaders): boolean {
156-
return !!(
155+
_canMakeMessage(msg: import('./message').MessageHeaders) {
156+
return (
157157
msg.from &&
158158
(msg.to || msg.cc || msg.bcc) &&
159159
(msg.text !== undefined || this._containsInlinedHtml(msg.attachment))
@@ -194,15 +194,12 @@ export class Client {
194194
* @param {function(MessageStack): void} next next
195195
* @returns {function(Error): void} callback
196196
*/
197-
_sendsmtp(
198-
stack: MessageStack,
199-
next: (msg: MessageStack) => void
200-
): (err: Error) => void {
197+
_sendsmtp(stack: MessageStack, next: (msg: MessageStack) => void) {
201198
/**
202199
* @param {Error} [err] error
203200
* @returns {void}
204201
*/
205-
return (err) => {
202+
return (err: Error) => {
206203
if (!err && next) {
207204
next.apply(this, [stack]);
208205
} else {
@@ -234,12 +231,9 @@ export class Client {
234231
throw new TypeError('stack.to must be array');
235232
}
236233

237-
const to = stack.to.shift()?.address;
234+
const to = stack.to.shift()!.address;
238235
this.smtp.rcpt(
239-
this._sendsmtp(
240-
stack,
241-
stack.to.length > 0 ? this._sendrcpt : this._senddata
242-
),
236+
this._sendsmtp(stack, stack.to.length ? this._sendrcpt : this._senddata),
243237
`<${to}>`
244238
);
245239
}

smtp/error.ts

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
1-
/* eslint-disable no-unused-vars */
2-
export enum SMTPErrorStates {
3-
COULDNOTCONNECT = 1,
4-
BADRESPONSE = 2,
5-
AUTHFAILED = 3,
6-
TIMEDOUT = 4,
7-
ERROR = 5,
8-
NOCONNECTION = 6,
9-
AUTHNOTSUPPORTED = 7,
10-
CONNECTIONCLOSED = 8,
11-
CONNECTIONENDED = 9,
12-
CONNECTIONAUTH = 10,
13-
}
14-
/* eslint-enable no-unused-vars */
1+
/**
2+
* @readonly
3+
* @enum
4+
*/
5+
export const SMTPErrorStates = {
6+
COULDNOTCONNECT: 1,
7+
BADRESPONSE: 2,
8+
AUTHFAILED: 3,
9+
TIMEDOUT: 4,
10+
ERROR: 5,
11+
NOCONNECTION: 6,
12+
AUTHNOTSUPPORTED: 7,
13+
CONNECTIONCLOSED: 8,
14+
CONNECTIONENDED: 9,
15+
CONNECTIONAUTH: 10,
16+
} as const;
1517

1618
class SMTPError extends Error {
1719
public code: number | null = null;
@@ -26,7 +28,7 @@ class SMTPError extends Error {
2628
export function makeSMTPError(
2729
message: string,
2830
code: number,
29-
error?: Error,
31+
error?: Error | null,
3032
smtp?: any
3133
) {
3234
const msg = error?.message ? `${message} (${error.message})` : message;

smtp/message.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ class MessageStream extends Stream {
359359

360360
const output_file = (
361361
attachment: MessageAttachment | AlternateMessageAttachment,
362-
next: (err: NodeJS.ErrnoException) => void
362+
next: (err: NodeJS.ErrnoException | null) => void
363363
) => {
364364
const chunk = MIME64CHUNK * 16;
365365
const buffer = Buffer.alloc(chunk);
@@ -370,9 +370,9 @@ class MessageStream extends Stream {
370370
* @param {number} fd the file descriptor
371371
* @returns {void}
372372
*/
373-
const opened = (err: Error, fd: number) => {
373+
const opened = (err: NodeJS.ErrnoException | null, fd: number) => {
374374
if (!err) {
375-
const read = (err: Error, bytes: number) => {
375+
const read = (err: NodeJS.ErrnoException | null, bytes: number) => {
376376
if (!err && this.readable) {
377377
let encoding =
378378
attachment && attachment.headers

smtp/response.ts

Lines changed: 85 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -2,118 +2,106 @@ import { makeSMTPError, SMTPErrorStates } from './error';
22

33
type Socket = import('net').Socket | import('tls').TLSSocket;
44
export class SMTPResponse {
5-
private buffer = '';
65
public stop: (err?: Error) => void;
76

8-
constructor(
9-
private stream: Socket,
10-
timeout: number,
11-
onerror: (err: Error) => void
12-
) {
13-
const watch = (data: Parameters<SMTPResponse['watch']>[0]) =>
14-
this.watch(data);
15-
const end = (err: Error) => this.end(err);
16-
const close = (err: Error) => this.close(err);
17-
const error = (data: Parameters<SMTPResponse['error']>[0]) =>
18-
this.error(data);
19-
const timedout = (data: Parameters<SMTPResponse['timedout']>[0]) =>
20-
this.timedout(data);
7+
constructor(stream: Socket, timeout: number, onerror: (err: Error) => void) {
8+
let buffer = '';
219

22-
this.stream.on('data', watch);
23-
this.stream.on('end', end);
24-
this.stream.on('close', close);
25-
this.stream.on('error', error);
26-
this.stream.setTimeout(timeout, timedout);
10+
const notify = () => {
11+
if (buffer.length) {
12+
// parse buffer for response codes
13+
const line = buffer.replace('\r', '');
14+
if (
15+
!(
16+
line
17+
.trim()
18+
.split(/\n/)
19+
.pop()
20+
?.match(/^(\d{3})\s/) ?? false
21+
)
22+
) {
23+
return;
24+
}
2725

28-
this.stop = (err) => {
29-
this.stream.removeAllListeners('response');
30-
this.stream.removeListener('data', watch);
31-
this.stream.removeListener('end', end);
32-
this.stream.removeListener('close', close);
33-
this.stream.removeListener('error', error);
26+
const match = line ? line.match(/(\d+)\s?(.*)/) : null;
27+
const data =
28+
match !== null
29+
? { code: match[1], message: match[2], data: line }
30+
: { code: -1, data: line };
3431

35-
if (err != null && typeof onerror === 'function') {
36-
onerror(err);
32+
stream.emit('response', null, data);
33+
buffer = '';
3734
}
3835
};
39-
}
4036

41-
public notify() {
42-
if (this.buffer.length) {
43-
// parse buffer for response codes
44-
const line = this.buffer.replace('\r', '');
45-
if (
46-
!(
47-
line
48-
.trim()
49-
.split(/\n/)
50-
.pop()
51-
?.match(/^(\d{3})\s/) ?? false
37+
const error = (err: Error) => {
38+
stream.emit(
39+
'response',
40+
makeSMTPError(
41+
'connection encountered an error',
42+
SMTPErrorStates.ERROR,
43+
err
5244
)
53-
) {
54-
return;
55-
}
45+
);
46+
};
5647

57-
const match = line ? line.match(/(\d+)\s?(.*)/) : null;
58-
const data =
59-
match !== null
60-
? { code: match[1], message: match[2], data: line }
61-
: { code: -1, data: line };
48+
const timedout = (err?: Error) => {
49+
stream.end();
50+
stream.emit(
51+
'response',
52+
makeSMTPError(
53+
'timedout while connecting to smtp server',
54+
SMTPErrorStates.TIMEDOUT,
55+
err
56+
)
57+
);
58+
};
6259

63-
this.stream.emit('response', null, data);
64-
this.buffer = '';
65-
}
66-
}
60+
const watch = (data: string | Buffer) => {
61+
if (data !== null) {
62+
buffer += data.toString();
63+
notify();
64+
}
65+
};
6766

68-
protected error(err: Error) {
69-
this.stream.emit(
70-
'response',
71-
makeSMTPError(
72-
'connection encountered an error',
73-
SMTPErrorStates.ERROR,
74-
err
75-
)
76-
);
77-
}
67+
const close = (err: Error) => {
68+
stream.emit(
69+
'response',
70+
makeSMTPError(
71+
'connection has closed',
72+
SMTPErrorStates.CONNECTIONCLOSED,
73+
err
74+
)
75+
);
76+
};
7877

79-
protected timedout(err: Error) {
80-
this.stream.end();
81-
this.stream.emit(
82-
'response',
83-
makeSMTPError(
84-
'timedout while connecting to smtp server',
85-
SMTPErrorStates.TIMEDOUT,
86-
err
87-
)
88-
);
89-
}
78+
const end = (err: Error) => {
79+
stream.emit(
80+
'response',
81+
makeSMTPError(
82+
'connection has ended',
83+
SMTPErrorStates.CONNECTIONENDED,
84+
err
85+
)
86+
);
87+
};
9088

91-
protected watch(data: string | Buffer) {
92-
if (data !== null) {
93-
this.buffer += data.toString();
94-
this.notify();
95-
}
96-
}
89+
this.stop = (err) => {
90+
stream.removeAllListeners('response');
91+
stream.removeListener('data', watch);
92+
stream.removeListener('end', end);
93+
stream.removeListener('close', close);
94+
stream.removeListener('error', error);
9795

98-
protected close(err: Error) {
99-
this.stream.emit(
100-
'response',
101-
makeSMTPError(
102-
'connection has closed',
103-
SMTPErrorStates.CONNECTIONCLOSED,
104-
err
105-
)
106-
);
107-
}
96+
if (err != null && typeof onerror === 'function') {
97+
onerror(err);
98+
}
99+
};
108100

109-
protected end(err: Error) {
110-
this.stream.emit(
111-
'response',
112-
makeSMTPError(
113-
'connection has ended',
114-
SMTPErrorStates.CONNECTIONENDED,
115-
err
116-
)
117-
);
101+
stream.on('data', watch);
102+
stream.on('end', end);
103+
stream.on('close', close);
104+
stream.on('error', error);
105+
stream.setTimeout(timeout, timedout);
118106
}
119107
}

0 commit comments

Comments
 (0)