@timshel_npm/maildev 3.1.4 → 3.2.1
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 +2 -2
- package/dist/index.js +0 -1
- package/dist/lib/mailparser.js +1 -1
- package/dist/lib/mailserver.js +16 -27
- package/dist/lib/options.js +6 -2
- package/dist/lib/outgoing.js +7 -8
- package/dist/lib/routes.js +13 -13
- package/dist/lib/web.js +4 -4
- package/package.json +18 -18
package/README.md
CHANGED
|
@@ -30,8 +30,8 @@ Or can be installed using [Github](https://docs.npmjs.com/cli/v10/configuring-np
|
|
|
30
30
|
Ex:
|
|
31
31
|
```json
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"maildev": "github:timshel/maildev#3.1
|
|
34
|
-
"maildev": "npm:@timshel_npm/maildev@^3.1
|
|
33
|
+
"maildev": "github:timshel/maildev#3.2.1",
|
|
34
|
+
"maildev": "npm:@timshel_npm/maildev@^3.2.1"
|
|
35
35
|
}
|
|
36
36
|
```
|
|
37
37
|
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.MailDev = void 0;
|
|
4
4
|
const mailserver_1 = require("./lib/mailserver");
|
|
5
5
|
const web_1 = require("./lib/web");
|
|
6
|
-
const async = require("async");
|
|
7
6
|
const logger = require("./lib/logger");
|
|
8
7
|
class MailDev extends mailserver_1.MailServer {
|
|
9
8
|
constructor(config, mailEventSubjectMapper) {
|
package/dist/lib/mailparser.js
CHANGED
|
@@ -160,7 +160,7 @@ function generateFileNames(fileNames, fileName, contentType) {
|
|
|
160
160
|
let ext;
|
|
161
161
|
let defaultExt = "";
|
|
162
162
|
if (contentType) {
|
|
163
|
-
const ext = mime.
|
|
163
|
+
const ext = mime.getExtension(contentType);
|
|
164
164
|
defaultExt = ext ? "." + ext : "";
|
|
165
165
|
}
|
|
166
166
|
fileName = fileName || "attachment" + defaultExt;
|
package/dist/lib/mailserver.js
CHANGED
|
@@ -226,7 +226,7 @@ class MailServer {
|
|
|
226
226
|
return elt.id === id;
|
|
227
227
|
});
|
|
228
228
|
if (envelope) {
|
|
229
|
-
return getDiskEmail(this.mailDir, envelope.id
|
|
229
|
+
return getDiskEmail(this.mailDir, envelope.id).then((mail) => {
|
|
230
230
|
if (mail.html) {
|
|
231
231
|
// sanitize html
|
|
232
232
|
const window = new JSDOM("").window;
|
|
@@ -390,7 +390,7 @@ class MailServer {
|
|
|
390
390
|
const saved = files.map(function (file) {
|
|
391
391
|
return __awaiter(this, void 0, void 0, function* () {
|
|
392
392
|
const id = path.parse(file).name;
|
|
393
|
-
const email = yield getDiskEmail(self.mailDir, id
|
|
393
|
+
const email = yield getDiskEmail(self.mailDir, id);
|
|
394
394
|
return saveEmailToStore(self, email);
|
|
395
395
|
});
|
|
396
396
|
});
|
|
@@ -417,29 +417,27 @@ function createMailDir(mailDir) {
|
|
|
417
417
|
fs.mkdirSync(mailDir, { recursive: true });
|
|
418
418
|
logger.info("MailDev using directory %s", mailDir);
|
|
419
419
|
}
|
|
420
|
-
function getDiskEmail(mailDir, id
|
|
420
|
+
function getDiskEmail(mailDir, id) {
|
|
421
421
|
return __awaiter(this, void 0, void 0, function* () {
|
|
422
422
|
const emlPath = path.join(mailDir, id + ".eml");
|
|
423
423
|
const data = yield fs_1.promises.readFile(emlPath, "utf8");
|
|
424
424
|
const parsedMail = yield (0, mailparser_1.parse)(data);
|
|
425
|
-
|
|
426
|
-
envelope = {
|
|
427
|
-
id: id,
|
|
428
|
-
from: parsedMail.from,
|
|
429
|
-
to: parsedMail.to,
|
|
430
|
-
date: parsedMail.date,
|
|
431
|
-
subject: parsedMail.subject,
|
|
432
|
-
hasAttachment: parsedMail.attachments.length > 0,
|
|
433
|
-
isRead: false,
|
|
434
|
-
};
|
|
435
|
-
}
|
|
436
|
-
return buildMail(mailDir, envelope, parsedMail);
|
|
425
|
+
return buildMail(mailDir, id, parsedMail);
|
|
437
426
|
});
|
|
438
427
|
}
|
|
439
|
-
function buildMail(mailDir,
|
|
428
|
+
function buildMail(mailDir, id, parsedMail) {
|
|
440
429
|
return __awaiter(this, void 0, void 0, function* () {
|
|
441
|
-
const emlPath = path.join(mailDir,
|
|
430
|
+
const emlPath = path.join(mailDir, id + ".eml");
|
|
442
431
|
const stat = yield fs_1.promises.stat(emlPath);
|
|
432
|
+
const envelope = {
|
|
433
|
+
id: id,
|
|
434
|
+
from: parsedMail.from,
|
|
435
|
+
to: parsedMail.to,
|
|
436
|
+
date: parsedMail.date,
|
|
437
|
+
subject: parsedMail.subject,
|
|
438
|
+
hasAttachment: parsedMail.attachments.length > 0,
|
|
439
|
+
isRead: false,
|
|
440
|
+
};
|
|
443
441
|
return Object.assign({ id: envelope.id, envelope, calculatedBcc: (0, bcc_1.calculateBcc)(envelope.to, parsedMail.to, parsedMail.cc), size: stat.size, sizeHuman: utils.formatBytes(stat.size) }, parsedMail);
|
|
444
442
|
});
|
|
445
443
|
}
|
|
@@ -482,16 +480,7 @@ function handleDataStream(mailServer, stream, session, callback) {
|
|
|
482
480
|
});
|
|
483
481
|
stream.pipe(emlStream);
|
|
484
482
|
const parsed = yield (0, mailparser_1.parse)(stream);
|
|
485
|
-
const
|
|
486
|
-
id: id,
|
|
487
|
-
from: session.envelope.mailFrom,
|
|
488
|
-
to: session.envelope.rcptTo,
|
|
489
|
-
date: parsed.date,
|
|
490
|
-
subject: parsed.subject,
|
|
491
|
-
hasAttachment: parsed.attachments.length > 0,
|
|
492
|
-
isRead: false,
|
|
493
|
-
};
|
|
494
|
-
const mail = yield buildMail(mailServer.mailDir, envelope, parsed);
|
|
483
|
+
const mail = yield buildMail(mailServer.mailDir, id, parsed);
|
|
495
484
|
return saveEmailToStore(mailServer, mail);
|
|
496
485
|
});
|
|
497
486
|
}
|
package/dist/lib/options.js
CHANGED
|
@@ -58,7 +58,11 @@ const options = [
|
|
|
58
58
|
],
|
|
59
59
|
["--web-user <user>", "MAILDEV_WEB_USER", "HTTP user for GUI"],
|
|
60
60
|
["--web-pass <password>", "MAILDEV_WEB_PASS", "HTTP password for GUI"],
|
|
61
|
-
[
|
|
61
|
+
[
|
|
62
|
+
"--web-domain <path>",
|
|
63
|
+
"MAILDEV_WEB_DOMAIN",
|
|
64
|
+
'External domain name (used for socket CORS, "*" otherwise)',
|
|
65
|
+
],
|
|
62
66
|
["--base-pathname <path>", "MAILDEV_BASE_PATHNAME", "Base path for URLs"],
|
|
63
67
|
["--https", "MAILDEV_HTTPS", "Switch from http to https protocol", false],
|
|
64
68
|
["--https-key <file>", "MAILDEV_HTTPS_KEY", "The file path to the ssl private key"],
|
|
@@ -135,7 +139,7 @@ function cliOptions() {
|
|
|
135
139
|
hide8BITMIME: ((_a = config === null || config === void 0 ? void 0 : config.hideExtensions) !== null && _a !== void 0 ? _a : []).includes("8BITMIME"),
|
|
136
140
|
hidePIPELINING: ((_b = config === null || config === void 0 ? void 0 : config.hideExtensions) !== null && _b !== void 0 ? _b : []).includes("PIPELINING"),
|
|
137
141
|
hideSMTPUTF8: ((_c = config === null || config === void 0 ? void 0 : config.hideExtensions) !== null && _c !== void 0 ? _c : []).includes("SMTPUTF8"),
|
|
138
|
-
outgoing: (config === null || config === void 0 ? void 0 : config.autoRelay) || (config === null || config === void 0 ? void 0 : config.autoRelayRules)
|
|
142
|
+
outgoing: (config === null || config === void 0 ? void 0 : config.autoRelay) || (config === null || config === void 0 ? void 0 : config.autoRelayRules) || (config === null || config === void 0 ? void 0 : config.outgoingHost)
|
|
139
143
|
? {
|
|
140
144
|
host: config === null || config === void 0 ? void 0 : config.outgoingHost,
|
|
141
145
|
port: config === null || config === void 0 ? void 0 : config.outgoingPort,
|
package/dist/lib/outgoing.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Outgoing = void 0;
|
|
4
|
-
/**
|
|
5
|
-
* MailDev - outgoing
|
|
6
|
-
*/
|
|
7
4
|
const SMTPConnection = require("nodemailer/lib/smtp-connection");
|
|
8
5
|
const async = require("async");
|
|
9
6
|
const fs = require("fs");
|
|
@@ -98,17 +95,19 @@ function createClient(outgoing) {
|
|
|
98
95
|
}
|
|
99
96
|
function relayMail(outgoing, emailObject, emailStream, isAutoRelay, done) {
|
|
100
97
|
if (isAutoRelay && outgoing.autoRelayAddress) {
|
|
101
|
-
emailObject.to = [{ address: outgoing.autoRelayAddress }];
|
|
102
|
-
emailObject.envelope.to = [{ address: outgoing.autoRelayAddress,
|
|
98
|
+
emailObject.to = [{ address: outgoing.autoRelayAddress, name: "Auto-Relay" }];
|
|
99
|
+
emailObject.envelope.to = [{ address: outgoing.autoRelayAddress, name: "Auto-Relay" }];
|
|
103
100
|
}
|
|
104
101
|
let recipients = emailObject.envelope.to.map(getAddressFromAddressObject);
|
|
105
102
|
if (isAutoRelay && outgoing.autoRelayRules) {
|
|
106
103
|
recipients = getAutoRelayableRecipients(recipients, outgoing.autoRelayRules);
|
|
107
104
|
}
|
|
108
|
-
// Fail silently with auth relay mode on
|
|
109
105
|
if (recipients.length === 0) {
|
|
110
106
|
return done("Email had no recipients");
|
|
111
107
|
}
|
|
108
|
+
if (emailObject.envelope.from.length === 0) {
|
|
109
|
+
return done("Email had no sender");
|
|
110
|
+
}
|
|
112
111
|
const mailSendCallback = function (err) {
|
|
113
112
|
if (err) {
|
|
114
113
|
logger.error("Outgoing client login error: ", err);
|
|
@@ -116,13 +115,13 @@ function relayMail(outgoing, emailObject, emailStream, isAutoRelay, done) {
|
|
|
116
115
|
}
|
|
117
116
|
const sender = getAddressFromAddressObject(emailObject.envelope.from);
|
|
118
117
|
outgoing.client.send({
|
|
119
|
-
from:
|
|
118
|
+
from: emailObject.envelope.from[0].address,
|
|
120
119
|
to: recipients,
|
|
121
120
|
}, emailStream, function (err) {
|
|
122
121
|
outgoing.client.quit();
|
|
123
122
|
createClient(outgoing);
|
|
124
123
|
if (err) {
|
|
125
|
-
logger.error("Mail Delivery Error: ", err);
|
|
124
|
+
logger.error("Mail Delivery Error: ", err, { sender, recipients });
|
|
126
125
|
return done(err);
|
|
127
126
|
}
|
|
128
127
|
logger.log("Mail Delivered: ", emailObject.subject);
|
package/dist/lib/routes.js
CHANGED
|
@@ -13,13 +13,13 @@ function routes(app, mailserver, basePathname) {
|
|
|
13
13
|
const router = express.Router();
|
|
14
14
|
// Get all emails Enveloppe
|
|
15
15
|
router.get("/envelope", compression(), function (req, res) {
|
|
16
|
-
res.json(mailserver.getAllEnvelope());
|
|
16
|
+
res.status(200).json(mailserver.getAllEnvelope());
|
|
17
17
|
});
|
|
18
18
|
// Get all emails
|
|
19
19
|
router.get("/email", compression(), function (req, res) {
|
|
20
20
|
mailserver
|
|
21
21
|
.getAllEmail()
|
|
22
|
-
.then((mails) => res.json(req.query ? filterEmails(mails, req.query) : mails))
|
|
22
|
+
.then((mails) => res.status(200).json(req.query ? filterEmails(mails, req.query) : mails))
|
|
23
23
|
.catch((err) => res.status(500).json({ error: err.message }));
|
|
24
24
|
});
|
|
25
25
|
// Get single email
|
|
@@ -28,7 +28,7 @@ function routes(app, mailserver, basePathname) {
|
|
|
28
28
|
.getEmail(req.params.id)
|
|
29
29
|
.then((mail) => {
|
|
30
30
|
mail.envelope.isRead = true; // Mark the email as 'read'
|
|
31
|
-
res.json(mail);
|
|
31
|
+
res.status(200).json(mail);
|
|
32
32
|
})
|
|
33
33
|
.catch((err) => res.status(404).json({ error: err.message }));
|
|
34
34
|
});
|
|
@@ -42,20 +42,20 @@ function routes(app, mailserver, basePathname) {
|
|
|
42
42
|
// Read all emails
|
|
43
43
|
router.patch("/email/read-all", function (req, res) {
|
|
44
44
|
const count = mailserver.readAllEmail();
|
|
45
|
-
res.json(count);
|
|
45
|
+
res.status(200).json(count);
|
|
46
46
|
});
|
|
47
47
|
// Delete all emails
|
|
48
48
|
router.delete("/email/all", function (req, res) {
|
|
49
49
|
mailserver
|
|
50
50
|
.deleteAllEmail()
|
|
51
|
-
.then((count) => res.json(count))
|
|
51
|
+
.then((count) => res.status(200).json(count))
|
|
52
52
|
.catch((err) => res.status(500).json({ error: err.message }));
|
|
53
53
|
});
|
|
54
54
|
// Delete email by id
|
|
55
55
|
router.delete("/email/:id", function (req, res) {
|
|
56
56
|
mailserver
|
|
57
57
|
.deleteEmail(req.params.id)
|
|
58
|
-
.then((deleted) => res.json(deleted))
|
|
58
|
+
.then((deleted) => res.status(200).json(deleted))
|
|
59
59
|
.catch((err) => res.status(500).json({ error: err.message }));
|
|
60
60
|
});
|
|
61
61
|
// Get Email HTML
|
|
@@ -64,7 +64,7 @@ function routes(app, mailserver, basePathname) {
|
|
|
64
64
|
const baseUrl = req.headers.host + (req.baseUrl || "");
|
|
65
65
|
mailserver
|
|
66
66
|
.getEmailHTML(req.params.id, baseUrl)
|
|
67
|
-
.then((html) => res.send(html))
|
|
67
|
+
.then((html) => res.status(200).send(html))
|
|
68
68
|
.catch((err) => res.status(404).json({ error: err.message }));
|
|
69
69
|
});
|
|
70
70
|
// Serve Attachments
|
|
@@ -73,7 +73,7 @@ function routes(app, mailserver, basePathname) {
|
|
|
73
73
|
.getEmailAttachment(req.params.id, req.params.filename)
|
|
74
74
|
.then((attachement) => {
|
|
75
75
|
res.contentType(attachement.contentType);
|
|
76
|
-
res.send(attachement.content);
|
|
76
|
+
res.status(200).send(attachement.content);
|
|
77
77
|
})
|
|
78
78
|
.catch((err) => res.status(404).json({ error: err.message }));
|
|
79
79
|
});
|
|
@@ -97,7 +97,7 @@ function routes(app, mailserver, basePathname) {
|
|
|
97
97
|
});
|
|
98
98
|
// Get any config settings for display
|
|
99
99
|
router.get("/config", function (req, res) {
|
|
100
|
-
res.json({
|
|
100
|
+
res.status(200).json({
|
|
101
101
|
version: pkg.version,
|
|
102
102
|
smtpPort: mailserver.port,
|
|
103
103
|
isOutgoingEnabled: mailserver.isOutgoingEnabled(),
|
|
@@ -105,7 +105,7 @@ function routes(app, mailserver, basePathname) {
|
|
|
105
105
|
});
|
|
106
106
|
});
|
|
107
107
|
// Relay the email
|
|
108
|
-
router.post("/email/:id/relay/:relayTo
|
|
108
|
+
router.post("/email/:id/relay{/:relayTo}", function (req, res) {
|
|
109
109
|
mailserver
|
|
110
110
|
.getEmail(req.params.id)
|
|
111
111
|
.then((mail) => {
|
|
@@ -122,18 +122,18 @@ function routes(app, mailserver, basePathname) {
|
|
|
122
122
|
}
|
|
123
123
|
return mailserver
|
|
124
124
|
.relayMail(mail, false)
|
|
125
|
-
.then(() => res.json(true))
|
|
125
|
+
.then(() => res.status(200).json(true))
|
|
126
126
|
.catch((err) => res.status(500).json({ error: err.message }));
|
|
127
127
|
})
|
|
128
128
|
.catch((err) => res.status(404).json({ error: err.message }));
|
|
129
129
|
});
|
|
130
130
|
// Health check
|
|
131
131
|
router.get("/healthz", function (req, res) {
|
|
132
|
-
res.json(true);
|
|
132
|
+
res.status(200).json(true);
|
|
133
133
|
});
|
|
134
134
|
router.get("/reloadMailsFromDirectory", function (req, res) {
|
|
135
135
|
mailserver.loadMailsFromDirectory();
|
|
136
|
-
res.json(true);
|
|
136
|
+
res.status(200).json(true);
|
|
137
137
|
});
|
|
138
138
|
app.use(basePathname, router);
|
|
139
139
|
}
|
package/dist/lib/web.js
CHANGED
|
@@ -33,11 +33,11 @@ class Web {
|
|
|
33
33
|
app.use(auth((_d = options === null || options === void 0 ? void 0 : options.auth) === null || _d === void 0 ? void 0 : _d.user, (_e = options === null || options === void 0 ? void 0 : options.auth) === null || _e === void 0 ? void 0 : _e.pass));
|
|
34
34
|
}
|
|
35
35
|
this.io = socketio({
|
|
36
|
-
path: path.posix.join(this.basePathname,
|
|
36
|
+
path: path.posix.join(this.basePathname, "/socket.io"),
|
|
37
37
|
cors: {
|
|
38
|
-
origin: (_f = options === null || options === void 0 ? void 0 : options.domain) !== null && _f !== void 0 ? _f :
|
|
39
|
-
methods: ["GET", "POST"]
|
|
40
|
-
}
|
|
38
|
+
origin: (_f = options === null || options === void 0 ? void 0 : options.domain) !== null && _f !== void 0 ? _f : "*",
|
|
39
|
+
methods: ["GET", "POST"],
|
|
40
|
+
},
|
|
41
41
|
});
|
|
42
42
|
app.use(this.basePathname, express.static(path.join(__dirname, "../app")));
|
|
43
43
|
app.use(cors());
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@timshel_npm/maildev",
|
|
3
3
|
"description": "SMTP Server with async API and Web Interface for viewing and testing emails during development",
|
|
4
|
-
"version": "3.1
|
|
4
|
+
"version": "3.2.1",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"email",
|
|
7
7
|
"e-mail",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"playwright"
|
|
16
16
|
],
|
|
17
17
|
"author": "Timshel",
|
|
18
|
-
"homepage": "https://github.com/
|
|
18
|
+
"homepage": "https://github.com/Timshel/maildev",
|
|
19
19
|
"maintainers": [
|
|
20
20
|
{
|
|
21
21
|
"name": "Timshel",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
],
|
|
25
25
|
"repository": {
|
|
26
26
|
"type": "git",
|
|
27
|
-
"url": "https://github.com/
|
|
27
|
+
"url": "https://github.com/Timshel/maildev"
|
|
28
28
|
},
|
|
29
29
|
"scripts": {
|
|
30
30
|
"clean": "rm -rf dist coverage tsconfig.tsbuildinfo",
|
|
@@ -58,16 +58,16 @@
|
|
|
58
58
|
"@types/mailparser": "^3.4.6",
|
|
59
59
|
"addressparser": "1.0.1",
|
|
60
60
|
"async": "^3.2.6",
|
|
61
|
-
"commander": "^
|
|
62
|
-
"compression": "^1.8.
|
|
61
|
+
"commander": "^13.1.0",
|
|
62
|
+
"compression": "^1.8.1",
|
|
63
63
|
"cors": "^2.8.5",
|
|
64
64
|
"dompurify": "^3.2.6",
|
|
65
|
-
"express": "^
|
|
66
|
-
"jsdom": "^
|
|
67
|
-
"mailparser": "^3.7.
|
|
68
|
-
"mime": "
|
|
69
|
-
"nodemailer": "^
|
|
70
|
-
"smtp-server": "^3.
|
|
65
|
+
"express": "^5.1.0",
|
|
66
|
+
"jsdom": "^26.1.0",
|
|
67
|
+
"mailparser": "^3.7.4",
|
|
68
|
+
"mime": "^3.0.0",
|
|
69
|
+
"nodemailer": "^7.0.5",
|
|
70
|
+
"smtp-server": "^3.14.0",
|
|
71
71
|
"socket.io": "^4.8.1",
|
|
72
72
|
"wildstring": "1.0.9"
|
|
73
73
|
},
|
|
@@ -76,19 +76,19 @@
|
|
|
76
76
|
},
|
|
77
77
|
"devDependencies": {
|
|
78
78
|
"@types/express": "^4.17.23",
|
|
79
|
-
"@types/node": "^18.19.
|
|
80
|
-
"expect": "^
|
|
79
|
+
"@types/node": "^18.19.122",
|
|
80
|
+
"expect": "^30.0.3",
|
|
81
81
|
"http-proxy-middleware": "^3.0.5",
|
|
82
|
-
"jest": "^
|
|
83
|
-
"jest-mock": "^
|
|
84
|
-
"mocha": "^
|
|
82
|
+
"jest": "^30.0.5",
|
|
83
|
+
"jest-mock": "^30.0.2",
|
|
84
|
+
"mocha": "^11.7.1",
|
|
85
85
|
"nodemon": "^3.1.10",
|
|
86
86
|
"nyc": "^17.1.0",
|
|
87
87
|
"prettier": "^3.6.2",
|
|
88
|
-
"sass": "^1.
|
|
88
|
+
"sass": "^1.90.0",
|
|
89
89
|
"ts-node": "^10.9.2",
|
|
90
90
|
"ts-node-dev": "^2.0.0",
|
|
91
|
-
"typescript": "^5.
|
|
91
|
+
"typescript": "^5.9.2"
|
|
92
92
|
},
|
|
93
93
|
"engines": {
|
|
94
94
|
"node": ">=18.0.0"
|