@beignet/provider-mail-smtp 0.0.48 → 0.0.50
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/CHANGELOG.md +22 -0
- package/README.md +23 -4
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -12
- package/dist/index.js.map +1 -1
- package/package.json +5 -4
- package/src/index.ts +27 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# @beignet/provider-mail-smtp
|
|
2
2
|
|
|
3
|
+
## 0.0.50
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 4be4573: Keep mail content out of provider instrumentation, document the Redis
|
|
8
|
+
deployment policy required for monotonic fencing, and align generated agent
|
|
9
|
+
guidance with optional seed, worker, and migration paths.
|
|
10
|
+
|
|
11
|
+
## 0.0.49
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- e597d53: Require Node.js 22.12 or newer across every Beignet package, generated app,
|
|
16
|
+
and documented workflow.
|
|
17
|
+
- b2188d8: Align provider production behavior by validating cache TTLs consistently,
|
|
18
|
+
requiring encrypted SMTP transport by default, and streaming unknown-size S3
|
|
19
|
+
uploads through bounded managed multipart uploads with explicit cleanup across
|
|
20
|
+
all failure stages.
|
|
21
|
+
|
|
22
|
+
The S3 provider now requires `@aws-sdk/lib-storage`; the Beignet provider
|
|
23
|
+
preset installs the compatible version automatically.
|
|
24
|
+
|
|
3
25
|
## 0.0.48
|
|
4
26
|
|
|
5
27
|
## 0.0.47
|
package/README.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# @beignet/provider-mail-smtp
|
|
2
2
|
|
|
3
|
+
> **Runtime:** Beignet requires Node.js 22.12 or newer. Bun 1.3.14 or newer is
|
|
4
|
+
> supported for Beignet commands.
|
|
5
|
+
|
|
3
6
|
> [!CAUTION]
|
|
4
7
|
> Beignet is experimental alpha software. The `0.0.x` package line is for early
|
|
5
8
|
> evaluation, and APIs may change between releases while the framework settles.
|
|
@@ -36,7 +39,7 @@ const server = await createServer({
|
|
|
36
39
|
});
|
|
37
40
|
```
|
|
38
41
|
|
|
39
|
-
|
|
42
|
+
Environment variables:
|
|
40
43
|
|
|
41
44
|
| Variable | Description |
|
|
42
45
|
| --- | --- |
|
|
@@ -45,6 +48,10 @@ Required environment variables:
|
|
|
45
48
|
| `MAIL_USER` | SMTP username |
|
|
46
49
|
| `MAIL_PASS` | SMTP password |
|
|
47
50
|
| `MAIL_FROM` | Default sender address |
|
|
51
|
+
| `MAIL_REQUIRE_TLS` | Require encrypted transport. Defaults to `true`. Port `465` uses implicit TLS; other ports must negotiate STARTTLS. |
|
|
52
|
+
|
|
53
|
+
The host, port, credentials, and sender are required. `MAIL_REQUIRE_TLS` is
|
|
54
|
+
optional and defaults to `true`.
|
|
48
55
|
|
|
49
56
|
`beignet doctor --strict` checks that installed SMTP mail providers are
|
|
50
57
|
registered in `server/providers.ts` and that all required `MAIL_*` env vars are
|
|
@@ -63,6 +70,7 @@ export const providers = [
|
|
|
63
70
|
user: secrets.smtpUser,
|
|
64
71
|
pass: secrets.smtpPass,
|
|
65
72
|
from: "My App <no-reply@example.com>",
|
|
73
|
+
requireTls: true,
|
|
66
74
|
}),
|
|
67
75
|
];
|
|
68
76
|
```
|
|
@@ -70,6 +78,12 @@ export const providers = [
|
|
|
70
78
|
Calling `createSmtpMailProvider()` with no options uses the env-backed
|
|
71
79
|
configuration.
|
|
72
80
|
|
|
81
|
+
Encrypted transport is required by default. Port `465` uses implicit TLS;
|
|
82
|
+
other ports must complete STARTTLS negotiation, and provider setup fails when
|
|
83
|
+
the SMTP server cannot do so. Set `requireTls: false` or
|
|
84
|
+
`MAIL_REQUIRE_TLS=false` only for a trusted local capture service that does not
|
|
85
|
+
support TLS.
|
|
86
|
+
|
|
73
87
|
## Use in application code
|
|
74
88
|
|
|
75
89
|
```typescript
|
|
@@ -127,7 +141,9 @@ await ctx.ports.smtp.transporter.sendMail({
|
|
|
127
141
|
|
|
128
142
|
When `ctx.ports.devtools` is installed, this provider records `mail.send`,
|
|
129
143
|
`mail.sent`, and `mail.failed` events under the `mail` watcher. Completed and
|
|
130
|
-
failed events include `durationMs` in their details.
|
|
144
|
+
failed events include `durationMs` in their details. Events retain the provider,
|
|
145
|
+
recipient count, delivery ID when available, and duration, but never include
|
|
146
|
+
addresses, subjects, message bodies, or raw SMTP errors.
|
|
131
147
|
|
|
132
148
|
## Failure and retry semantics
|
|
133
149
|
|
|
@@ -138,7 +154,8 @@ still have been delivered, so a blind provider retry risks duplicate emails.
|
|
|
138
154
|
|
|
139
155
|
Delivery failures throw `MailDeliveryError` from `@beignet/core/mail` with the
|
|
140
156
|
provider name, the recipient count, and the original SMTP error preserved as
|
|
141
|
-
`cause
|
|
157
|
+
`cause` for app-owned handling. The error is not copied into provider
|
|
158
|
+
instrumentation. Redact or restrict access when an application logs the cause.
|
|
142
159
|
|
|
143
160
|
The provider calls `transporter.verify()` during setup, so an unreachable SMTP
|
|
144
161
|
server or rejected credentials fail server startup immediately instead of
|
|
@@ -154,7 +171,9 @@ sending.
|
|
|
154
171
|
|
|
155
172
|
Use a memory or fake `MailerPort` in use-case tests. For local SMTP testing,
|
|
156
173
|
point the provider at a local capture service such as Mailpit or MailHog and
|
|
157
|
-
keep those credentials out of production env files.
|
|
174
|
+
keep those credentials out of production env files. If that service does not
|
|
175
|
+
support STARTTLS, explicitly set `MAIL_REQUIRE_TLS=false` in the local
|
|
176
|
+
environment; never carry the opt-out into preview, staging, or production.
|
|
158
177
|
|
|
159
178
|
## Deployment notes
|
|
160
179
|
|
package/dist/index.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export interface MailConfig {
|
|
|
15
15
|
USER: string;
|
|
16
16
|
PASS: string;
|
|
17
17
|
FROM: string;
|
|
18
|
+
REQUIRE_TLS: boolean;
|
|
18
19
|
}
|
|
19
20
|
/**
|
|
20
21
|
* Escape hatch for apps that need the raw Nodemailer transporter.
|
|
@@ -90,6 +91,15 @@ export interface CreateSmtpMailProviderOptions {
|
|
|
90
91
|
* Default sender address. Overrides `MAIL_FROM`.
|
|
91
92
|
*/
|
|
92
93
|
from?: string;
|
|
94
|
+
/**
|
|
95
|
+
* Require encrypted SMTP transport. Non-465 ports must negotiate STARTTLS;
|
|
96
|
+
* port 465 always uses implicit TLS. Overrides `MAIL_REQUIRE_TLS`.
|
|
97
|
+
*
|
|
98
|
+
* Disable this only for a trusted local SMTP capture service.
|
|
99
|
+
*
|
|
100
|
+
* @default true
|
|
101
|
+
*/
|
|
102
|
+
requireTls?: boolean;
|
|
93
103
|
}
|
|
94
104
|
/**
|
|
95
105
|
* Create an env-backed SMTP mail provider.
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAGL,KAAK,WAAW,EAEhB,KAAK,UAAU,EAIhB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,KAAK,uBAAuB,EAG5B,KAAK,6BAA6B,EAClC,KAAK,eAAe,EACrB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAEV,WAAW,EACZ,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAGL,KAAK,WAAW,EAEhB,KAAK,UAAU,EAIhB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,KAAK,uBAAuB,EAG5B,KAAK,6BAA6B,EAClC,KAAK,eAAe,EACrB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAEV,WAAW,EACZ,MAAM,YAAY,CAAC;AAkBpB;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,OAAO,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,WAAW,EAAE,WAAW,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC;;OAEG;IACH,MAAM,EAAE,UAAU,CAAC;IACnB;;OAEG;IACH,IAAI,EAAE,mBAAmB,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,eAAe,CAC5C,OAAO,EACP,uBAAuB,CAAC,UAAU,CAAC,EACnC,IAAI,CAAC,qBAAqB,EAAE,MAAM,qBAAqB,CAAC,CACzD,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC;;OAEG;IACH,WAAW,EAAE,WAAW,CAAC;IACzB;;OAEG;IACH,IAAI,EAAE,WAAW,CAAC;IAClB;;OAEG;IACH,eAAe,CAAC,EAAE,6BAA6B,CAAC;CACjD;AA0DD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,WAAW,EACX,IAAI,EACJ,eAAe,EAAE,qBAAqB,GACvC,EAAE,uBAAuB,GAAG,UAAU,CAoEtC;AAED;;GAEG;AACH,MAAM,WAAW,6BAA6B;IAC5C;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,GAAE,6BAAkC,GAC1C,gBAAgB,CA6ElB"}
|
package/dist/index.js
CHANGED
|
@@ -7,12 +7,17 @@ import { formatMailAddress, formatMailAddressList, MailDeliveryError, normalizeM
|
|
|
7
7
|
import { createProvider, createProviderInstrumentation, } from "@beignet/core/providers";
|
|
8
8
|
import nodemailer from "nodemailer";
|
|
9
9
|
import { z } from "zod";
|
|
10
|
+
const BooleanConfigValue = z.union([
|
|
11
|
+
z.boolean(),
|
|
12
|
+
z.enum(["true", "false"]).transform((value) => value === "true"),
|
|
13
|
+
]);
|
|
10
14
|
const MailConfigSchema = z.object({
|
|
11
15
|
HOST: z.string(),
|
|
12
16
|
PORT: z.coerce.number().int().positive(),
|
|
13
17
|
USER: z.string(),
|
|
14
18
|
PASS: z.string(),
|
|
15
19
|
FROM: z.string().min(1),
|
|
20
|
+
REQUIRE_TLS: BooleanConfigValue.default(true),
|
|
16
21
|
});
|
|
17
22
|
function addOptional(target, key, value) {
|
|
18
23
|
if (value !== undefined) {
|
|
@@ -63,11 +68,10 @@ export function createSmtpMailer({ transporter, from, instrumentation: instrumen
|
|
|
63
68
|
instrumentation.custom({
|
|
64
69
|
name: "mail.send",
|
|
65
70
|
label: "Mail send",
|
|
66
|
-
summary:
|
|
71
|
+
summary: "Sending mail",
|
|
67
72
|
details: {
|
|
68
73
|
provider: "smtp",
|
|
69
|
-
|
|
70
|
-
to: payload.to,
|
|
74
|
+
recipientCount,
|
|
71
75
|
},
|
|
72
76
|
});
|
|
73
77
|
try {
|
|
@@ -81,11 +85,10 @@ export function createSmtpMailer({ transporter, from, instrumentation: instrumen
|
|
|
81
85
|
instrumentation.custom({
|
|
82
86
|
name: "mail.sent",
|
|
83
87
|
label: "Mail sent",
|
|
84
|
-
summary:
|
|
88
|
+
summary: "Mail sent",
|
|
85
89
|
details: {
|
|
86
90
|
provider: "smtp",
|
|
87
|
-
|
|
88
|
-
to: payload.to,
|
|
91
|
+
recipientCount,
|
|
89
92
|
id,
|
|
90
93
|
durationMs: Date.now() - startedAt,
|
|
91
94
|
},
|
|
@@ -99,12 +102,10 @@ export function createSmtpMailer({ transporter, from, instrumentation: instrumen
|
|
|
99
102
|
instrumentation.custom({
|
|
100
103
|
name: "mail.failed",
|
|
101
104
|
label: "Mail failed",
|
|
102
|
-
summary:
|
|
105
|
+
summary: "Mail delivery failed",
|
|
103
106
|
details: {
|
|
104
107
|
provider: "smtp",
|
|
105
|
-
|
|
106
|
-
to: payload.to,
|
|
107
|
-
error: error instanceof Error ? error.message : String(error),
|
|
108
|
+
recipientCount,
|
|
108
109
|
durationMs: Date.now() - startedAt,
|
|
109
110
|
},
|
|
110
111
|
});
|
|
@@ -135,6 +136,7 @@ export function createSmtpMailProvider(options = {}) {
|
|
|
135
136
|
USER: options.user,
|
|
136
137
|
PASS: options.pass,
|
|
137
138
|
FROM: options.from,
|
|
139
|
+
REQUIRE_TLS: options.requireTls,
|
|
138
140
|
},
|
|
139
141
|
},
|
|
140
142
|
async setup({ config, ports }) {
|
|
@@ -142,11 +144,13 @@ export function createSmtpMailProvider(options = {}) {
|
|
|
142
144
|
throw new Error("[createSmtpMailProvider] Missing Mail config. " +
|
|
143
145
|
"Please set MAIL_HOST, MAIL_PORT, MAIL_USER, MAIL_PASS, and MAIL_FROM environment variables.");
|
|
144
146
|
}
|
|
145
|
-
const { HOST: host, PORT: port, USER: user, PASS: pass, FROM: from, } = config;
|
|
147
|
+
const { HOST: host, PORT: port, USER: user, PASS: pass, FROM: from, REQUIRE_TLS: requireTls = true, } = config;
|
|
148
|
+
const usesImplicitTls = port === 465;
|
|
146
149
|
const transporter = nodemailer.createTransport({
|
|
147
150
|
host,
|
|
148
151
|
port,
|
|
149
|
-
secure:
|
|
152
|
+
secure: usesImplicitTls,
|
|
153
|
+
requireTLS: !usesImplicitTls && requireTls,
|
|
150
154
|
auth: {
|
|
151
155
|
user,
|
|
152
156
|
pass,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EAErB,iBAAiB,EAEjB,oBAAoB,GAGrB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAEL,cAAc,EACd,6BAA6B,GAG9B,MAAM,yBAAyB,CAAC;AAKjC,OAAO,UAAU,MAAM,YAAY,CAAC;AACpC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACxC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@beignet/provider-mail-smtp",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.50",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "SMTP mail provider for Beignet - adds mailer port using nodemailer",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"access": "public"
|
|
53
53
|
},
|
|
54
54
|
"engines": {
|
|
55
|
-
"node": ">=
|
|
55
|
+
"node": ">=22.12.0"
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
58
|
"@beignet/core": ">=0.0.3 <1.0.0",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"@beignet/core": "*",
|
|
66
66
|
"@beignet/devtools": "*",
|
|
67
67
|
"@types/bun": "^1.3.13",
|
|
68
|
-
"@types/node": "^
|
|
68
|
+
"@types/node": "^22.0.0",
|
|
69
69
|
"@types/nodemailer": "^8.0.1",
|
|
70
70
|
"nodemailer": "^9.0.1",
|
|
71
71
|
"typescript": "^5.3.0"
|
|
@@ -88,7 +88,8 @@
|
|
|
88
88
|
"MAIL_PORT",
|
|
89
89
|
"MAIL_USER",
|
|
90
90
|
"MAIL_PASS",
|
|
91
|
-
"MAIL_FROM"
|
|
91
|
+
"MAIL_FROM",
|
|
92
|
+
"MAIL_REQUIRE_TLS"
|
|
92
93
|
],
|
|
93
94
|
"requiredEnv": [
|
|
94
95
|
"MAIL_HOST",
|
package/src/index.ts
CHANGED
|
@@ -28,12 +28,18 @@ import type {
|
|
|
28
28
|
import nodemailer from "nodemailer";
|
|
29
29
|
import { z } from "zod";
|
|
30
30
|
|
|
31
|
+
const BooleanConfigValue = z.union([
|
|
32
|
+
z.boolean(),
|
|
33
|
+
z.enum(["true", "false"]).transform((value) => value === "true"),
|
|
34
|
+
]);
|
|
35
|
+
|
|
31
36
|
const MailConfigSchema = z.object({
|
|
32
37
|
HOST: z.string(),
|
|
33
38
|
PORT: z.coerce.number().int().positive(),
|
|
34
39
|
USER: z.string(),
|
|
35
40
|
PASS: z.string(),
|
|
36
41
|
FROM: z.string().min(1),
|
|
42
|
+
REQUIRE_TLS: BooleanConfigValue.default(true),
|
|
37
43
|
}) satisfies z.ZodType<MailConfig>;
|
|
38
44
|
|
|
39
45
|
/**
|
|
@@ -45,6 +51,7 @@ export interface MailConfig {
|
|
|
45
51
|
USER: string;
|
|
46
52
|
PASS: string;
|
|
47
53
|
FROM: string;
|
|
54
|
+
REQUIRE_TLS: boolean;
|
|
48
55
|
}
|
|
49
56
|
|
|
50
57
|
/**
|
|
@@ -178,11 +185,10 @@ export function createSmtpMailer({
|
|
|
178
185
|
instrumentation.custom({
|
|
179
186
|
name: "mail.send",
|
|
180
187
|
label: "Mail send",
|
|
181
|
-
summary:
|
|
188
|
+
summary: "Sending mail",
|
|
182
189
|
details: {
|
|
183
190
|
provider: "smtp",
|
|
184
|
-
|
|
185
|
-
to: payload.to,
|
|
191
|
+
recipientCount,
|
|
186
192
|
},
|
|
187
193
|
});
|
|
188
194
|
|
|
@@ -199,11 +205,10 @@ export function createSmtpMailer({
|
|
|
199
205
|
instrumentation.custom({
|
|
200
206
|
name: "mail.sent",
|
|
201
207
|
label: "Mail sent",
|
|
202
|
-
summary:
|
|
208
|
+
summary: "Mail sent",
|
|
203
209
|
details: {
|
|
204
210
|
provider: "smtp",
|
|
205
|
-
|
|
206
|
-
to: payload.to,
|
|
211
|
+
recipientCount,
|
|
207
212
|
id,
|
|
208
213
|
durationMs: Date.now() - startedAt,
|
|
209
214
|
},
|
|
@@ -217,12 +222,10 @@ export function createSmtpMailer({
|
|
|
217
222
|
instrumentation.custom({
|
|
218
223
|
name: "mail.failed",
|
|
219
224
|
label: "Mail failed",
|
|
220
|
-
summary:
|
|
225
|
+
summary: "Mail delivery failed",
|
|
221
226
|
details: {
|
|
222
227
|
provider: "smtp",
|
|
223
|
-
|
|
224
|
-
to: payload.to,
|
|
225
|
-
error: error instanceof Error ? error.message : String(error),
|
|
228
|
+
recipientCount,
|
|
226
229
|
durationMs: Date.now() - startedAt,
|
|
227
230
|
},
|
|
228
231
|
});
|
|
@@ -262,6 +265,15 @@ export interface CreateSmtpMailProviderOptions {
|
|
|
262
265
|
* Default sender address. Overrides `MAIL_FROM`.
|
|
263
266
|
*/
|
|
264
267
|
from?: string;
|
|
268
|
+
/**
|
|
269
|
+
* Require encrypted SMTP transport. Non-465 ports must negotiate STARTTLS;
|
|
270
|
+
* port 465 always uses implicit TLS. Overrides `MAIL_REQUIRE_TLS`.
|
|
271
|
+
*
|
|
272
|
+
* Disable this only for a trusted local SMTP capture service.
|
|
273
|
+
*
|
|
274
|
+
* @default true
|
|
275
|
+
*/
|
|
276
|
+
requireTls?: boolean;
|
|
265
277
|
}
|
|
266
278
|
|
|
267
279
|
/**
|
|
@@ -285,6 +297,7 @@ export function createSmtpMailProvider(
|
|
|
285
297
|
USER: options.user,
|
|
286
298
|
PASS: options.pass,
|
|
287
299
|
FROM: options.from,
|
|
300
|
+
REQUIRE_TLS: options.requireTls,
|
|
288
301
|
},
|
|
289
302
|
},
|
|
290
303
|
|
|
@@ -301,12 +314,15 @@ export function createSmtpMailProvider(
|
|
|
301
314
|
USER: user,
|
|
302
315
|
PASS: pass,
|
|
303
316
|
FROM: from,
|
|
317
|
+
REQUIRE_TLS: requireTls = true,
|
|
304
318
|
} = config;
|
|
319
|
+
const usesImplicitTls = port === 465;
|
|
305
320
|
|
|
306
321
|
const transporter = nodemailer.createTransport({
|
|
307
322
|
host,
|
|
308
323
|
port,
|
|
309
|
-
secure:
|
|
324
|
+
secure: usesImplicitTls,
|
|
325
|
+
requireTLS: !usesImplicitTls && requireTls,
|
|
310
326
|
auth: {
|
|
311
327
|
user,
|
|
312
328
|
pass,
|