test-smtp-server 0.9.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/LICENSE +21 -0
- package/README.md +72 -0
- package/build/lib/test-smtp-server.d.ts +66 -0
- package/build/lib/test-smtp-server.js +141 -0
- package/package.json +67 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021 Chris. Webster
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Test SMTP Server
|
|
2
|
+
|
|
3
|
+
Test SMTP Server is a lightweight wrapper for
|
|
4
|
+
[smtp-server](<https://nodemailer.com/extras/smtp-server/>).
|
|
5
|
+
It is primarily intended for development and testing. The test code can start the server, run email tests and then validate the email contents. It can replace the use of external fake SMTP services which may have availablility issues.
|
|
6
|
+
|
|
7
|
+
All received emails are stored in an array. The emails may be viewed as raw data or a parsed object that is easily examined.
|
|
8
|
+
|
|
9
|
+
## Getting Started
|
|
10
|
+
|
|
11
|
+
### Prerequisites
|
|
12
|
+
|
|
13
|
+
Tested on Node v16 with npm v7.
|
|
14
|
+
|
|
15
|
+
### Installation
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
npm install test-smtp-server --save-dev
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Usage
|
|
22
|
+
|
|
23
|
+
See [test code](https://github.com/webstech/test-smtp-server/test/index.ts) for an example.
|
|
24
|
+
|
|
25
|
+
```js
|
|
26
|
+
import { testSmtpServer } from "test-smtp-server";
|
|
27
|
+
|
|
28
|
+
(async (): Promise<void> => {
|
|
29
|
+
const smtpserver = new testSmtpServer();
|
|
30
|
+
await smtpserver.startServer(); // start listening
|
|
31
|
+
|
|
32
|
+
// send some emails capturing ids ..
|
|
33
|
+
messageId.unshift( await sendMail(email, smtpOptions));
|
|
34
|
+
|
|
35
|
+
const mails = smtpserver.getEmails();
|
|
36
|
+
|
|
37
|
+
// validate/dump emails
|
|
38
|
+
|
|
39
|
+
if (mails.length) {
|
|
40
|
+
let entry = 0;
|
|
41
|
+
for (const mail of mails) {
|
|
42
|
+
console.log(`Checking mail entry <${entry}>`);
|
|
43
|
+
console.log(mail.envelope);
|
|
44
|
+
const parsed = await mail.getParsed();
|
|
45
|
+
if (parsed.messageId !== messageId[entry]) {
|
|
46
|
+
throw new Error(`Messageids do not match for email ${
|
|
47
|
+
entry} <${parsed.messageId}> <${messageId[entry]}>`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
console.log(parsed);
|
|
51
|
+
entry++;
|
|
52
|
+
}
|
|
53
|
+
} else {
|
|
54
|
+
throw new Error("No emails captured when expected");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
await smtpserver.stopServer(); // terminate server
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Security
|
|
61
|
+
|
|
62
|
+
The server is started as secure but that may not be possibly in the tesing
|
|
63
|
+
environment. If the server does not have a valid certificate, the connection
|
|
64
|
+
will fail from the client side. Some clients (e.g. nodemailer/SMTP-Transport options)
|
|
65
|
+
allow connections to non-secure servers. Node allows connections through an
|
|
66
|
+
environment variable that turns off certificate authorization chaecking. See
|
|
67
|
+
[node_tls_reject_unauthorizedvalue](https://nodejs.org/api/cli.html#node_tls_reject_unauthorizedvalue)
|
|
68
|
+
for more information. This may be insecure if other ports are used.
|
|
69
|
+
|
|
70
|
+
## License
|
|
71
|
+
|
|
72
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { SMTPServerEnvelope } from "smtp-server";
|
|
3
|
+
import { ParsedMail } from "mailparser";
|
|
4
|
+
/**
|
|
5
|
+
* Class to describe an email. The `envelope` contains the SMTP routing
|
|
6
|
+
* information. This may not match the `to/cc/bcc` information in the
|
|
7
|
+
* email contaents. The buffer contains the raw email content. To easily
|
|
8
|
+
* access parts of the email, `getParsed` should be used.
|
|
9
|
+
*/
|
|
10
|
+
export declare class eMail {
|
|
11
|
+
envelope: SMTPServerEnvelope;
|
|
12
|
+
buffer: Buffer | null;
|
|
13
|
+
length: number;
|
|
14
|
+
constructor(envelope: SMTPServerEnvelope, buffer: Buffer);
|
|
15
|
+
/**
|
|
16
|
+
* Return a parsed email as formatted by `simpleParser`.
|
|
17
|
+
*
|
|
18
|
+
* @returns Promise<ParsedMail> See
|
|
19
|
+
* https://nodemailer.com/extras/mailparser/ for the structure.
|
|
20
|
+
*/
|
|
21
|
+
getParsed(): Promise<ParsedMail>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* testSmtpServer optional parameters
|
|
25
|
+
*/
|
|
26
|
+
export declare type testSmtpServerOptions = {
|
|
27
|
+
/** the port number to use (default: 1025) */
|
|
28
|
+
smtpPort?: number;
|
|
29
|
+
/** logging function like console.log() */
|
|
30
|
+
debug?: (message?: unknown, ...optionalParams: any[]) => void;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Create a testSmtpServer. This provides a wrapper to SMTPServer that
|
|
34
|
+
* can be used for testing. The emails are stored in an array that
|
|
35
|
+
* can be examined to validate the content.
|
|
36
|
+
*/
|
|
37
|
+
export declare class testSmtpServer {
|
|
38
|
+
private debug;
|
|
39
|
+
private emails;
|
|
40
|
+
private isDebugging;
|
|
41
|
+
private port;
|
|
42
|
+
private server;
|
|
43
|
+
constructor(options?: testSmtpServerOptions | undefined);
|
|
44
|
+
/**
|
|
45
|
+
* Clear the set of emails.
|
|
46
|
+
*
|
|
47
|
+
* @returns number of emails deleted
|
|
48
|
+
*/
|
|
49
|
+
clearEmails(): number;
|
|
50
|
+
/**
|
|
51
|
+
* Retrieve the set of emails in order from latest to oldest.
|
|
52
|
+
*
|
|
53
|
+
* @returns array of eMail objects
|
|
54
|
+
*/
|
|
55
|
+
getEmails(): eMail[];
|
|
56
|
+
/**
|
|
57
|
+
* Query for the port number used by the server.
|
|
58
|
+
*
|
|
59
|
+
* @returns the port number being used
|
|
60
|
+
*/
|
|
61
|
+
getPort(): number;
|
|
62
|
+
/** Start the server */
|
|
63
|
+
startServer(): void;
|
|
64
|
+
/** Stop the server */
|
|
65
|
+
stopServer(): void;
|
|
66
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.testSmtpServer = exports.eMail = void 0;
|
|
4
|
+
const smtp_server_1 = require("smtp-server");
|
|
5
|
+
const mailparser_1 = require("mailparser");
|
|
6
|
+
const stream_1 = require("stream");
|
|
7
|
+
/**
|
|
8
|
+
* Class to describe an email. The `envelope` contains the SMTP routing
|
|
9
|
+
* information. This may not match the `to/cc/bcc` information in the
|
|
10
|
+
* email contaents. The buffer contains the raw email content. To easily
|
|
11
|
+
* access parts of the email, `getParsed` should be used.
|
|
12
|
+
*/
|
|
13
|
+
class eMail {
|
|
14
|
+
constructor(envelope, buffer) {
|
|
15
|
+
this.buffer = null;
|
|
16
|
+
this.length = 0;
|
|
17
|
+
this.envelope = envelope;
|
|
18
|
+
this.buffer = buffer;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Return a parsed email as formatted by `simpleParser`.
|
|
22
|
+
*
|
|
23
|
+
* @returns Promise<ParsedMail> See
|
|
24
|
+
* https://nodemailer.com/extras/mailparser/ for the structure.
|
|
25
|
+
*/
|
|
26
|
+
async getParsed() {
|
|
27
|
+
if (this.buffer) {
|
|
28
|
+
const stream = stream_1.Readable.from(this.buffer);
|
|
29
|
+
const options = {
|
|
30
|
+
skipHtmlToText: true,
|
|
31
|
+
skipTextLinks: true,
|
|
32
|
+
skipTextToHtml: true
|
|
33
|
+
};
|
|
34
|
+
return (0, mailparser_1.simpleParser)(stream, options);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
throw new Error("Empty email buffer");
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
exports.eMail = eMail;
|
|
42
|
+
/**
|
|
43
|
+
* Create a testSmtpServer. This provides a wrapper to SMTPServer that
|
|
44
|
+
* can be used for testing. The emails are stored in an array that
|
|
45
|
+
* can be examined to validate the content.
|
|
46
|
+
*/
|
|
47
|
+
class testSmtpServer {
|
|
48
|
+
constructor(options) {
|
|
49
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
50
|
+
this.debug = (_message, ..._optionalParams) => { };
|
|
51
|
+
this.emails = [];
|
|
52
|
+
this.isDebugging = false;
|
|
53
|
+
this.port = 1025;
|
|
54
|
+
if (options) {
|
|
55
|
+
if (options.smtpPort) {
|
|
56
|
+
this.port = options.smtpPort;
|
|
57
|
+
}
|
|
58
|
+
if (options.debug) {
|
|
59
|
+
this.debug = options.debug;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
63
|
+
const that = this; // preserve for use in other objects
|
|
64
|
+
this.server = new smtp_server_1.SMTPServer({
|
|
65
|
+
authOptional: true,
|
|
66
|
+
onConnect(session, callback) {
|
|
67
|
+
if (session.remoteAddress !== "127.0.0.1") {
|
|
68
|
+
return callback(new Error("Only connections from localhost allowed"));
|
|
69
|
+
}
|
|
70
|
+
return callback(); // Accept the connection
|
|
71
|
+
},
|
|
72
|
+
onAuth(auth, _session, callback) {
|
|
73
|
+
that.debug(`SMTP login for user: ${auth.username}`);
|
|
74
|
+
callback(null, { user: auth.username });
|
|
75
|
+
},
|
|
76
|
+
onData(stream, session, callback) {
|
|
77
|
+
const buffers = [];
|
|
78
|
+
const writer = new stream_1.Writable({
|
|
79
|
+
write(data, _encoding, writerCallback) {
|
|
80
|
+
buffers.push(data);
|
|
81
|
+
writerCallback();
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
stream.pipe(writer);
|
|
85
|
+
stream.on("end", () => {
|
|
86
|
+
const buffer = Buffer.concat(buffers);
|
|
87
|
+
const email = new eMail(session.envelope, buffer);
|
|
88
|
+
that.emails.unshift(email);
|
|
89
|
+
if (that.isDebugging) {
|
|
90
|
+
that.debug(JSON.stringify(email, (key, value) => {
|
|
91
|
+
if ("buffer" === key) {
|
|
92
|
+
return buffer.toString();
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
return value;
|
|
96
|
+
}
|
|
97
|
+
}, 2));
|
|
98
|
+
}
|
|
99
|
+
callback();
|
|
100
|
+
});
|
|
101
|
+
},
|
|
102
|
+
secure: true,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Clear the set of emails.
|
|
107
|
+
*
|
|
108
|
+
* @returns number of emails deleted
|
|
109
|
+
*/
|
|
110
|
+
clearEmails() {
|
|
111
|
+
const count = this.emails.length;
|
|
112
|
+
this.emails.length = 0;
|
|
113
|
+
return count;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Retrieve the set of emails in order from latest to oldest.
|
|
117
|
+
*
|
|
118
|
+
* @returns array of eMail objects
|
|
119
|
+
*/
|
|
120
|
+
getEmails() {
|
|
121
|
+
return this.emails;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Query for the port number used by the server.
|
|
125
|
+
*
|
|
126
|
+
* @returns the port number being used
|
|
127
|
+
*/
|
|
128
|
+
getPort() {
|
|
129
|
+
return this.port;
|
|
130
|
+
}
|
|
131
|
+
/** Start the server */
|
|
132
|
+
startServer() {
|
|
133
|
+
this.server.listen(this.port);
|
|
134
|
+
}
|
|
135
|
+
/** Stop the server */
|
|
136
|
+
stopServer() {
|
|
137
|
+
this.server.close();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
exports.testSmtpServer = testSmtpServer;
|
|
141
|
+
//# sourceMappingURL=test-smtp-server.js.map
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "test-smtp-server",
|
|
3
|
+
"version": "0.9.0",
|
|
4
|
+
"description": "The test-smtp-server package allows internal testing of projects needing an SMTP server.",
|
|
5
|
+
"main": "./build/lib/test-smtp-server.js",
|
|
6
|
+
"xtype": "module",
|
|
7
|
+
"types": "./build/lib/test-smtp-server.d.ts",
|
|
8
|
+
"directories": {
|
|
9
|
+
"lib": "lib",
|
|
10
|
+
"test": "test"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"/build/lib/test-smtp-server.js",
|
|
14
|
+
"/build/lib/test-smtp-server.d.ts"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc",
|
|
18
|
+
"lint": "eslint --ignore-path .gitignore -c .eslintrc.js --ext .ts,.js \"{lib,test}/**/*.{ts,tsx,mjs,js}\"",
|
|
19
|
+
"test": "npm run test:ts && npm run test:js",
|
|
20
|
+
"test:ts": "node build/test/index.js",
|
|
21
|
+
"test:js": "node test/jstest.mjs"
|
|
22
|
+
},
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/webstech/test-smtp-server/issues"
|
|
25
|
+
},
|
|
26
|
+
"homepage": "https://github.com/webstech/test-smtp-server#readme",
|
|
27
|
+
"keywords": [
|
|
28
|
+
"smtp",
|
|
29
|
+
"development",
|
|
30
|
+
"test",
|
|
31
|
+
"fake",
|
|
32
|
+
"dummy",
|
|
33
|
+
"mock",
|
|
34
|
+
"faux",
|
|
35
|
+
"email",
|
|
36
|
+
"e-mail",
|
|
37
|
+
"automated",
|
|
38
|
+
"integration",
|
|
39
|
+
"ci"
|
|
40
|
+
],
|
|
41
|
+
"author": "Chris. Webster <chris@webstech.net> (https://www.webstech.com/)",
|
|
42
|
+
"license": "MIT",
|
|
43
|
+
"repository": {
|
|
44
|
+
"type": "git",
|
|
45
|
+
"url": "git+https://github.com/webstech/test-smtp-server"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/nodemailer": "^6.4.4",
|
|
49
|
+
"@types/smtp-server": "^3.5.7",
|
|
50
|
+
"@typescript-eslint/eslint-plugin": "^5.1.0",
|
|
51
|
+
"@typescript-eslint/parser": "^5.1.0",
|
|
52
|
+
"commander": "^8.3.0",
|
|
53
|
+
"eslint": "^8.2.0",
|
|
54
|
+
"eslint-config-prettier": "^8.3.0",
|
|
55
|
+
"eslint-plugin-jsdoc": "^37.0.0",
|
|
56
|
+
"nodemailer": "^6.7.0",
|
|
57
|
+
"typescript": "^4.4.4"
|
|
58
|
+
},
|
|
59
|
+
"dependencies": {
|
|
60
|
+
"@types/mailparser": "^3.4.0",
|
|
61
|
+
"mailparser": "^3.4.0",
|
|
62
|
+
"smtp-server": "^3.9.0"
|
|
63
|
+
},
|
|
64
|
+
"engines": {
|
|
65
|
+
"node": ">= 16.0.0"
|
|
66
|
+
}
|
|
67
|
+
}
|