@flusys/nestjs-email 7.1.0 → 8.0.0-beta.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/config/index.d.ts +3 -3
- package/controllers/email-config.controller.d.ts +2 -2
- package/controllers/email-send.controller.d.ts +3 -3
- package/controllers/email-template.controller.d.ts +4 -4
- package/controllers/index.d.ts +3 -3
- package/docs/email-swagger.config.d.ts +2 -2
- package/docs/index.d.ts +1 -1
- package/dtos/email-config.dto.d.ts +1 -1
- package/dtos/email-send.dto.d.ts +1 -1
- package/dtos/index.d.ts +3 -3
- package/entities/email-config-with-company.entity.d.ts +1 -1
- package/entities/email-template-with-company.entity.d.ts +1 -1
- package/entities/index.d.ts +10 -10
- package/enums/index.d.ts +1 -1
- package/fesm/261.js +799 -0
- package/fesm/493.js +1723 -0
- package/fesm/chunks/99.js +12 -0
- package/fesm/config/index.js +104 -3
- package/fesm/controllers/index.js +396 -3
- package/fesm/docs/index.js +134 -1
- package/fesm/dtos/index.js +22 -3
- package/fesm/entities/index.js +409 -13
- package/fesm/enums/index.js +37 -1
- package/fesm/index.js +762 -10
- package/fesm/interfaces/index.js +18 -4
- package/fesm/modules/index.js +541 -1
- package/fesm/providers/index.js +523 -5
- package/fesm/runtime.js +134 -0
- package/fesm/services/index.js +17 -5
- package/index.d.ts +10 -10
- package/interfaces/email-config.interface.d.ts +2 -2
- package/interfaces/email-module-options.interface.d.ts +3 -3
- package/interfaces/email-template.interface.d.ts +1 -1
- package/interfaces/index.d.ts +4 -4
- package/modules/email.module.d.ts +2 -2
- package/modules/index.d.ts +1 -1
- package/package.json +27 -38
- package/providers/email-factory.service.d.ts +2 -2
- package/providers/email-provider.registry.d.ts +2 -2
- package/providers/index.d.ts +5 -5
- package/providers/mailgun-provider.d.ts +1 -1
- package/providers/sendgrid-provider.d.ts +1 -1
- package/providers/smtp-provider.d.ts +1 -1
- package/services/email-config.service.d.ts +3 -3
- package/services/email-datasource.provider.d.ts +3 -3
- package/services/email-provider-config.service.d.ts +7 -7
- package/services/email-send.service.d.ts +7 -7
- package/services/email-template.service.d.ts +6 -6
- package/services/index.d.ts +5 -5
- package/utils/index.d.ts +1 -1
- package/cjs/config/email.constants.js +0 -22
- package/cjs/config/event-actions.js +0 -34
- package/cjs/config/index.js +0 -20
- package/cjs/config/message-keys.js +0 -39
- package/cjs/controllers/email-config.controller.js +0 -111
- package/cjs/controllers/email-config.controller.spec.js +0 -85
- package/cjs/controllers/email-send.controller.js +0 -128
- package/cjs/controllers/email-send.controller.spec.js +0 -139
- package/cjs/controllers/email-template.controller.js +0 -142
- package/cjs/controllers/email-template.controller.spec.js +0 -89
- package/cjs/controllers/index.js +0 -20
- package/cjs/docs/email-swagger.config.js +0 -116
- package/cjs/docs/email-swagger.config.spec.js +0 -62
- package/cjs/docs/index.js +0 -11
- package/cjs/dtos/email-config.dto.js +0 -212
- package/cjs/dtos/email-send.dto.js +0 -354
- package/cjs/dtos/email-template.dto.js +0 -252
- package/cjs/dtos/index.js +0 -20
- package/cjs/entities/email-config-with-company.entity.js +0 -63
- package/cjs/entities/email-config.entity.js +0 -114
- package/cjs/entities/email-template-with-company.entity.js +0 -65
- package/cjs/entities/email-template.entity.js +0 -136
- package/cjs/entities/index.js +0 -56
- package/cjs/entities/index.spec.js +0 -18
- package/cjs/enums/email-provider-type.enum.js +0 -18
- package/cjs/enums/index.js +0 -18
- package/cjs/index.js +0 -28
- package/cjs/interfaces/email-config.interface.js +0 -4
- package/cjs/interfaces/email-module-options.interface.js +0 -4
- package/cjs/interfaces/email-provider.interface.js +0 -4
- package/cjs/interfaces/email-template.interface.js +0 -4
- package/cjs/interfaces/index.js +0 -21
- package/cjs/modules/email.module.js +0 -122
- package/cjs/modules/email.module.spec.js +0 -142
- package/cjs/modules/index.js +0 -18
- package/cjs/providers/email-factory.service.js +0 -113
- package/cjs/providers/email-factory.service.spec.js +0 -242
- package/cjs/providers/email-provider.registry.js +0 -41
- package/cjs/providers/email-provider.registry.spec.js +0 -58
- package/cjs/providers/index.js +0 -22
- package/cjs/providers/mailgun-provider.js +0 -119
- package/cjs/providers/mailgun-provider.spec.js +0 -244
- package/cjs/providers/sendgrid-provider.js +0 -129
- package/cjs/providers/sendgrid-provider.spec.js +0 -346
- package/cjs/providers/smtp-provider.js +0 -164
- package/cjs/providers/smtp-provider.spec.js +0 -327
- package/cjs/services/email-config.service.js +0 -71
- package/cjs/services/email-config.service.spec.js +0 -69
- package/cjs/services/email-datasource.provider.js +0 -84
- package/cjs/services/email-datasource.provider.spec.js +0 -135
- package/cjs/services/email-provider-config.service.js +0 -159
- package/cjs/services/email-provider-config.service.spec.js +0 -269
- package/cjs/services/email-send.service.js +0 -315
- package/cjs/services/email-send.service.spec.js +0 -614
- package/cjs/services/email-template.service.js +0 -144
- package/cjs/services/email-template.service.spec.js +0 -261
- package/cjs/services/index.js +0 -22
- package/cjs/utils/email-templates.util.js +0 -64
- package/cjs/utils/email-templates.util.spec.js +0 -61
- package/cjs/utils/index.js +0 -18
- package/fesm/config/email.constants.js +0 -4
- package/fesm/config/event-actions.js +0 -13
- package/fesm/config/message-keys.js +0 -18
- package/fesm/controllers/email-config.controller.js +0 -101
- package/fesm/controllers/email-config.controller.spec.js +0 -81
- package/fesm/controllers/email-send.controller.js +0 -118
- package/fesm/controllers/email-send.controller.spec.js +0 -135
- package/fesm/controllers/email-template.controller.js +0 -132
- package/fesm/controllers/email-template.controller.spec.js +0 -85
- package/fesm/docs/email-swagger.config.js +0 -109
- package/fesm/docs/email-swagger.config.spec.js +0 -58
- package/fesm/dtos/email-config.dto.js +0 -191
- package/fesm/dtos/email-send.dto.js +0 -324
- package/fesm/dtos/email-template.dto.js +0 -231
- package/fesm/entities/email-config-with-company.entity.js +0 -53
- package/fesm/entities/email-config.entity.js +0 -104
- package/fesm/entities/email-template-with-company.entity.js +0 -55
- package/fesm/entities/email-template.entity.js +0 -126
- package/fesm/entities/index.spec.js +0 -14
- package/fesm/enums/email-provider-type.enum.js +0 -8
- package/fesm/interfaces/email-config.interface.js +0 -1
- package/fesm/interfaces/email-module-options.interface.js +0 -1
- package/fesm/interfaces/email-provider.interface.js +0 -1
- package/fesm/interfaces/email-template.interface.js +0 -1
- package/fesm/modules/email.module.js +0 -112
- package/fesm/modules/email.module.spec.js +0 -138
- package/fesm/providers/email-factory.service.js +0 -103
- package/fesm/providers/email-factory.service.spec.js +0 -238
- package/fesm/providers/email-provider.registry.js +0 -31
- package/fesm/providers/email-provider.registry.spec.js +0 -54
- package/fesm/providers/mailgun-provider.js +0 -109
- package/fesm/providers/mailgun-provider.spec.js +0 -240
- package/fesm/providers/sendgrid-provider.js +0 -119
- package/fesm/providers/sendgrid-provider.spec.js +0 -342
- package/fesm/providers/smtp-provider.js +0 -113
- package/fesm/providers/smtp-provider.spec.js +0 -282
- package/fesm/services/email-config.service.js +0 -61
- package/fesm/services/email-config.service.spec.js +0 -65
- package/fesm/services/email-datasource.provider.js +0 -74
- package/fesm/services/email-datasource.provider.spec.js +0 -131
- package/fesm/services/email-provider-config.service.js +0 -149
- package/fesm/services/email-provider-config.service.spec.js +0 -265
- package/fesm/services/email-send.service.js +0 -305
- package/fesm/services/email-send.service.spec.js +0 -610
- package/fesm/services/email-template.service.js +0 -134
- package/fesm/services/email-template.service.spec.js +0 -257
- package/fesm/utils/email-templates.util.js +0 -47
- package/fesm/utils/email-templates.util.spec.js +0 -57
- package/fesm/utils/index.js +0 -1
|
@@ -1,346 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", {
|
|
3
|
-
value: true
|
|
4
|
-
});
|
|
5
|
-
const _common = require("@nestjs/common");
|
|
6
|
-
const _sendgridprovider = require("./sendgrid-provider");
|
|
7
|
-
// @sendgrid/mail is not an installed dependency in this workspace, so the real dynamic
|
|
8
|
-
// import() inside `initialize()` fails — exercised directly, no mocking needed.
|
|
9
|
-
// For "happy path" behavior we bypass initialize() and inject a fake sgMail client,
|
|
10
|
-
// matching the private `sgMail`/`apiKey` fields the provider mutates internally.
|
|
11
|
-
function injectSgMail(provider, sgMail, apiKey = 'SG.fake-key') {
|
|
12
|
-
provider.sgMail = sgMail;
|
|
13
|
-
provider.apiKey = apiKey;
|
|
14
|
-
}
|
|
15
|
-
describe('SendGridProvider', ()=>{
|
|
16
|
-
let provider;
|
|
17
|
-
beforeEach(()=>{
|
|
18
|
-
provider = new _sendgridprovider.SendGridProvider();
|
|
19
|
-
});
|
|
20
|
-
describe('initialize', ()=>{
|
|
21
|
-
it('throws InternalServerErrorException with SDK_NOT_INSTALLED when @sendgrid/mail is unavailable', async ()=>{
|
|
22
|
-
await expect(provider.initialize({
|
|
23
|
-
apiKey: 'SG.key'
|
|
24
|
-
})).rejects.toThrow(_common.InternalServerErrorException);
|
|
25
|
-
});
|
|
26
|
-
it('surfaces the sdk name in the exception messageVariables', async ()=>{
|
|
27
|
-
try {
|
|
28
|
-
await provider.initialize({
|
|
29
|
-
apiKey: 'SG.key'
|
|
30
|
-
});
|
|
31
|
-
fail('expected initialize to throw');
|
|
32
|
-
} catch (error) {
|
|
33
|
-
expect(error.getResponse()).toEqual(expect.objectContaining({
|
|
34
|
-
messageKey: 'system.sdk.not.installed',
|
|
35
|
-
messageVariables: {
|
|
36
|
-
sdk: 'sendgrid'
|
|
37
|
-
}
|
|
38
|
-
}));
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
});
|
|
42
|
-
describe('sendEmail', ()=>{
|
|
43
|
-
it('returns a failure result when the provider was never initialized', async ()=>{
|
|
44
|
-
const result = await provider.sendEmail({
|
|
45
|
-
to: 'a@example.com',
|
|
46
|
-
subject: 'Hi'
|
|
47
|
-
});
|
|
48
|
-
expect(result).toEqual({
|
|
49
|
-
success: false,
|
|
50
|
-
error: 'SendGrid provider not initialized'
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
it('sends via sgMail.send and extracts the message id from response headers', async ()=>{
|
|
54
|
-
const send = jest.fn().mockResolvedValue([
|
|
55
|
-
{
|
|
56
|
-
headers: {
|
|
57
|
-
'x-message-id': 'sg-msg-1'
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
]);
|
|
61
|
-
injectSgMail(provider, {
|
|
62
|
-
send
|
|
63
|
-
});
|
|
64
|
-
const result = await provider.sendEmail({
|
|
65
|
-
to: [
|
|
66
|
-
'a@example.com',
|
|
67
|
-
'b@example.com'
|
|
68
|
-
],
|
|
69
|
-
subject: 'Hello',
|
|
70
|
-
html: '<p>hi</p>',
|
|
71
|
-
from: 'sender@example.com',
|
|
72
|
-
fromName: 'Sender Name',
|
|
73
|
-
cc: 'c@example.com',
|
|
74
|
-
bcc: [
|
|
75
|
-
'd@example.com'
|
|
76
|
-
],
|
|
77
|
-
replyTo: 'reply@example.com'
|
|
78
|
-
});
|
|
79
|
-
expect(result).toEqual({
|
|
80
|
-
success: true,
|
|
81
|
-
messageId: 'sg-msg-1'
|
|
82
|
-
});
|
|
83
|
-
expect(send).toHaveBeenCalledWith(expect.objectContaining({
|
|
84
|
-
to: [
|
|
85
|
-
'a@example.com',
|
|
86
|
-
'b@example.com'
|
|
87
|
-
],
|
|
88
|
-
from: {
|
|
89
|
-
email: 'sender@example.com',
|
|
90
|
-
name: 'Sender Name'
|
|
91
|
-
},
|
|
92
|
-
subject: 'Hello',
|
|
93
|
-
html: '<p>hi</p>',
|
|
94
|
-
cc: [
|
|
95
|
-
'c@example.com'
|
|
96
|
-
],
|
|
97
|
-
bcc: [
|
|
98
|
-
'd@example.com'
|
|
99
|
-
],
|
|
100
|
-
replyTo: 'reply@example.com'
|
|
101
|
-
}));
|
|
102
|
-
});
|
|
103
|
-
it('falls back to the capitalized X-Message-Id header when lowercase is absent', async ()=>{
|
|
104
|
-
const send = jest.fn().mockResolvedValue([
|
|
105
|
-
{
|
|
106
|
-
headers: {
|
|
107
|
-
'X-Message-Id': 'sg-msg-2'
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
]);
|
|
111
|
-
injectSgMail(provider, {
|
|
112
|
-
send
|
|
113
|
-
});
|
|
114
|
-
const result = await provider.sendEmail({
|
|
115
|
-
to: 'a@example.com',
|
|
116
|
-
subject: 'Hi',
|
|
117
|
-
from: 'x@example.com'
|
|
118
|
-
});
|
|
119
|
-
expect(result).toEqual({
|
|
120
|
-
success: true,
|
|
121
|
-
messageId: 'sg-msg-2'
|
|
122
|
-
});
|
|
123
|
-
});
|
|
124
|
-
it('base64-encodes buffer attachment content for the SendGrid payload', async ()=>{
|
|
125
|
-
const send = jest.fn().mockResolvedValue([
|
|
126
|
-
{
|
|
127
|
-
headers: {}
|
|
128
|
-
}
|
|
129
|
-
]);
|
|
130
|
-
injectSgMail(provider, {
|
|
131
|
-
send
|
|
132
|
-
});
|
|
133
|
-
await provider.sendEmail({
|
|
134
|
-
to: 'a@example.com',
|
|
135
|
-
subject: 'Hi',
|
|
136
|
-
from: 'x@example.com',
|
|
137
|
-
attachments: [
|
|
138
|
-
{
|
|
139
|
-
filename: 'doc.txt',
|
|
140
|
-
content: Buffer.from('hello'),
|
|
141
|
-
contentType: 'text/plain'
|
|
142
|
-
}
|
|
143
|
-
]
|
|
144
|
-
});
|
|
145
|
-
const [msg] = send.mock.calls[0];
|
|
146
|
-
expect(msg.attachments[0]).toEqual({
|
|
147
|
-
filename: 'doc.txt',
|
|
148
|
-
content: Buffer.from('hello').toString('base64'),
|
|
149
|
-
type: 'text/plain',
|
|
150
|
-
disposition: 'attachment'
|
|
151
|
-
});
|
|
152
|
-
});
|
|
153
|
-
it('returns the SendGrid API error message on failure', async ()=>{
|
|
154
|
-
injectSgMail(provider, {
|
|
155
|
-
send: jest.fn().mockRejectedValue({
|
|
156
|
-
response: {
|
|
157
|
-
body: {
|
|
158
|
-
errors: [
|
|
159
|
-
{
|
|
160
|
-
message: 'Invalid recipient'
|
|
161
|
-
}
|
|
162
|
-
]
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
})
|
|
166
|
-
});
|
|
167
|
-
const result = await provider.sendEmail({
|
|
168
|
-
to: 'a@example.com',
|
|
169
|
-
subject: 'Hi'
|
|
170
|
-
});
|
|
171
|
-
expect(result).toEqual({
|
|
172
|
-
success: false,
|
|
173
|
-
error: 'Invalid recipient'
|
|
174
|
-
});
|
|
175
|
-
});
|
|
176
|
-
it('falls back to the generic error message when no SendGrid error body is present', async ()=>{
|
|
177
|
-
injectSgMail(provider, {
|
|
178
|
-
send: jest.fn().mockRejectedValue(new Error('network down'))
|
|
179
|
-
});
|
|
180
|
-
const result = await provider.sendEmail({
|
|
181
|
-
to: 'a@example.com',
|
|
182
|
-
subject: 'Hi'
|
|
183
|
-
});
|
|
184
|
-
expect(result).toEqual({
|
|
185
|
-
success: false,
|
|
186
|
-
error: 'network down'
|
|
187
|
-
});
|
|
188
|
-
});
|
|
189
|
-
it('falls back to "Unknown error" when no message is available at all', async ()=>{
|
|
190
|
-
injectSgMail(provider, {
|
|
191
|
-
send: jest.fn().mockRejectedValue({})
|
|
192
|
-
});
|
|
193
|
-
const result = await provider.sendEmail({
|
|
194
|
-
to: 'a@example.com',
|
|
195
|
-
subject: 'Hi'
|
|
196
|
-
});
|
|
197
|
-
expect(result).toEqual({
|
|
198
|
-
success: false,
|
|
199
|
-
error: 'Unknown error'
|
|
200
|
-
});
|
|
201
|
-
});
|
|
202
|
-
});
|
|
203
|
-
describe('sendBulkEmails', ()=>{
|
|
204
|
-
it('returns a not-initialized failure per message when not initialized', async ()=>{
|
|
205
|
-
const results = await provider.sendBulkEmails([
|
|
206
|
-
{
|
|
207
|
-
to: 'a@example.com',
|
|
208
|
-
subject: 'A'
|
|
209
|
-
},
|
|
210
|
-
{
|
|
211
|
-
to: 'b@example.com',
|
|
212
|
-
subject: 'B'
|
|
213
|
-
}
|
|
214
|
-
]);
|
|
215
|
-
expect(results).toEqual([
|
|
216
|
-
{
|
|
217
|
-
success: false,
|
|
218
|
-
error: 'SendGrid provider not initialized'
|
|
219
|
-
},
|
|
220
|
-
{
|
|
221
|
-
success: false,
|
|
222
|
-
error: 'SendGrid provider not initialized'
|
|
223
|
-
}
|
|
224
|
-
]);
|
|
225
|
-
});
|
|
226
|
-
it('sends all messages in a single sgMail.send call and reports success for all', async ()=>{
|
|
227
|
-
const send = jest.fn().mockResolvedValue(undefined);
|
|
228
|
-
injectSgMail(provider, {
|
|
229
|
-
send
|
|
230
|
-
});
|
|
231
|
-
const results = await provider.sendBulkEmails([
|
|
232
|
-
{
|
|
233
|
-
to: 'a@example.com',
|
|
234
|
-
subject: 'A',
|
|
235
|
-
from: 'x@example.com'
|
|
236
|
-
},
|
|
237
|
-
{
|
|
238
|
-
to: 'b@example.com',
|
|
239
|
-
subject: 'B',
|
|
240
|
-
from: 'x@example.com'
|
|
241
|
-
}
|
|
242
|
-
]);
|
|
243
|
-
expect(send).toHaveBeenCalledTimes(1);
|
|
244
|
-
expect(send).toHaveBeenCalledWith([
|
|
245
|
-
expect.objectContaining({
|
|
246
|
-
to: [
|
|
247
|
-
'a@example.com'
|
|
248
|
-
],
|
|
249
|
-
subject: 'A'
|
|
250
|
-
}),
|
|
251
|
-
expect.objectContaining({
|
|
252
|
-
to: [
|
|
253
|
-
'b@example.com'
|
|
254
|
-
],
|
|
255
|
-
subject: 'B'
|
|
256
|
-
})
|
|
257
|
-
]);
|
|
258
|
-
expect(results).toEqual([
|
|
259
|
-
{
|
|
260
|
-
success: true
|
|
261
|
-
},
|
|
262
|
-
{
|
|
263
|
-
success: true
|
|
264
|
-
}
|
|
265
|
-
]);
|
|
266
|
-
});
|
|
267
|
-
it('excludes cc/bcc/replyTo/attachments from bulk messages (includeExtras=false)', async ()=>{
|
|
268
|
-
const send = jest.fn().mockResolvedValue(undefined);
|
|
269
|
-
injectSgMail(provider, {
|
|
270
|
-
send
|
|
271
|
-
});
|
|
272
|
-
await provider.sendBulkEmails([
|
|
273
|
-
{
|
|
274
|
-
to: 'a@example.com',
|
|
275
|
-
subject: 'A',
|
|
276
|
-
from: 'x@example.com',
|
|
277
|
-
cc: 'c@example.com',
|
|
278
|
-
replyTo: 'r@example.com'
|
|
279
|
-
}
|
|
280
|
-
]);
|
|
281
|
-
const [messages] = send.mock.calls[0];
|
|
282
|
-
expect(messages[0]).not.toHaveProperty('cc');
|
|
283
|
-
expect(messages[0]).not.toHaveProperty('replyTo');
|
|
284
|
-
});
|
|
285
|
-
it('reports the same failure for every message when the bulk send call rejects', async ()=>{
|
|
286
|
-
injectSgMail(provider, {
|
|
287
|
-
send: jest.fn().mockRejectedValue(new Error('rate limited'))
|
|
288
|
-
});
|
|
289
|
-
const results = await provider.sendBulkEmails([
|
|
290
|
-
{
|
|
291
|
-
to: 'a@example.com',
|
|
292
|
-
subject: 'A',
|
|
293
|
-
from: 'x@example.com'
|
|
294
|
-
},
|
|
295
|
-
{
|
|
296
|
-
to: 'b@example.com',
|
|
297
|
-
subject: 'B',
|
|
298
|
-
from: 'x@example.com'
|
|
299
|
-
}
|
|
300
|
-
]);
|
|
301
|
-
expect(results).toEqual([
|
|
302
|
-
{
|
|
303
|
-
success: false,
|
|
304
|
-
error: 'rate limited'
|
|
305
|
-
},
|
|
306
|
-
{
|
|
307
|
-
success: false,
|
|
308
|
-
error: 'rate limited'
|
|
309
|
-
}
|
|
310
|
-
]);
|
|
311
|
-
});
|
|
312
|
-
});
|
|
313
|
-
describe('healthCheck', ()=>{
|
|
314
|
-
it('returns false when not initialized', async ()=>{
|
|
315
|
-
await expect(provider.healthCheck()).resolves.toBe(false);
|
|
316
|
-
});
|
|
317
|
-
it('returns true when sgMail is set and the api key has the SG. prefix', async ()=>{
|
|
318
|
-
injectSgMail(provider, {
|
|
319
|
-
send: jest.fn()
|
|
320
|
-
}, 'SG.validkey');
|
|
321
|
-
await expect(provider.healthCheck()).resolves.toBe(true);
|
|
322
|
-
});
|
|
323
|
-
it('returns false when the api key does not have the SG. prefix', async ()=>{
|
|
324
|
-
injectSgMail(provider, {
|
|
325
|
-
send: jest.fn()
|
|
326
|
-
}, 'invalid-key');
|
|
327
|
-
await expect(provider.healthCheck()).resolves.toBe(false);
|
|
328
|
-
});
|
|
329
|
-
});
|
|
330
|
-
describe('close', ()=>{
|
|
331
|
-
it('clears the sgMail client reference', async ()=>{
|
|
332
|
-
injectSgMail(provider, {
|
|
333
|
-
send: jest.fn()
|
|
334
|
-
});
|
|
335
|
-
await provider.close();
|
|
336
|
-
const result = await provider.sendEmail({
|
|
337
|
-
to: 'a@example.com',
|
|
338
|
-
subject: 'Hi'
|
|
339
|
-
});
|
|
340
|
-
expect(result).toEqual({
|
|
341
|
-
success: false,
|
|
342
|
-
error: 'SendGrid provider not initialized'
|
|
343
|
-
});
|
|
344
|
-
});
|
|
345
|
-
});
|
|
346
|
-
});
|
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", {
|
|
3
|
-
value: true
|
|
4
|
-
});
|
|
5
|
-
Object.defineProperty(exports, "SmtpProvider", {
|
|
6
|
-
enumerable: true,
|
|
7
|
-
get: function() {
|
|
8
|
-
return SmtpProvider;
|
|
9
|
-
}
|
|
10
|
-
});
|
|
11
|
-
function _define_property(obj, key, value) {
|
|
12
|
-
if (key in obj) {
|
|
13
|
-
Object.defineProperty(obj, key, {
|
|
14
|
-
value: value,
|
|
15
|
-
enumerable: true,
|
|
16
|
-
configurable: true,
|
|
17
|
-
writable: true
|
|
18
|
-
});
|
|
19
|
-
} else {
|
|
20
|
-
obj[key] = value;
|
|
21
|
-
}
|
|
22
|
-
return obj;
|
|
23
|
-
}
|
|
24
|
-
function _getRequireWildcardCache(nodeInterop) {
|
|
25
|
-
if (typeof WeakMap !== "function") return null;
|
|
26
|
-
var cacheBabelInterop = new WeakMap();
|
|
27
|
-
var cacheNodeInterop = new WeakMap();
|
|
28
|
-
return (_getRequireWildcardCache = function(nodeInterop) {
|
|
29
|
-
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|
30
|
-
})(nodeInterop);
|
|
31
|
-
}
|
|
32
|
-
function _interop_require_wildcard(obj, nodeInterop) {
|
|
33
|
-
if (!nodeInterop && obj && obj.__esModule) {
|
|
34
|
-
return obj;
|
|
35
|
-
}
|
|
36
|
-
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
|
37
|
-
return {
|
|
38
|
-
default: obj
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
var cache = _getRequireWildcardCache(nodeInterop);
|
|
42
|
-
if (cache && cache.has(obj)) {
|
|
43
|
-
return cache.get(obj);
|
|
44
|
-
}
|
|
45
|
-
var newObj = {
|
|
46
|
-
__proto__: null
|
|
47
|
-
};
|
|
48
|
-
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|
49
|
-
for(var key in obj){
|
|
50
|
-
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
51
|
-
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
|
52
|
-
if (desc && (desc.get || desc.set)) {
|
|
53
|
-
Object.defineProperty(newObj, key, desc);
|
|
54
|
-
} else {
|
|
55
|
-
newObj[key] = obj[key];
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
newObj.default = obj;
|
|
60
|
-
if (cache) {
|
|
61
|
-
cache.set(obj, newObj);
|
|
62
|
-
}
|
|
63
|
-
return newObj;
|
|
64
|
-
}
|
|
65
|
-
const VERIFY_TIMEOUT_MS = 10_000;
|
|
66
|
-
const SEND_TIMEOUT_MS = 30_000;
|
|
67
|
-
let SmtpProvider = class SmtpProvider {
|
|
68
|
-
async initialize(config) {
|
|
69
|
-
const nodemailer = await Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("nodemailer")));
|
|
70
|
-
this.transporter = nodemailer.createTransport({
|
|
71
|
-
host: config.host,
|
|
72
|
-
port: config.port,
|
|
73
|
-
secure: config.secure ?? config.port === 465,
|
|
74
|
-
auth: config.auth,
|
|
75
|
-
connectionTimeout: VERIFY_TIMEOUT_MS,
|
|
76
|
-
greetingTimeout: VERIFY_TIMEOUT_MS,
|
|
77
|
-
socketTimeout: SEND_TIMEOUT_MS,
|
|
78
|
-
tls: {
|
|
79
|
-
rejectUnauthorized: config.tls?.rejectUnauthorized ?? true,
|
|
80
|
-
minVersion: config.tls?.minVersion ?? 'TLSv1.2'
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
await this.withTimeout(this.transporter.verify(), VERIFY_TIMEOUT_MS, 'SMTP verification timeout');
|
|
84
|
-
}
|
|
85
|
-
async sendEmail(options) {
|
|
86
|
-
if (!this.transporter) return {
|
|
87
|
-
success: false,
|
|
88
|
-
error: 'SMTP provider not initialized'
|
|
89
|
-
};
|
|
90
|
-
try {
|
|
91
|
-
const mailOptions = {
|
|
92
|
-
from: this.formatFrom(options.from, options.fromName),
|
|
93
|
-
to: this.joinAddresses(options.to),
|
|
94
|
-
cc: options.cc ? this.joinAddresses(options.cc) : undefined,
|
|
95
|
-
bcc: options.bcc ? this.joinAddresses(options.bcc) : undefined,
|
|
96
|
-
subject: options.subject,
|
|
97
|
-
text: options.text,
|
|
98
|
-
html: options.html,
|
|
99
|
-
replyTo: options.replyTo,
|
|
100
|
-
attachments: options.attachments?.map((a)=>({
|
|
101
|
-
filename: a.filename,
|
|
102
|
-
content: a.content,
|
|
103
|
-
contentType: a.contentType,
|
|
104
|
-
encoding: a.encoding
|
|
105
|
-
}))
|
|
106
|
-
};
|
|
107
|
-
const info = await this.withTimeout(this.transporter.sendMail(mailOptions), SEND_TIMEOUT_MS, 'SMTP send timeout');
|
|
108
|
-
return {
|
|
109
|
-
success: true,
|
|
110
|
-
messageId: info.messageId
|
|
111
|
-
};
|
|
112
|
-
} catch (error) {
|
|
113
|
-
return {
|
|
114
|
-
success: false,
|
|
115
|
-
error: this.extractError(error)
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
async sendBulkEmails(options) {
|
|
120
|
-
return Promise.all(options.map((opt)=>this.sendEmail(opt)));
|
|
121
|
-
}
|
|
122
|
-
async healthCheck() {
|
|
123
|
-
if (!this.transporter) return false;
|
|
124
|
-
try {
|
|
125
|
-
await this.transporter.verify();
|
|
126
|
-
return true;
|
|
127
|
-
} catch {
|
|
128
|
-
return false;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
async close() {
|
|
132
|
-
if (this.transporter) {
|
|
133
|
-
this.transporter.close();
|
|
134
|
-
this.transporter = null;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
// ─── Private Helpers ────────────────────────────────────────────────────────
|
|
138
|
-
formatFrom(from, fromName) {
|
|
139
|
-
return fromName ? `"${fromName}" <${from}>` : from;
|
|
140
|
-
}
|
|
141
|
-
joinAddresses(addresses) {
|
|
142
|
-
return Array.isArray(addresses) ? addresses.join(', ') : addresses;
|
|
143
|
-
}
|
|
144
|
-
async withTimeout(promise, ms, message) {
|
|
145
|
-
let timer;
|
|
146
|
-
const timeout = new Promise((_, reject)=>{
|
|
147
|
-
timer = setTimeout(()=>reject(new Error(message)), ms);
|
|
148
|
-
});
|
|
149
|
-
try {
|
|
150
|
-
return await Promise.race([
|
|
151
|
-
promise,
|
|
152
|
-
timeout
|
|
153
|
-
]);
|
|
154
|
-
} finally{
|
|
155
|
-
clearTimeout(timer);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
extractError(error) {
|
|
159
|
-
return error instanceof Error ? error.message : 'Unknown error';
|
|
160
|
-
}
|
|
161
|
-
constructor(){
|
|
162
|
-
_define_property(this, "transporter", null);
|
|
163
|
-
}
|
|
164
|
-
};
|