@spinajs/email-smtp-transport 2.0.480 → 2.0.482
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/lib/cjs/index.d.ts +12 -1
- package/lib/cjs/index.d.ts.map +1 -1
- package/lib/cjs/index.js +52 -16
- package/lib/cjs/index.js.map +1 -1
- package/lib/mjs/index.d.ts +12 -1
- package/lib/mjs/index.d.ts.map +1 -1
- package/lib/mjs/index.js +53 -17
- package/lib/mjs/index.js.map +1 -1
- package/lib/tsconfig.cjs.tsbuildinfo +1 -1
- package/lib/tsconfig.mjs.tsbuildinfo +1 -1
- package/package.json +16 -17
package/lib/cjs/index.d.ts
CHANGED
|
@@ -1,14 +1,25 @@
|
|
|
1
1
|
import { Log } from '@spinajs/log';
|
|
2
2
|
import { IEmail, EmailSender, EmailConnectionOptions } from '@spinajs/email';
|
|
3
3
|
import { Templates } from '@spinajs/templates';
|
|
4
|
+
import { ResiliencePipeline } from '@spinajs/util';
|
|
4
5
|
import * as nodemailer from 'nodemailer';
|
|
5
6
|
export declare class EmailSenderSmtp extends EmailSender {
|
|
6
7
|
Options: EmailConnectionOptions;
|
|
7
8
|
protected Log: Log;
|
|
8
|
-
protected
|
|
9
|
+
protected Templates: Templates;
|
|
9
10
|
protected DefaultFileProvider: string;
|
|
10
11
|
protected Transporter: nodemailer.Transporter;
|
|
12
|
+
/**
|
|
13
|
+
* In-process resilience pipeline guarding the SMTP send ( per-attempt timeout + retry ).
|
|
14
|
+
*/
|
|
15
|
+
protected SendPipeline: ResiliencePipeline<nodemailer.SentMessageInfo>;
|
|
11
16
|
constructor(Options: EmailConnectionOptions);
|
|
17
|
+
/**
|
|
18
|
+
* Builds the in-process resilience pipeline guarding the SMTP send
|
|
19
|
+
* ( per-attempt timeout + exponential retry ). Extracted so the send
|
|
20
|
+
* behavior can be tested hermetically without opening a real connection.
|
|
21
|
+
*/
|
|
22
|
+
protected buildSendPipeline(): ResiliencePipeline<nodemailer.SentMessageInfo>;
|
|
12
23
|
resolve(): Promise<void>;
|
|
13
24
|
send(email: IEmail): Promise<void>;
|
|
14
25
|
}
|
package/lib/cjs/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,GAAG,EAAU,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,sBAAsB,EAAqB,MAAM,gBAAgB,CAAC;AAChG,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,KAAK,UAAU,MAAM,YAAY,CAAC;AAKzC,qBAEa,eAAgB,SAAQ,WAAW;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,GAAG,EAAU,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,sBAAsB,EAAqB,MAAM,gBAAgB,CAAC;AAChG,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAe,kBAAkB,EAA6B,MAAM,eAAe,CAAC;AAC3F,OAAO,KAAK,UAAU,MAAM,YAAY,CAAC;AAKzC,qBAEa,eAAgB,SAAQ,WAAW;IAiB3B,OAAO,EAAE,sBAAsB;IAflD,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC;IAGnB,SAAS,CAAC,SAAS,EAAE,SAAS,CAAC;IAG/B,SAAS,CAAC,mBAAmB,EAAE,MAAM,CAAC;IAEtC,SAAS,CAAC,WAAW,EAAE,UAAU,CAAC,WAAW,CAAC;IAE9C;;OAEG;IACH,SAAS,CAAC,YAAY,EAAE,kBAAkB,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;gBAEpD,OAAO,EAAE,sBAAsB;IAIlD;;;;OAIG;IACH,SAAS,CAAC,iBAAiB,IAAI,kBAAkB,CAAC,UAAU,CAAC,eAAe,CAAC;IAOhE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAwCxB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAmFhD"}
|
package/lib/cjs/index.js
CHANGED
|
@@ -51,6 +51,7 @@ const di_1 = require("@spinajs/di");
|
|
|
51
51
|
const log_1 = require("@spinajs/log");
|
|
52
52
|
const email_1 = require("@spinajs/email");
|
|
53
53
|
const templates_1 = require("@spinajs/templates");
|
|
54
|
+
const util_1 = require("@spinajs/util");
|
|
54
55
|
const nodemailer = __importStar(require("nodemailer"));
|
|
55
56
|
const lodash_1 = __importDefault(require("lodash"));
|
|
56
57
|
const configuration_1 = require("@spinajs/configuration");
|
|
@@ -59,6 +60,17 @@ let EmailSenderSmtp = class EmailSenderSmtp extends email_1.EmailSender {
|
|
|
59
60
|
super();
|
|
60
61
|
this.Options = Options;
|
|
61
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Builds the in-process resilience pipeline guarding the SMTP send
|
|
65
|
+
* ( per-attempt timeout + exponential retry ). Extracted so the send
|
|
66
|
+
* behavior can be tested hermetically without opening a real connection.
|
|
67
|
+
*/
|
|
68
|
+
buildSendPipeline() {
|
|
69
|
+
return new util_1.ResiliencePipelineBuilder()
|
|
70
|
+
.addTimeout(this.Options.resilience?.timeout ?? 30_000)
|
|
71
|
+
.addRetry({ MaxRetryAttempts: this.Options.resilience?.retries ?? 2, Delay: this.Options.resilience?.delay ?? 500, BackoffType: util_1.BackoffType.Exponential, UseJitter: true })
|
|
72
|
+
.build();
|
|
73
|
+
}
|
|
62
74
|
async resolve() {
|
|
63
75
|
await super.resolve();
|
|
64
76
|
const options = Object.assign({
|
|
@@ -67,7 +79,7 @@ let EmailSenderSmtp = class EmailSenderSmtp extends email_1.EmailSender {
|
|
|
67
79
|
secure: this.Options.ssl, // true for 465, false for other ports
|
|
68
80
|
auth: {
|
|
69
81
|
user: this.Options.user, // generated ethereal user
|
|
70
|
-
pass: this.Options.
|
|
82
|
+
pass: this.Options.password, // generated ethereal password
|
|
71
83
|
},
|
|
72
84
|
},
|
|
73
85
|
// all additional options merged
|
|
@@ -75,13 +87,17 @@ let EmailSenderSmtp = class EmailSenderSmtp extends email_1.EmailSender {
|
|
|
75
87
|
this.Log.info(`Creating connection to smtp: ${options.auth.user}@${options.host}:${options.port}, secure: ${options.secure}`);
|
|
76
88
|
// create reusable transporter object using the default SMTP transport
|
|
77
89
|
this.Transporter = nodemailer.createTransport(options);
|
|
90
|
+
// in-process resilience applied only around the SMTP send. Queue-level retry
|
|
91
|
+
// handles deferred sends once this pipeline gives up.
|
|
92
|
+
this.SendPipeline = this.buildSendPipeline();
|
|
78
93
|
try {
|
|
79
94
|
// verify returns Promise<true> so always is true
|
|
80
95
|
// we must catch exception
|
|
81
96
|
await this.Transporter.verify();
|
|
82
97
|
}
|
|
83
98
|
catch (err) {
|
|
84
|
-
|
|
99
|
+
this.Log.error(err, `Cannot verify smtp connection ${this.Options.name} (${this.Options.host}:${this.Options.port})`);
|
|
100
|
+
throw new exceptions_1.UnexpectedServerError(`Cannot verify smtp connection ${this.Options.name} (${this.Options.host}:${this.Options.port})`, err);
|
|
85
101
|
}
|
|
86
102
|
this.Log.success(`Email smtp connection ${this.Options.name} on host ${this.Options.host} established !`);
|
|
87
103
|
}
|
|
@@ -89,19 +105,31 @@ let EmailSenderSmtp = class EmailSenderSmtp extends email_1.EmailSender {
|
|
|
89
105
|
if (!email.from && !this.Options.defaults?.mailFrom) {
|
|
90
106
|
throw new exceptions_1.IOFail(`Email from address is required. Please provide it in email or in configuration`);
|
|
91
107
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
108
|
+
// only resolve / download / render a template when one is actually provided.
|
|
109
|
+
// text-only emails leave html undefined.
|
|
110
|
+
let html;
|
|
111
|
+
if (email.template) {
|
|
112
|
+
// string template -> default template filesystem
|
|
113
|
+
// IEmailTemplate object -> resolve its own fs provider
|
|
114
|
+
let templateFs = this.defaultTemplateFs;
|
|
115
|
+
if (!lodash_1.default.isString(email.template)) {
|
|
116
|
+
templateFs = await di_1.DI.resolve('__file_provider__', [email.template.fs]);
|
|
117
|
+
if (!templateFs) {
|
|
118
|
+
throw new exceptions_1.IOFail(`Filesystem provider for ${email.template.fs} not registered. Make sure you importer all required fs providers`);
|
|
119
|
+
}
|
|
96
120
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
121
|
+
this.Log.trace(`Using filesystem ${templateFs.Name} to resolve email template`);
|
|
122
|
+
const tfile = await (lodash_1.default.isString(email.template) ? templateFs.download(email.template) : templateFs.download(email.template.file));
|
|
123
|
+
this.Log.trace(`Resolved email template ${tfile}`);
|
|
124
|
+
try {
|
|
125
|
+
html = await this.Templates.render(tfile, { ...email.model, ...this.Options.templates?.defaults }, email.lang);
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
// template rendering is a deterministic failure - log & rethrow the original error, do not retry
|
|
129
|
+
this.Log.error(err, `Cannot render email template ${tfile} for connection ${this.Options.name}`);
|
|
130
|
+
throw err;
|
|
100
131
|
}
|
|
101
132
|
}
|
|
102
|
-
this.Log.trace(`Using filesystem ${fs.Name} to resolve email template`);
|
|
103
|
-
const tfile = await (lodash_1.default.isString(email.template) ? fs.download(email.template) : fs.download(email.template.file));
|
|
104
|
-
this.Log.trace(`Resolved email template ${tfile}`);
|
|
105
133
|
const options = {
|
|
106
134
|
from: email.from ?? this.Options.defaults?.mailFrom, // sender address
|
|
107
135
|
to: email.to.join(','), // list of receivers
|
|
@@ -110,7 +138,7 @@ let EmailSenderSmtp = class EmailSenderSmtp extends email_1.EmailSender {
|
|
|
110
138
|
replyTo: email.replyTo,
|
|
111
139
|
subject: email.subject, // Subject line
|
|
112
140
|
text: email.text, // plain text body
|
|
113
|
-
html
|
|
141
|
+
html, // rendered template or undefined for text-only emails
|
|
114
142
|
attachments: [],
|
|
115
143
|
};
|
|
116
144
|
if (email.attachements) {
|
|
@@ -134,8 +162,16 @@ let EmailSenderSmtp = class EmailSenderSmtp extends email_1.EmailSender {
|
|
|
134
162
|
};
|
|
135
163
|
}));
|
|
136
164
|
}
|
|
137
|
-
let message
|
|
138
|
-
|
|
165
|
+
let message;
|
|
166
|
+
try {
|
|
167
|
+
// guard only the SMTP send with the resilience pipeline ( timeout + retry )
|
|
168
|
+
message = await this.SendPipeline.execute(() => this.Transporter.sendMail(options));
|
|
169
|
+
}
|
|
170
|
+
catch (err) {
|
|
171
|
+
this.Log.error(err, `Cannot send email for connection ${this.Options.name}, subject: ${email.subject}, recipients: ${email.to?.length ?? 0}`);
|
|
172
|
+
throw err;
|
|
173
|
+
}
|
|
174
|
+
this.Log.trace(`Sent email with data: ${JSON.stringify(lodash_1.default.pick(email, ['from', 'to', 'cc', 'bcc', 'replyTo', 'subject']))}, messageId: ${message?.messageId}, response: ${message?.response}`);
|
|
139
175
|
}
|
|
140
176
|
};
|
|
141
177
|
exports.EmailSenderSmtp = EmailSenderSmtp;
|
|
@@ -146,7 +182,7 @@ __decorate([
|
|
|
146
182
|
__decorate([
|
|
147
183
|
(0, di_1.Autoinject)(templates_1.Templates),
|
|
148
184
|
__metadata("design:type", templates_1.Templates)
|
|
149
|
-
], EmailSenderSmtp.prototype, "
|
|
185
|
+
], EmailSenderSmtp.prototype, "Templates", void 0);
|
|
150
186
|
__decorate([
|
|
151
187
|
(0, configuration_1.Config)('fs.defaultProvider'),
|
|
152
188
|
__metadata("design:type", String)
|
package/lib/cjs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
|
package/lib/mjs/index.d.ts
CHANGED
|
@@ -1,14 +1,25 @@
|
|
|
1
1
|
import { Log } from '@spinajs/log';
|
|
2
2
|
import { IEmail, EmailSender, EmailConnectionOptions } from '@spinajs/email';
|
|
3
3
|
import { Templates } from '@spinajs/templates';
|
|
4
|
+
import { ResiliencePipeline } from '@spinajs/util';
|
|
4
5
|
import * as nodemailer from 'nodemailer';
|
|
5
6
|
export declare class EmailSenderSmtp extends EmailSender {
|
|
6
7
|
Options: EmailConnectionOptions;
|
|
7
8
|
protected Log: Log;
|
|
8
|
-
protected
|
|
9
|
+
protected Templates: Templates;
|
|
9
10
|
protected DefaultFileProvider: string;
|
|
10
11
|
protected Transporter: nodemailer.Transporter;
|
|
12
|
+
/**
|
|
13
|
+
* In-process resilience pipeline guarding the SMTP send ( per-attempt timeout + retry ).
|
|
14
|
+
*/
|
|
15
|
+
protected SendPipeline: ResiliencePipeline<nodemailer.SentMessageInfo>;
|
|
11
16
|
constructor(Options: EmailConnectionOptions);
|
|
17
|
+
/**
|
|
18
|
+
* Builds the in-process resilience pipeline guarding the SMTP send
|
|
19
|
+
* ( per-attempt timeout + exponential retry ). Extracted so the send
|
|
20
|
+
* behavior can be tested hermetically without opening a real connection.
|
|
21
|
+
*/
|
|
22
|
+
protected buildSendPipeline(): ResiliencePipeline<nodemailer.SentMessageInfo>;
|
|
12
23
|
resolve(): Promise<void>;
|
|
13
24
|
send(email: IEmail): Promise<void>;
|
|
14
25
|
}
|
package/lib/mjs/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,GAAG,EAAU,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,sBAAsB,EAAqB,MAAM,gBAAgB,CAAC;AAChG,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,KAAK,UAAU,MAAM,YAAY,CAAC;AAKzC,qBAEa,eAAgB,SAAQ,WAAW;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,GAAG,EAAU,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,sBAAsB,EAAqB,MAAM,gBAAgB,CAAC;AAChG,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAe,kBAAkB,EAA6B,MAAM,eAAe,CAAC;AAC3F,OAAO,KAAK,UAAU,MAAM,YAAY,CAAC;AAKzC,qBAEa,eAAgB,SAAQ,WAAW;IAiB3B,OAAO,EAAE,sBAAsB;IAflD,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC;IAGnB,SAAS,CAAC,SAAS,EAAE,SAAS,CAAC;IAG/B,SAAS,CAAC,mBAAmB,EAAE,MAAM,CAAC;IAEtC,SAAS,CAAC,WAAW,EAAE,UAAU,CAAC,WAAW,CAAC;IAE9C;;OAEG;IACH,SAAS,CAAC,YAAY,EAAE,kBAAkB,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;gBAEpD,OAAO,EAAE,sBAAsB;IAIlD;;;;OAIG;IACH,SAAS,CAAC,iBAAiB,IAAI,kBAAkB,CAAC,UAAU,CAAC,eAAe,CAAC;IAOhE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAwCxB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAmFhD"}
|
package/lib/mjs/index.js
CHANGED
|
@@ -7,11 +7,12 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
7
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
8
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
9
|
};
|
|
10
|
-
import { IOFail } from '@spinajs/exceptions';
|
|
10
|
+
import { IOFail, UnexpectedServerError } from '@spinajs/exceptions';
|
|
11
11
|
import { Autoinject, DI, Injectable, NewInstance } from '@spinajs/di';
|
|
12
12
|
import { Log, Logger } from '@spinajs/log';
|
|
13
13
|
import { EmailSender } from '@spinajs/email';
|
|
14
14
|
import { Templates } from '@spinajs/templates';
|
|
15
|
+
import { BackoffType, ResiliencePipelineBuilder } from '@spinajs/util';
|
|
15
16
|
import * as nodemailer from 'nodemailer';
|
|
16
17
|
import _ from 'lodash';
|
|
17
18
|
import { Config } from '@spinajs/configuration';
|
|
@@ -20,6 +21,17 @@ let EmailSenderSmtp = class EmailSenderSmtp extends EmailSender {
|
|
|
20
21
|
super();
|
|
21
22
|
this.Options = Options;
|
|
22
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* Builds the in-process resilience pipeline guarding the SMTP send
|
|
26
|
+
* ( per-attempt timeout + exponential retry ). Extracted so the send
|
|
27
|
+
* behavior can be tested hermetically without opening a real connection.
|
|
28
|
+
*/
|
|
29
|
+
buildSendPipeline() {
|
|
30
|
+
return new ResiliencePipelineBuilder()
|
|
31
|
+
.addTimeout(this.Options.resilience?.timeout ?? 30_000)
|
|
32
|
+
.addRetry({ MaxRetryAttempts: this.Options.resilience?.retries ?? 2, Delay: this.Options.resilience?.delay ?? 500, BackoffType: BackoffType.Exponential, UseJitter: true })
|
|
33
|
+
.build();
|
|
34
|
+
}
|
|
23
35
|
async resolve() {
|
|
24
36
|
await super.resolve();
|
|
25
37
|
const options = Object.assign({
|
|
@@ -28,7 +40,7 @@ let EmailSenderSmtp = class EmailSenderSmtp extends EmailSender {
|
|
|
28
40
|
secure: this.Options.ssl, // true for 465, false for other ports
|
|
29
41
|
auth: {
|
|
30
42
|
user: this.Options.user, // generated ethereal user
|
|
31
|
-
pass: this.Options.
|
|
43
|
+
pass: this.Options.password, // generated ethereal password
|
|
32
44
|
},
|
|
33
45
|
},
|
|
34
46
|
// all additional options merged
|
|
@@ -36,13 +48,17 @@ let EmailSenderSmtp = class EmailSenderSmtp extends EmailSender {
|
|
|
36
48
|
this.Log.info(`Creating connection to smtp: ${options.auth.user}@${options.host}:${options.port}, secure: ${options.secure}`);
|
|
37
49
|
// create reusable transporter object using the default SMTP transport
|
|
38
50
|
this.Transporter = nodemailer.createTransport(options);
|
|
51
|
+
// in-process resilience applied only around the SMTP send. Queue-level retry
|
|
52
|
+
// handles deferred sends once this pipeline gives up.
|
|
53
|
+
this.SendPipeline = this.buildSendPipeline();
|
|
39
54
|
try {
|
|
40
55
|
// verify returns Promise<true> so always is true
|
|
41
56
|
// we must catch exception
|
|
42
57
|
await this.Transporter.verify();
|
|
43
58
|
}
|
|
44
59
|
catch (err) {
|
|
45
|
-
|
|
60
|
+
this.Log.error(err, `Cannot verify smtp connection ${this.Options.name} (${this.Options.host}:${this.Options.port})`);
|
|
61
|
+
throw new UnexpectedServerError(`Cannot verify smtp connection ${this.Options.name} (${this.Options.host}:${this.Options.port})`, err);
|
|
46
62
|
}
|
|
47
63
|
this.Log.success(`Email smtp connection ${this.Options.name} on host ${this.Options.host} established !`);
|
|
48
64
|
}
|
|
@@ -50,19 +66,31 @@ let EmailSenderSmtp = class EmailSenderSmtp extends EmailSender {
|
|
|
50
66
|
if (!email.from && !this.Options.defaults?.mailFrom) {
|
|
51
67
|
throw new IOFail(`Email from address is required. Please provide it in email or in configuration`);
|
|
52
68
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
69
|
+
// only resolve / download / render a template when one is actually provided.
|
|
70
|
+
// text-only emails leave html undefined.
|
|
71
|
+
let html;
|
|
72
|
+
if (email.template) {
|
|
73
|
+
// string template -> default template filesystem
|
|
74
|
+
// IEmailTemplate object -> resolve its own fs provider
|
|
75
|
+
let templateFs = this.defaultTemplateFs;
|
|
76
|
+
if (!_.isString(email.template)) {
|
|
77
|
+
templateFs = await DI.resolve('__file_provider__', [email.template.fs]);
|
|
78
|
+
if (!templateFs) {
|
|
79
|
+
throw new IOFail(`Filesystem provider for ${email.template.fs} not registered. Make sure you importer all required fs providers`);
|
|
80
|
+
}
|
|
57
81
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
82
|
+
this.Log.trace(`Using filesystem ${templateFs.Name} to resolve email template`);
|
|
83
|
+
const tfile = await (_.isString(email.template) ? templateFs.download(email.template) : templateFs.download(email.template.file));
|
|
84
|
+
this.Log.trace(`Resolved email template ${tfile}`);
|
|
85
|
+
try {
|
|
86
|
+
html = await this.Templates.render(tfile, { ...email.model, ...this.Options.templates?.defaults }, email.lang);
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
// template rendering is a deterministic failure - log & rethrow the original error, do not retry
|
|
90
|
+
this.Log.error(err, `Cannot render email template ${tfile} for connection ${this.Options.name}`);
|
|
91
|
+
throw err;
|
|
61
92
|
}
|
|
62
93
|
}
|
|
63
|
-
this.Log.trace(`Using filesystem ${fs.Name} to resolve email template`);
|
|
64
|
-
const tfile = await (_.isString(email.template) ? fs.download(email.template) : fs.download(email.template.file));
|
|
65
|
-
this.Log.trace(`Resolved email template ${tfile}`);
|
|
66
94
|
const options = {
|
|
67
95
|
from: email.from ?? this.Options.defaults?.mailFrom, // sender address
|
|
68
96
|
to: email.to.join(','), // list of receivers
|
|
@@ -71,7 +99,7 @@ let EmailSenderSmtp = class EmailSenderSmtp extends EmailSender {
|
|
|
71
99
|
replyTo: email.replyTo,
|
|
72
100
|
subject: email.subject, // Subject line
|
|
73
101
|
text: email.text, // plain text body
|
|
74
|
-
html
|
|
102
|
+
html, // rendered template or undefined for text-only emails
|
|
75
103
|
attachments: [],
|
|
76
104
|
};
|
|
77
105
|
if (email.attachements) {
|
|
@@ -95,8 +123,16 @@ let EmailSenderSmtp = class EmailSenderSmtp extends EmailSender {
|
|
|
95
123
|
};
|
|
96
124
|
}));
|
|
97
125
|
}
|
|
98
|
-
let message
|
|
99
|
-
|
|
126
|
+
let message;
|
|
127
|
+
try {
|
|
128
|
+
// guard only the SMTP send with the resilience pipeline ( timeout + retry )
|
|
129
|
+
message = await this.SendPipeline.execute(() => this.Transporter.sendMail(options));
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
this.Log.error(err, `Cannot send email for connection ${this.Options.name}, subject: ${email.subject}, recipients: ${email.to?.length ?? 0}`);
|
|
133
|
+
throw err;
|
|
134
|
+
}
|
|
135
|
+
this.Log.trace(`Sent email with data: ${JSON.stringify(_.pick(email, ['from', 'to', 'cc', 'bcc', 'replyTo', 'subject']))}, messageId: ${message?.messageId}, response: ${message?.response}`);
|
|
100
136
|
}
|
|
101
137
|
};
|
|
102
138
|
__decorate([
|
|
@@ -106,7 +142,7 @@ __decorate([
|
|
|
106
142
|
__decorate([
|
|
107
143
|
Autoinject(Templates),
|
|
108
144
|
__metadata("design:type", Templates)
|
|
109
|
-
], EmailSenderSmtp.prototype, "
|
|
145
|
+
], EmailSenderSmtp.prototype, "Templates", void 0);
|
|
110
146
|
__decorate([
|
|
111
147
|
Config('fs.defaultProvider'),
|
|
112
148
|
__metadata("design:type", String)
|
package/lib/mjs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
|