@nwire/mail-nodemailer 0.9.2 → 0.10.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/dist/mail-nodemailer.d.ts +0 -1
- package/dist/mail-nodemailer.js +0 -1
- package/package.json +3 -3
- package/dist/__tests__/mail-nodemailer.integration.test.d.ts +0 -24
- package/dist/__tests__/mail-nodemailer.integration.test.d.ts.map +0 -1
- package/dist/__tests__/mail-nodemailer.integration.test.js +0 -129
- package/dist/__tests__/mail-nodemailer.integration.test.js.map +0 -1
- package/dist/__tests__/mail-nodemailer.test.d.ts +0 -9
- package/dist/__tests__/mail-nodemailer.test.d.ts.map +0 -1
- package/dist/__tests__/mail-nodemailer.test.js +0 -66
- package/dist/__tests__/mail-nodemailer.test.js.map +0 -1
- package/dist/mail-nodemailer.d.ts.map +0 -1
- package/dist/mail-nodemailer.js.map +0 -1
package/dist/mail-nodemailer.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nwire/mail-nodemailer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.1",
|
|
4
4
|
"description": "Nwire — Nodemailer-backed mail adapter. Implements the Mailer contract via nodemailer's transporter (SMTP/Mailhog/Gmail/Office365/...). Health-checked with transporter.verify(); graceful shutdown closes the pool.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"adapter",
|
|
@@ -30,14 +30,14 @@
|
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"nodemailer": "^6.9.16",
|
|
33
|
-
"@nwire/mail": "0.
|
|
33
|
+
"@nwire/mail": "0.10.1"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/node": "^22.19.9",
|
|
37
37
|
"@types/nodemailer": "^6.4.17",
|
|
38
38
|
"typescript": "^5.9.3",
|
|
39
39
|
"vitest": "^4.1.6",
|
|
40
|
-
"@nwire/test-kit": "0.
|
|
40
|
+
"@nwire/test-kit": "0.10.1"
|
|
41
41
|
},
|
|
42
42
|
"scripts": {
|
|
43
43
|
"build": "tsc && node ../../scripts/fix-dist-extensions.mjs dist",
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Integration test — exercises `@nwire/mail-nodemailer` against real
|
|
3
|
-
* Mailhog. Mailhog accepts SMTP on `1025` and exposes a tiny JSON API
|
|
4
|
-
* on `8025/api/v2/messages` listing every received message — that's
|
|
5
|
-
* what we use to confirm the mail actually arrived as we sent it.
|
|
6
|
-
*
|
|
7
|
-
* Mailhog comes from the workspace docker-compose. When the SMTP port
|
|
8
|
-
* isn't reachable on `127.0.0.1:1025`, the whole suite skips.
|
|
9
|
-
*
|
|
10
|
-
* Why we need real SMTP for these checks:
|
|
11
|
-
*
|
|
12
|
-
* - `transporter.verify()` (our healthCheck) opens a real connection,
|
|
13
|
-
* completes the HELO + EHLO handshake, then closes. Mocks can't
|
|
14
|
-
* prove the wire protocol is wired up correctly.
|
|
15
|
-
* - The mapping from our `MailMessage` shape (mixed string +
|
|
16
|
-
* `{email,name}` recipients, attachments as `Uint8Array`) into
|
|
17
|
-
* RFC-822 headers + MIME parts is where Nodemailer's behavior is
|
|
18
|
-
* most likely to surprise us across upgrades. Asserting against
|
|
19
|
-
* Mailhog's parsed inbox lets us check the receiver's view.
|
|
20
|
-
* - Pool teardown (`shutdown()`) only matters when there's a real
|
|
21
|
-
* connection pool to close.
|
|
22
|
-
*/
|
|
23
|
-
export {};
|
|
24
|
-
//# sourceMappingURL=mail-nodemailer.integration.test.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mail-nodemailer.integration.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/mail-nodemailer.integration.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG"}
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Integration test — exercises `@nwire/mail-nodemailer` against real
|
|
3
|
-
* Mailhog. Mailhog accepts SMTP on `1025` and exposes a tiny JSON API
|
|
4
|
-
* on `8025/api/v2/messages` listing every received message — that's
|
|
5
|
-
* what we use to confirm the mail actually arrived as we sent it.
|
|
6
|
-
*
|
|
7
|
-
* Mailhog comes from the workspace docker-compose. When the SMTP port
|
|
8
|
-
* isn't reachable on `127.0.0.1:1025`, the whole suite skips.
|
|
9
|
-
*
|
|
10
|
-
* Why we need real SMTP for these checks:
|
|
11
|
-
*
|
|
12
|
-
* - `transporter.verify()` (our healthCheck) opens a real connection,
|
|
13
|
-
* completes the HELO + EHLO handshake, then closes. Mocks can't
|
|
14
|
-
* prove the wire protocol is wired up correctly.
|
|
15
|
-
* - The mapping from our `MailMessage` shape (mixed string +
|
|
16
|
-
* `{email,name}` recipients, attachments as `Uint8Array`) into
|
|
17
|
-
* RFC-822 headers + MIME parts is where Nodemailer's behavior is
|
|
18
|
-
* most likely to surprise us across upgrades. Asserting against
|
|
19
|
-
* Mailhog's parsed inbox lets us check the receiver's view.
|
|
20
|
-
* - Pool teardown (`shutdown()`) only matters when there's a real
|
|
21
|
-
* connection pool to close.
|
|
22
|
-
*/
|
|
23
|
-
import { describe, it, expect, beforeAll, afterAll, beforeEach } from "vitest";
|
|
24
|
-
import { isReachable } from "@nwire/test-kit";
|
|
25
|
-
import { smtpMailer } from "../mail-nodemailer.js";
|
|
26
|
-
const MAILHOG_HOST = "127.0.0.1";
|
|
27
|
-
const MAILHOG_SMTP_PORT = 1025;
|
|
28
|
-
const MAILHOG_HTTP_PORT = 8025;
|
|
29
|
-
const MAILHOG_API = `http://${MAILHOG_HOST}:${MAILHOG_HTTP_PORT}/api/v2/messages`;
|
|
30
|
-
const reachable = await isReachable(MAILHOG_HOST, MAILHOG_SMTP_PORT, 800);
|
|
31
|
-
async function purgeInbox() {
|
|
32
|
-
await fetch(`http://${MAILHOG_HOST}:${MAILHOG_HTTP_PORT}/api/v1/messages`, {
|
|
33
|
-
method: "DELETE",
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
async function fetchInbox() {
|
|
37
|
-
const res = await fetch(MAILHOG_API);
|
|
38
|
-
if (!res.ok)
|
|
39
|
-
throw new Error(`Mailhog API ${res.status}`);
|
|
40
|
-
const data = (await res.json());
|
|
41
|
-
return data.items;
|
|
42
|
-
}
|
|
43
|
-
async function waitForCount(n, timeoutMs = 3_000) {
|
|
44
|
-
const deadline = Date.now() + timeoutMs;
|
|
45
|
-
while (Date.now() < deadline) {
|
|
46
|
-
const items = await fetchInbox();
|
|
47
|
-
if (items.length >= n)
|
|
48
|
-
return items;
|
|
49
|
-
await new Promise((r) => setTimeout(r, 25));
|
|
50
|
-
}
|
|
51
|
-
throw new Error(`waitForCount: only ${(await fetchInbox()).length}/${n} after ${timeoutMs}ms`);
|
|
52
|
-
}
|
|
53
|
-
describe.skipIf(!reachable)("mail-nodemailer ↔ real Mailhog", () => {
|
|
54
|
-
let mailer;
|
|
55
|
-
beforeAll(() => {
|
|
56
|
-
mailer = smtpMailer({
|
|
57
|
-
host: MAILHOG_HOST,
|
|
58
|
-
port: MAILHOG_SMTP_PORT,
|
|
59
|
-
// Mailhog has no auth and no TLS in the dev compose.
|
|
60
|
-
pool: true,
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
beforeEach(async () => {
|
|
64
|
-
await purgeInbox();
|
|
65
|
-
});
|
|
66
|
-
afterAll(async () => {
|
|
67
|
-
await mailer.shutdown?.();
|
|
68
|
-
});
|
|
69
|
-
it("healthCheck verifies the SMTP handshake", async () => {
|
|
70
|
-
await expect(mailer.healthCheck()).resolves.toBeUndefined();
|
|
71
|
-
});
|
|
72
|
-
it("sends a plain-text message with the right To/From/Subject headers", async () => {
|
|
73
|
-
const result = await mailer.send({
|
|
74
|
-
from: "noreply@example.com",
|
|
75
|
-
to: "alice@example.com",
|
|
76
|
-
subject: "Phase 77 hello",
|
|
77
|
-
text: "Hello from a real SMTP round-trip.",
|
|
78
|
-
});
|
|
79
|
-
expect(result.messageId).toMatch(/@/); // RFC-822 message-id
|
|
80
|
-
const [msg] = await waitForCount(1);
|
|
81
|
-
expect(msg.Content.Headers.Subject?.[0]).toBe("Phase 77 hello");
|
|
82
|
-
expect(msg.Content.Headers.From?.[0]).toContain("noreply@example.com");
|
|
83
|
-
expect(msg.Content.Headers.To?.[0]).toContain("alice@example.com");
|
|
84
|
-
expect(msg.Content.Body).toContain("Hello from a real SMTP round-trip.");
|
|
85
|
-
});
|
|
86
|
-
it("maps {email,name} recipient objects into RFC-822 display-name form", async () => {
|
|
87
|
-
await mailer.send({
|
|
88
|
-
from: { email: "noreply@example.com", name: "Phase 77" },
|
|
89
|
-
to: { email: "alice@example.com", name: "Alice Example" },
|
|
90
|
-
subject: "Named recipient",
|
|
91
|
-
text: "ok",
|
|
92
|
-
});
|
|
93
|
-
const [msg] = await waitForCount(1);
|
|
94
|
-
// Nodemailer emits `Display Name <addr>` for simple display names; only
|
|
95
|
-
// names with special chars get quoted. Verify both parts arrived.
|
|
96
|
-
const from = msg.Content.Headers.From?.[0] ?? "";
|
|
97
|
-
const to = msg.Content.Headers.To?.[0] ?? "";
|
|
98
|
-
expect(from).toContain("Phase 77");
|
|
99
|
-
expect(from).toContain("<noreply@example.com>");
|
|
100
|
-
expect(to).toContain("Alice Example");
|
|
101
|
-
expect(to).toContain("<alice@example.com>");
|
|
102
|
-
});
|
|
103
|
-
it("multi-recipient arrays produce a comma-separated To header", async () => {
|
|
104
|
-
await mailer.send({
|
|
105
|
-
from: "noreply@example.com",
|
|
106
|
-
to: ["alice@example.com", "bob@example.com"],
|
|
107
|
-
subject: "Group blast",
|
|
108
|
-
text: "ok",
|
|
109
|
-
});
|
|
110
|
-
const [msg] = await waitForCount(1);
|
|
111
|
-
const to = msg.Content.Headers.To?.[0] ?? "";
|
|
112
|
-
expect(to).toMatch(/alice@example\.com/);
|
|
113
|
-
expect(to).toMatch(/bob@example\.com/);
|
|
114
|
-
});
|
|
115
|
-
it("html bodies arrive as a MIME multipart with the expected content type", async () => {
|
|
116
|
-
await mailer.send({
|
|
117
|
-
from: "noreply@example.com",
|
|
118
|
-
to: "alice@example.com",
|
|
119
|
-
subject: "HTML test",
|
|
120
|
-
text: "fallback",
|
|
121
|
-
html: "<p>Hello, <b>real SMTP</b>.</p>",
|
|
122
|
-
});
|
|
123
|
-
const [msg] = await waitForCount(1);
|
|
124
|
-
const ct = msg.Content.Headers["Content-Type"]?.[0] ?? "";
|
|
125
|
-
expect(ct).toMatch(/multipart\/alternative/);
|
|
126
|
-
expect(msg.Content.Body).toContain("<b>real SMTP</b>");
|
|
127
|
-
});
|
|
128
|
-
});
|
|
129
|
-
//# sourceMappingURL=mail-nodemailer.integration.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mail-nodemailer.integration.test.js","sourceRoot":"","sources":["../../src/__tests__/mail-nodemailer.integration.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `@nwire/mail-nodemailer` — adapter unit tests.
|
|
3
|
-
*
|
|
4
|
-
* We don't boot a real SMTP server here; we stub the transporter so the
|
|
5
|
-
* tests run fast without Mailhog. Integration tests against real Mailhog
|
|
6
|
-
* happen via `nwire infra up`.
|
|
7
|
-
*/
|
|
8
|
-
export {};
|
|
9
|
-
//# sourceMappingURL=mail-nodemailer.test.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mail-nodemailer.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/mail-nodemailer.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `@nwire/mail-nodemailer` — adapter unit tests.
|
|
3
|
-
*
|
|
4
|
-
* We don't boot a real SMTP server here; we stub the transporter so the
|
|
5
|
-
* tests run fast without Mailhog. Integration tests against real Mailhog
|
|
6
|
-
* happen via `nwire infra up`.
|
|
7
|
-
*/
|
|
8
|
-
import { describe, it, expect, vi } from "vitest";
|
|
9
|
-
import { smtpMailer } from "../mail-nodemailer.js";
|
|
10
|
-
import { MailSendError } from "@nwire/mail";
|
|
11
|
-
function stubTransporter(overrides = {}) {
|
|
12
|
-
return {
|
|
13
|
-
sendMail: vi.fn(async () => ({ messageId: "<smtp-abc@local>" })),
|
|
14
|
-
verify: vi.fn(async () => true),
|
|
15
|
-
close: vi.fn(() => { }),
|
|
16
|
-
...overrides,
|
|
17
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
describe("smtpMailer", () => {
|
|
21
|
-
it("send maps the canonical MailMessage to Nodemailer's SendMailOptions", async () => {
|
|
22
|
-
const transporter = stubTransporter();
|
|
23
|
-
const mailer = smtpMailer({ host: "x", port: 1025, transporter });
|
|
24
|
-
await mailer.send({
|
|
25
|
-
to: [{ email: "alice@x", name: "Alice" }, "bob@x"],
|
|
26
|
-
from: { email: "noreply@x", name: "My App" },
|
|
27
|
-
subject: "Welcome",
|
|
28
|
-
html: "<p>hi</p>",
|
|
29
|
-
headers: { "X-Trace": "abc" },
|
|
30
|
-
});
|
|
31
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
32
|
-
const call = transporter.sendMail.mock.calls[0][0];
|
|
33
|
-
expect(call.subject).toBe("Welcome");
|
|
34
|
-
expect(call.from).toEqual({ name: "My App", address: "noreply@x" });
|
|
35
|
-
expect(call.to).toEqual([{ name: "Alice", address: "alice@x" }, "bob@x"]);
|
|
36
|
-
expect(call.headers).toEqual({ "X-Trace": "abc" });
|
|
37
|
-
});
|
|
38
|
-
it("send returns a populated MailSendResult", async () => {
|
|
39
|
-
const mailer = smtpMailer({ host: "x", port: 1025, transporter: stubTransporter() });
|
|
40
|
-
const result = await mailer.send({ to: "a", subject: "" });
|
|
41
|
-
expect(result.messageId).toBe("<smtp-abc@local>");
|
|
42
|
-
expect(typeof result.durationMs).toBe("number");
|
|
43
|
-
});
|
|
44
|
-
it("send wraps transporter errors as MailSendError", async () => {
|
|
45
|
-
const transporter = stubTransporter({
|
|
46
|
-
sendMail: vi.fn(async () => {
|
|
47
|
-
throw new Error("conn refused");
|
|
48
|
-
}),
|
|
49
|
-
});
|
|
50
|
-
const mailer = smtpMailer({ host: "x", port: 1025, transporter });
|
|
51
|
-
await expect(mailer.send({ to: "a", subject: "" })).rejects.toBeInstanceOf(MailSendError);
|
|
52
|
-
});
|
|
53
|
-
it("healthCheck calls transporter.verify", async () => {
|
|
54
|
-
const transporter = stubTransporter();
|
|
55
|
-
const mailer = smtpMailer({ host: "x", port: 1025, transporter });
|
|
56
|
-
await mailer.healthCheck();
|
|
57
|
-
expect(transporter.verify).toHaveBeenCalled();
|
|
58
|
-
});
|
|
59
|
-
it("shutdown closes the transporter", async () => {
|
|
60
|
-
const transporter = stubTransporter();
|
|
61
|
-
const mailer = smtpMailer({ host: "x", port: 1025, transporter });
|
|
62
|
-
await mailer.shutdown();
|
|
63
|
-
expect(transporter.close).toHaveBeenCalled();
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
//# sourceMappingURL=mail-nodemailer.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mail-nodemailer.test.js","sourceRoot":"","sources":["../../src/__tests__/mail-nodemailer.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mail-nodemailer.d.ts","sourceRoot":"","sources":["../src/mail-nodemailer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAmB,MAAM,YAAY,CAAC;AAC/D,OAAO,EAEL,KAAK,MAAM,EAIZ,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,+EAA+E;IAC/E,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,IAAI,CAAC,EAAE;QACd,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;KACvB,CAAC;IACF;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC;IACnC;;;OAGG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,4DAA4D;AAC5D,wBAAgB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,CAe7D"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mail-nodemailer.js","sourceRoot":"","sources":["../src/mail-nodemailer.ts"],"names":[],"mappings":"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"}
|