@flusys/nestjs-email 3.0.0 → 4.0.0-rc
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 +1 -1
- package/cjs/config/index.js +1 -0
- package/cjs/config/message-keys.js +70 -0
- package/cjs/controllers/email-config.controller.js +1 -0
- package/cjs/controllers/email-send.controller.js +2 -0
- package/cjs/controllers/email-template.controller.js +3 -0
- package/cjs/modules/email.module.js +0 -2
- package/cjs/providers/email-factory.service.js +37 -12
- package/cjs/providers/mailgun-provider.js +10 -15
- package/cjs/providers/sendgrid-provider.js +10 -16
- package/cjs/providers/smtp-provider.js +7 -21
- package/cjs/services/email-datasource.provider.js +6 -2
- package/cjs/services/email-provider-config.service.js +1 -1
- package/cjs/services/email-send.service.js +77 -21
- package/cjs/services/email-template.service.js +1 -2
- package/config/index.d.ts +1 -0
- package/config/message-keys.d.ts +82 -0
- package/controllers/email-config.controller.d.ts +7 -7
- package/dtos/email-config.dto.d.ts +2 -2
- package/dtos/email-send.dto.d.ts +1 -1
- package/fesm/config/index.js +1 -0
- package/fesm/config/message-keys.js +47 -0
- package/fesm/controllers/email-config.controller.js +1 -0
- package/fesm/controllers/email-send.controller.js +2 -0
- package/fesm/controllers/email-template.controller.js +3 -0
- package/fesm/modules/email.module.js +1 -3
- package/fesm/providers/email-factory.service.js +38 -13
- package/fesm/providers/mailgun-provider.js +11 -16
- package/fesm/providers/sendgrid-provider.js +11 -17
- package/fesm/providers/smtp-provider.js +7 -21
- package/fesm/services/email-datasource.provider.js +7 -3
- package/fesm/services/email-provider-config.service.js +1 -1
- package/fesm/services/email-send.service.js +78 -22
- package/fesm/services/email-template.service.js +1 -2
- package/interfaces/email-config.interface.d.ts +1 -1
- package/interfaces/email-provider.interface.d.ts +2 -2
- package/interfaces/email-template.interface.d.ts +1 -1
- package/package.json +3 -3
- package/providers/email-factory.service.d.ts +0 -1
- package/providers/mailgun-provider.d.ts +0 -2
- package/providers/sendgrid-provider.d.ts +0 -2
- package/providers/smtp-provider.d.ts +0 -2
- package/services/email-datasource.provider.d.ts +0 -2
- package/services/email-send.service.d.ts +0 -2
|
@@ -8,9 +8,13 @@ Object.defineProperty(exports, "EmailSendService", {
|
|
|
8
8
|
return EmailSendService;
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
|
+
const _nestjsshared = require("@flusys/nestjs-shared");
|
|
12
|
+
const _config = require("../config");
|
|
13
|
+
const _interfaces = require("@flusys/nestjs-shared/interfaces");
|
|
11
14
|
const _utils = require("@flusys/nestjs-shared/utils");
|
|
12
15
|
const _common = require("@nestjs/common");
|
|
13
16
|
const _emailconfigservice = require("./email-config.service");
|
|
17
|
+
const _dtos = require("../dtos");
|
|
14
18
|
const _providers = require("../providers");
|
|
15
19
|
const _emailproviderconfigservice = require("./email-provider-config.service");
|
|
16
20
|
const _emailtemplateservice = require("./email-template.service");
|
|
@@ -47,7 +51,7 @@ let EmailSendService = class EmailSendService {
|
|
|
47
51
|
async sendEmail(dto, user) {
|
|
48
52
|
const { provider, config } = await this.getEmailProviderWithConfig(dto.emailConfigId, user);
|
|
49
53
|
const sender = this.resolveSender(dto, config);
|
|
50
|
-
|
|
54
|
+
return await provider.sendEmail({
|
|
51
55
|
to: dto.to,
|
|
52
56
|
cc: dto.cc,
|
|
53
57
|
bcc: dto.bcc,
|
|
@@ -58,15 +62,13 @@ let EmailSendService = class EmailSendService {
|
|
|
58
62
|
replyTo: dto.replyTo,
|
|
59
63
|
attachments: this.buildAttachments(dto.attachments)
|
|
60
64
|
});
|
|
61
|
-
this.logResult(dto.to, result);
|
|
62
|
-
return result;
|
|
63
65
|
}
|
|
64
66
|
async sendTemplateEmail(dto, user) {
|
|
65
67
|
const template = await this.resolveTemplate(dto, user);
|
|
66
68
|
const { subject, html, text } = this.buildTemplateContent(template, dto.variables);
|
|
67
69
|
const { provider, config } = await this.getEmailProviderWithConfig(dto.emailConfigId, user);
|
|
68
70
|
const sender = this.resolveSender(dto, config);
|
|
69
|
-
|
|
71
|
+
return await provider.sendEmail({
|
|
70
72
|
to: dto.to,
|
|
71
73
|
cc: dto.cc,
|
|
72
74
|
bcc: dto.bcc,
|
|
@@ -77,8 +79,6 @@ let EmailSendService = class EmailSendService {
|
|
|
77
79
|
replyTo: dto.replyTo,
|
|
78
80
|
attachments: this.buildAttachments(dto.attachments)
|
|
79
81
|
});
|
|
80
|
-
this.logResult(dto.to, result, template.slug);
|
|
81
|
-
return result;
|
|
82
82
|
}
|
|
83
83
|
async sendTestEmail(emailConfigId, recipient, user) {
|
|
84
84
|
const { provider, config } = await this.getEmailProviderWithConfig(emailConfigId, user);
|
|
@@ -94,7 +94,6 @@ let EmailSendService = class EmailSendService {
|
|
|
94
94
|
from: config.fromEmail || undefined,
|
|
95
95
|
fromName: config.fromName || this.emailConfigService.getDefaultFromName()
|
|
96
96
|
});
|
|
97
|
-
this.logResult(recipient, result);
|
|
98
97
|
return result;
|
|
99
98
|
}
|
|
100
99
|
// ─── Private: Provider & Config Resolution ──────────────────────────────────
|
|
@@ -111,14 +110,29 @@ let EmailSendService = class EmailSendService {
|
|
|
111
110
|
}
|
|
112
111
|
async resolveConfigById(id, user) {
|
|
113
112
|
const config = await this.emailProviderConfigService.findByIdDirect(id);
|
|
114
|
-
if (!config)
|
|
113
|
+
if (!config) {
|
|
114
|
+
throw new _common.NotFoundException({
|
|
115
|
+
message: 'Email configuration not found',
|
|
116
|
+
messageKey: _config.EMAIL_SEND_MESSAGES.CONFIG_NOT_FOUND
|
|
117
|
+
});
|
|
118
|
+
}
|
|
115
119
|
(0, _utils.validateCompanyOwnership)(config, user, this.emailConfigService.isCompanyFeatureEnabled(), 'Email configuration');
|
|
116
|
-
if (!config.isActive)
|
|
120
|
+
if (!config.isActive) {
|
|
121
|
+
throw new _common.BadRequestException({
|
|
122
|
+
message: 'Email configuration is inactive',
|
|
123
|
+
messageKey: _config.EMAIL_SEND_MESSAGES.CONFIG_INACTIVE
|
|
124
|
+
});
|
|
125
|
+
}
|
|
117
126
|
return config;
|
|
118
127
|
}
|
|
119
128
|
async resolveDefaultConfig(user) {
|
|
120
129
|
const config = await this.emailProviderConfigService.getDefaultConfig(user);
|
|
121
|
-
if (!config)
|
|
130
|
+
if (!config) {
|
|
131
|
+
throw new _common.NotFoundException({
|
|
132
|
+
message: 'No default email configuration found',
|
|
133
|
+
messageKey: _config.EMAIL_SEND_MESSAGES.CONFIG_DEFAULT_NOT_FOUND
|
|
134
|
+
});
|
|
135
|
+
}
|
|
122
136
|
return config;
|
|
123
137
|
}
|
|
124
138
|
// ─── Private: Template Resolution ───────────────────────────────────────────
|
|
@@ -129,10 +143,23 @@ let EmailSendService = class EmailSendService {
|
|
|
129
143
|
} else if (dto.templateSlug) {
|
|
130
144
|
template = await this.emailTemplateService.findBySlug(dto.templateSlug, user);
|
|
131
145
|
} else {
|
|
132
|
-
throw new _common.BadRequestException(
|
|
146
|
+
throw new _common.BadRequestException({
|
|
147
|
+
message: 'templateId or templateSlug is required',
|
|
148
|
+
messageKey: _config.EMAIL_SEND_MESSAGES.TEMPLATE_ID_OR_SLUG_REQUIRED
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
if (!template) {
|
|
152
|
+
throw new _common.NotFoundException({
|
|
153
|
+
message: 'Email template not found',
|
|
154
|
+
messageKey: _config.EMAIL_SEND_MESSAGES.TEMPLATE_NOT_FOUND
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
if (!template.isActive) {
|
|
158
|
+
throw new _common.BadRequestException({
|
|
159
|
+
message: 'Email template is inactive',
|
|
160
|
+
messageKey: _config.EMAIL_SEND_MESSAGES.TEMPLATE_INACTIVE
|
|
161
|
+
});
|
|
133
162
|
}
|
|
134
|
-
if (!template) throw new _common.NotFoundException('Email template not found');
|
|
135
|
-
if (!template.isActive) throw new _common.BadRequestException('Email template is inactive');
|
|
136
163
|
(0, _utils.validateCompanyOwnership)(template, user, this.emailConfigService.isCompanyFeatureEnabled(), 'Email template');
|
|
137
164
|
return template;
|
|
138
165
|
}
|
|
@@ -173,12 +200,6 @@ let EmailSendService = class EmailSendService {
|
|
|
173
200
|
return varName in safeVars && safeVars[varName] !== undefined ? String(safeVars[varName]) : match;
|
|
174
201
|
});
|
|
175
202
|
}
|
|
176
|
-
logResult(to, result, templateSlug) {
|
|
177
|
-
const recipient = Array.isArray(to) ? to.join(', ') : to;
|
|
178
|
-
const status = result.success ? 'SUCCESS' : 'FAILED';
|
|
179
|
-
const message = templateSlug ? `Template email sent to ${recipient} using template "${templateSlug}": ${status}` : `Email sent to ${recipient}: ${status}`;
|
|
180
|
-
this.logger.log(message);
|
|
181
|
-
}
|
|
182
203
|
buildTestEmailHtml(safeConfig) {
|
|
183
204
|
return `
|
|
184
205
|
<div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
|
|
@@ -197,14 +218,49 @@ let EmailSendService = class EmailSendService {
|
|
|
197
218
|
_define_property(this, "emailConfigService", void 0);
|
|
198
219
|
_define_property(this, "emailProviderConfigService", void 0);
|
|
199
220
|
_define_property(this, "emailTemplateService", void 0);
|
|
200
|
-
_define_property(this, "logger", void 0);
|
|
201
221
|
this.emailFactory = emailFactory;
|
|
202
222
|
this.emailConfigService = emailConfigService;
|
|
203
223
|
this.emailProviderConfigService = emailProviderConfigService;
|
|
204
224
|
this.emailTemplateService = emailTemplateService;
|
|
205
|
-
this.logger = new _common.Logger(EmailSendService.name);
|
|
206
225
|
}
|
|
207
226
|
};
|
|
227
|
+
_ts_decorate([
|
|
228
|
+
(0, _nestjsshared.LogAction)({
|
|
229
|
+
action: 'email.send',
|
|
230
|
+
module: 'email'
|
|
231
|
+
}),
|
|
232
|
+
_ts_metadata("design:type", Function),
|
|
233
|
+
_ts_metadata("design:paramtypes", [
|
|
234
|
+
typeof _dtos.SendEmailDto === "undefined" ? Object : _dtos.SendEmailDto,
|
|
235
|
+
typeof _interfaces.ILoggedUserInfo === "undefined" ? Object : _interfaces.ILoggedUserInfo
|
|
236
|
+
]),
|
|
237
|
+
_ts_metadata("design:returntype", Promise)
|
|
238
|
+
], EmailSendService.prototype, "sendEmail", null);
|
|
239
|
+
_ts_decorate([
|
|
240
|
+
(0, _nestjsshared.LogAction)({
|
|
241
|
+
action: 'email.sendTemplate',
|
|
242
|
+
module: 'email'
|
|
243
|
+
}),
|
|
244
|
+
_ts_metadata("design:type", Function),
|
|
245
|
+
_ts_metadata("design:paramtypes", [
|
|
246
|
+
typeof _dtos.SendTemplateEmailDto === "undefined" ? Object : _dtos.SendTemplateEmailDto,
|
|
247
|
+
typeof _interfaces.ILoggedUserInfo === "undefined" ? Object : _interfaces.ILoggedUserInfo
|
|
248
|
+
]),
|
|
249
|
+
_ts_metadata("design:returntype", Promise)
|
|
250
|
+
], EmailSendService.prototype, "sendTemplateEmail", null);
|
|
251
|
+
_ts_decorate([
|
|
252
|
+
(0, _nestjsshared.LogAction)({
|
|
253
|
+
action: 'email.sendTest',
|
|
254
|
+
module: 'email'
|
|
255
|
+
}),
|
|
256
|
+
_ts_metadata("design:type", Function),
|
|
257
|
+
_ts_metadata("design:paramtypes", [
|
|
258
|
+
String,
|
|
259
|
+
String,
|
|
260
|
+
typeof _interfaces.ILoggedUserInfo === "undefined" ? Object : _interfaces.ILoggedUserInfo
|
|
261
|
+
]),
|
|
262
|
+
_ts_metadata("design:returntype", Promise)
|
|
263
|
+
], EmailSendService.prototype, "sendTestEmail", null);
|
|
208
264
|
EmailSendService = _ts_decorate([
|
|
209
265
|
(0, _common.Injectable)({
|
|
210
266
|
scope: _common.Scope.REQUEST
|
|
@@ -138,11 +138,10 @@ let EmailTemplateService = class EmailTemplateService extends _classes.RequestSc
|
|
|
138
138
|
});
|
|
139
139
|
if (existing && JSON.stringify(dto.schema) !== JSON.stringify(existing.schema)) {
|
|
140
140
|
entity.schemaVersion = existing.schemaVersion + 1;
|
|
141
|
-
this.logger.log(`Schema version incremented to ${entity.schemaVersion} for template ${updateDto.id}`);
|
|
142
141
|
}
|
|
143
142
|
}
|
|
144
143
|
constructor(cacheManager, utilsService, emailConfig, dataSourceProvider){
|
|
145
|
-
super('emailTemplate', null, cacheManager, utilsService, EmailTemplateService.name, true), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "emailConfig", void 0), _define_property(this, "dataSourceProvider", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.emailConfig = emailConfig, this.dataSourceProvider = dataSourceProvider;
|
|
144
|
+
super('emailTemplate', null, cacheManager, utilsService, EmailTemplateService.name, true, 'email'), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "emailConfig", void 0), _define_property(this, "dataSourceProvider", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.emailConfig = emailConfig, this.dataSourceProvider = dataSourceProvider;
|
|
146
145
|
}
|
|
147
146
|
};
|
|
148
147
|
EmailTemplateService = _ts_decorate([
|
package/config/index.d.ts
CHANGED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
export declare const EMAIL_CONFIG_MESSAGES: {
|
|
2
|
+
readonly CREATE_SUCCESS: "email.config.create.success";
|
|
3
|
+
readonly CREATE_MANY_SUCCESS: "email.config.create.many.success";
|
|
4
|
+
readonly GET_SUCCESS: "email.config.get.success";
|
|
5
|
+
readonly GET_ALL_SUCCESS: "email.config.get.all.success";
|
|
6
|
+
readonly UPDATE_SUCCESS: "email.config.update.success";
|
|
7
|
+
readonly UPDATE_MANY_SUCCESS: "email.config.update.many.success";
|
|
8
|
+
readonly DELETE_SUCCESS: "email.config.delete.success";
|
|
9
|
+
readonly RESTORE_SUCCESS: "email.config.restore.success";
|
|
10
|
+
readonly NOT_FOUND: "email.config.not.found";
|
|
11
|
+
readonly ACTIVE_SUCCESS: "email.config.active.success";
|
|
12
|
+
readonly TEST_SUCCESS: "email.config.test.success";
|
|
13
|
+
readonly TEST_FAILED: "email.config.test.failed";
|
|
14
|
+
};
|
|
15
|
+
export declare const EMAIL_TEMPLATE_MESSAGES: {
|
|
16
|
+
readonly CREATE_SUCCESS: "email.template.create.success";
|
|
17
|
+
readonly CREATE_MANY_SUCCESS: "email.template.create.many.success";
|
|
18
|
+
readonly GET_SUCCESS: "email.template.get.success";
|
|
19
|
+
readonly GET_ALL_SUCCESS: "email.template.get.all.success";
|
|
20
|
+
readonly UPDATE_SUCCESS: "email.template.update.success";
|
|
21
|
+
readonly UPDATE_MANY_SUCCESS: "email.template.update.many.success";
|
|
22
|
+
readonly DELETE_SUCCESS: "email.template.delete.success";
|
|
23
|
+
readonly RESTORE_SUCCESS: "email.template.restore.success";
|
|
24
|
+
readonly NOT_FOUND: "email.template.not.found";
|
|
25
|
+
readonly PREVIEW_SUCCESS: "email.template.preview.success";
|
|
26
|
+
};
|
|
27
|
+
export declare const EMAIL_SEND_MESSAGES: {
|
|
28
|
+
readonly SUCCESS: "email.send.success";
|
|
29
|
+
readonly FAILED: "email.send.failed";
|
|
30
|
+
readonly QUEUED: "email.send.queued";
|
|
31
|
+
readonly TEMPLATE_SUCCESS: "email.send.template.success";
|
|
32
|
+
readonly BULK_SUCCESS: "email.send.bulk.success";
|
|
33
|
+
readonly TEST_SUCCESS: "email.send.test.success";
|
|
34
|
+
readonly CONFIG_NOT_FOUND: "email.send.config.not.found";
|
|
35
|
+
readonly CONFIG_INACTIVE: "email.send.config.inactive";
|
|
36
|
+
readonly CONFIG_DEFAULT_NOT_FOUND: "email.send.config.default.not.found";
|
|
37
|
+
readonly TEMPLATE_NOT_FOUND: "email.send.template.not.found";
|
|
38
|
+
readonly TEMPLATE_INACTIVE: "email.send.template.inactive";
|
|
39
|
+
readonly TEMPLATE_ID_OR_SLUG_REQUIRED: "email.send.template.id.or.slug.required";
|
|
40
|
+
};
|
|
41
|
+
export declare const EMAIL_MODULE_MESSAGES: {
|
|
42
|
+
readonly EMAIL_CONFIG: {
|
|
43
|
+
readonly CREATE_SUCCESS: "email.config.create.success";
|
|
44
|
+
readonly CREATE_MANY_SUCCESS: "email.config.create.many.success";
|
|
45
|
+
readonly GET_SUCCESS: "email.config.get.success";
|
|
46
|
+
readonly GET_ALL_SUCCESS: "email.config.get.all.success";
|
|
47
|
+
readonly UPDATE_SUCCESS: "email.config.update.success";
|
|
48
|
+
readonly UPDATE_MANY_SUCCESS: "email.config.update.many.success";
|
|
49
|
+
readonly DELETE_SUCCESS: "email.config.delete.success";
|
|
50
|
+
readonly RESTORE_SUCCESS: "email.config.restore.success";
|
|
51
|
+
readonly NOT_FOUND: "email.config.not.found";
|
|
52
|
+
readonly ACTIVE_SUCCESS: "email.config.active.success";
|
|
53
|
+
readonly TEST_SUCCESS: "email.config.test.success";
|
|
54
|
+
readonly TEST_FAILED: "email.config.test.failed";
|
|
55
|
+
};
|
|
56
|
+
readonly EMAIL_TEMPLATE: {
|
|
57
|
+
readonly CREATE_SUCCESS: "email.template.create.success";
|
|
58
|
+
readonly CREATE_MANY_SUCCESS: "email.template.create.many.success";
|
|
59
|
+
readonly GET_SUCCESS: "email.template.get.success";
|
|
60
|
+
readonly GET_ALL_SUCCESS: "email.template.get.all.success";
|
|
61
|
+
readonly UPDATE_SUCCESS: "email.template.update.success";
|
|
62
|
+
readonly UPDATE_MANY_SUCCESS: "email.template.update.many.success";
|
|
63
|
+
readonly DELETE_SUCCESS: "email.template.delete.success";
|
|
64
|
+
readonly RESTORE_SUCCESS: "email.template.restore.success";
|
|
65
|
+
readonly NOT_FOUND: "email.template.not.found";
|
|
66
|
+
readonly PREVIEW_SUCCESS: "email.template.preview.success";
|
|
67
|
+
};
|
|
68
|
+
readonly EMAIL_SEND: {
|
|
69
|
+
readonly SUCCESS: "email.send.success";
|
|
70
|
+
readonly FAILED: "email.send.failed";
|
|
71
|
+
readonly QUEUED: "email.send.queued";
|
|
72
|
+
readonly TEMPLATE_SUCCESS: "email.send.template.success";
|
|
73
|
+
readonly BULK_SUCCESS: "email.send.bulk.success";
|
|
74
|
+
readonly TEST_SUCCESS: "email.send.test.success";
|
|
75
|
+
readonly CONFIG_NOT_FOUND: "email.send.config.not.found";
|
|
76
|
+
readonly CONFIG_INACTIVE: "email.send.config.inactive";
|
|
77
|
+
readonly CONFIG_DEFAULT_NOT_FOUND: "email.send.config.default.not.found";
|
|
78
|
+
readonly TEMPLATE_NOT_FOUND: "email.send.template.not.found";
|
|
79
|
+
readonly TEMPLATE_INACTIVE: "email.send.template.inactive";
|
|
80
|
+
readonly TEMPLATE_ID_OR_SLUG_REQUIRED: "email.send.template.id.or.slug.required";
|
|
81
|
+
};
|
|
82
|
+
};
|
|
@@ -2,13 +2,13 @@ import { CreateEmailConfigDto, EmailConfigResponseDto, UpdateEmailConfigDto } fr
|
|
|
2
2
|
import { EmailProviderConfigService } from '../services';
|
|
3
3
|
declare const EmailConfigController_base: abstract new (service: EmailProviderConfigService) => {
|
|
4
4
|
service: EmailProviderConfigService;
|
|
5
|
-
insert(addDto: CreateEmailConfigDto, user: import("@flusys/nestjs-shared
|
|
6
|
-
insertMany(addDto: CreateEmailConfigDto[], user: import("@flusys/nestjs-shared
|
|
7
|
-
getById(id: string, body: import("@flusys/nestjs-shared
|
|
8
|
-
update(updateDto: UpdateEmailConfigDto, user: import("@flusys/nestjs-shared
|
|
9
|
-
updateMany(updateDtos: UpdateEmailConfigDto[], user: import("@flusys/nestjs-shared
|
|
10
|
-
getAll(filterAndPaginationDto: import("@flusys/nestjs-shared
|
|
11
|
-
delete(deleteDto: import("@flusys/nestjs-shared
|
|
5
|
+
insert(addDto: CreateEmailConfigDto, user: import("@flusys/nestjs-shared").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").SingleResponseDto<EmailConfigResponseDto>>;
|
|
6
|
+
insertMany(addDto: CreateEmailConfigDto[], user: import("@flusys/nestjs-shared").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").BulkResponseDto<EmailConfigResponseDto>>;
|
|
7
|
+
getById(id: string, body: import("@flusys/nestjs-shared").GetByIdBodyDto, user: import("@flusys/nestjs-shared").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").SingleResponseDto<EmailConfigResponseDto>>;
|
|
8
|
+
update(updateDto: UpdateEmailConfigDto, user: import("@flusys/nestjs-shared").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").SingleResponseDto<EmailConfigResponseDto>>;
|
|
9
|
+
updateMany(updateDtos: UpdateEmailConfigDto[], user: import("@flusys/nestjs-shared").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").BulkResponseDto<EmailConfigResponseDto>>;
|
|
10
|
+
getAll(filterAndPaginationDto: import("@flusys/nestjs-shared").FilterAndPaginationDto, user: import("@flusys/nestjs-shared").ILoggedUserInfo | null, search?: string): Promise<import("@flusys/nestjs-shared").ListResponseDto<EmailConfigResponseDto>>;
|
|
11
|
+
delete(deleteDto: import("@flusys/nestjs-shared").DeleteDto, user: import("@flusys/nestjs-shared").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").MessageResponseDto>;
|
|
12
12
|
};
|
|
13
13
|
export declare class EmailConfigController extends EmailConfigController_base {
|
|
14
14
|
emailConfigService: EmailProviderConfigService;
|
|
@@ -3,7 +3,7 @@ import { EmailProviderTypeEnum } from '../enums';
|
|
|
3
3
|
export declare class CreateEmailConfigDto {
|
|
4
4
|
name: string;
|
|
5
5
|
provider: EmailProviderTypeEnum;
|
|
6
|
-
config: Record<string,
|
|
6
|
+
config: Record<string, unknown>;
|
|
7
7
|
fromEmail?: string;
|
|
8
8
|
fromName?: string;
|
|
9
9
|
isActive?: boolean;
|
|
@@ -16,7 +16,7 @@ export declare class UpdateEmailConfigDto extends UpdateEmailConfigDto_base {
|
|
|
16
16
|
export declare class EmailConfigResponseDto extends IdentityResponseDto {
|
|
17
17
|
name: string;
|
|
18
18
|
provider: EmailProviderTypeEnum;
|
|
19
|
-
config: Record<string,
|
|
19
|
+
config: Record<string, unknown>;
|
|
20
20
|
fromEmail: string | null;
|
|
21
21
|
fromName: string | null;
|
|
22
22
|
isActive: boolean;
|
package/dtos/email-send.dto.d.ts
CHANGED
|
@@ -27,7 +27,7 @@ export declare class SendEmailDto extends BaseEmailDto {
|
|
|
27
27
|
export declare class SendTemplateEmailDto extends BaseEmailDto {
|
|
28
28
|
templateId?: string;
|
|
29
29
|
templateSlug?: string;
|
|
30
|
-
variables?: Record<string,
|
|
30
|
+
variables?: Record<string, unknown>;
|
|
31
31
|
}
|
|
32
32
|
export declare class TestEmailDto {
|
|
33
33
|
emailConfigId: string;
|
package/fesm/config/index.js
CHANGED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// ==================== EMAIL MODULE MESSAGE KEYS ====================
|
|
2
|
+
export const EMAIL_CONFIG_MESSAGES = {
|
|
3
|
+
CREATE_SUCCESS: 'email.config.create.success',
|
|
4
|
+
CREATE_MANY_SUCCESS: 'email.config.create.many.success',
|
|
5
|
+
GET_SUCCESS: 'email.config.get.success',
|
|
6
|
+
GET_ALL_SUCCESS: 'email.config.get.all.success',
|
|
7
|
+
UPDATE_SUCCESS: 'email.config.update.success',
|
|
8
|
+
UPDATE_MANY_SUCCESS: 'email.config.update.many.success',
|
|
9
|
+
DELETE_SUCCESS: 'email.config.delete.success',
|
|
10
|
+
RESTORE_SUCCESS: 'email.config.restore.success',
|
|
11
|
+
NOT_FOUND: 'email.config.not.found',
|
|
12
|
+
ACTIVE_SUCCESS: 'email.config.active.success',
|
|
13
|
+
TEST_SUCCESS: 'email.config.test.success',
|
|
14
|
+
TEST_FAILED: 'email.config.test.failed'
|
|
15
|
+
};
|
|
16
|
+
export const EMAIL_TEMPLATE_MESSAGES = {
|
|
17
|
+
CREATE_SUCCESS: 'email.template.create.success',
|
|
18
|
+
CREATE_MANY_SUCCESS: 'email.template.create.many.success',
|
|
19
|
+
GET_SUCCESS: 'email.template.get.success',
|
|
20
|
+
GET_ALL_SUCCESS: 'email.template.get.all.success',
|
|
21
|
+
UPDATE_SUCCESS: 'email.template.update.success',
|
|
22
|
+
UPDATE_MANY_SUCCESS: 'email.template.update.many.success',
|
|
23
|
+
DELETE_SUCCESS: 'email.template.delete.success',
|
|
24
|
+
RESTORE_SUCCESS: 'email.template.restore.success',
|
|
25
|
+
NOT_FOUND: 'email.template.not.found',
|
|
26
|
+
PREVIEW_SUCCESS: 'email.template.preview.success'
|
|
27
|
+
};
|
|
28
|
+
export const EMAIL_SEND_MESSAGES = {
|
|
29
|
+
SUCCESS: 'email.send.success',
|
|
30
|
+
FAILED: 'email.send.failed',
|
|
31
|
+
QUEUED: 'email.send.queued',
|
|
32
|
+
TEMPLATE_SUCCESS: 'email.send.template.success',
|
|
33
|
+
BULK_SUCCESS: 'email.send.bulk.success',
|
|
34
|
+
TEST_SUCCESS: 'email.send.test.success',
|
|
35
|
+
CONFIG_NOT_FOUND: 'email.send.config.not.found',
|
|
36
|
+
CONFIG_INACTIVE: 'email.send.config.inactive',
|
|
37
|
+
CONFIG_DEFAULT_NOT_FOUND: 'email.send.config.default.not.found',
|
|
38
|
+
TEMPLATE_NOT_FOUND: 'email.send.template.not.found',
|
|
39
|
+
TEMPLATE_INACTIVE: 'email.send.template.inactive',
|
|
40
|
+
TEMPLATE_ID_OR_SLUG_REQUIRED: 'email.send.template.id.or.slug.required'
|
|
41
|
+
};
|
|
42
|
+
// Aggregated export for backward compatibility
|
|
43
|
+
export const EMAIL_MODULE_MESSAGES = {
|
|
44
|
+
EMAIL_CONFIG: EMAIL_CONFIG_MESSAGES,
|
|
45
|
+
EMAIL_TEMPLATE: EMAIL_TEMPLATE_MESSAGES,
|
|
46
|
+
EMAIL_SEND: EMAIL_SEND_MESSAGES
|
|
47
|
+
};
|
|
@@ -31,6 +31,7 @@ import { ApiTags } from '@nestjs/swagger';
|
|
|
31
31
|
import { CreateEmailConfigDto, EmailConfigResponseDto, UpdateEmailConfigDto } from '../dtos';
|
|
32
32
|
import { EmailProviderConfigService } from '../services';
|
|
33
33
|
export class EmailConfigController extends createApiController(CreateEmailConfigDto, UpdateEmailConfigDto, EmailConfigResponseDto, {
|
|
34
|
+
entityName: 'emailConfig',
|
|
34
35
|
security: {
|
|
35
36
|
insert: {
|
|
36
37
|
level: 'permission',
|
|
@@ -25,6 +25,7 @@ function _ts_param(paramIndex, decorator) {
|
|
|
25
25
|
decorator(target, key, paramIndex);
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
|
+
import { EMAIL_SEND_MESSAGES } from '../config';
|
|
28
29
|
import { CurrentUser, RequirePermission } from '@flusys/nestjs-shared/decorators';
|
|
29
30
|
import { JwtAuthGuard } from '@flusys/nestjs-shared/guards';
|
|
30
31
|
import { ILoggedUserInfo } from '@flusys/nestjs-shared/interfaces';
|
|
@@ -49,6 +50,7 @@ export class EmailSendController {
|
|
|
49
50
|
return {
|
|
50
51
|
success: result.success,
|
|
51
52
|
message: result.success ? `${label} sent successfully` : `Failed to send ${label.toLowerCase()}`,
|
|
53
|
+
messageKey: result.success ? EMAIL_SEND_MESSAGES.SUCCESS : EMAIL_SEND_MESSAGES.FAILED,
|
|
52
54
|
data: {
|
|
53
55
|
success: result.success,
|
|
54
56
|
messageId: result.messageId,
|
|
@@ -26,6 +26,7 @@ function _ts_param(paramIndex, decorator) {
|
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
import { createApiController, EMAIL_TEMPLATE_PERMISSIONS } from '@flusys/nestjs-shared/classes';
|
|
29
|
+
import { EMAIL_TEMPLATE_MESSAGES } from '../config';
|
|
29
30
|
import { CurrentUser, RequirePermission } from '@flusys/nestjs-shared/decorators';
|
|
30
31
|
import { JwtAuthGuard } from '@flusys/nestjs-shared/guards';
|
|
31
32
|
import { ILoggedUserInfo } from '@flusys/nestjs-shared/interfaces';
|
|
@@ -34,6 +35,7 @@ import { ApiBearerAuth, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagg
|
|
|
34
35
|
import { CreateEmailTemplateDto, EmailTemplateResponseDto, UpdateEmailTemplateDto } from '../dtos';
|
|
35
36
|
import { EmailTemplateService } from '../services';
|
|
36
37
|
export class EmailTemplateController extends createApiController(CreateEmailTemplateDto, UpdateEmailTemplateDto, EmailTemplateResponseDto, {
|
|
38
|
+
entityName: 'emailTemplate',
|
|
37
39
|
security: {
|
|
38
40
|
insert: {
|
|
39
41
|
level: 'permission',
|
|
@@ -84,6 +86,7 @@ export class EmailTemplateController extends createApiController(CreateEmailTemp
|
|
|
84
86
|
return {
|
|
85
87
|
success: true,
|
|
86
88
|
message: 'Template retrieved',
|
|
89
|
+
messageKey: EMAIL_TEMPLATE_MESSAGES.GET_SUCCESS,
|
|
87
90
|
data: data ?? undefined
|
|
88
91
|
};
|
|
89
92
|
}
|
|
@@ -5,13 +5,12 @@ function _ts_decorate(decorators, target, key, desc) {
|
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
}
|
|
7
7
|
import { CacheModule, UtilsModule } from '@flusys/nestjs-shared/modules';
|
|
8
|
-
import {
|
|
8
|
+
import { Module } from '@nestjs/common';
|
|
9
9
|
import { EMAIL_MODULE_OPTIONS } from '../config/email.constants';
|
|
10
10
|
import { EmailConfigController, EmailSendController, EmailTemplateController } from '../controllers';
|
|
11
11
|
import { EmailProviderTypeEnum } from '../enums';
|
|
12
12
|
import { EmailFactoryService, EmailProviderRegistry, MailgunProvider, SendGridProvider, SmtpProvider } from '../providers';
|
|
13
13
|
import { EmailConfigService, EmailDataSourceProvider, EmailProviderConfigService, EmailSendService, EmailTemplateService } from '../services';
|
|
14
|
-
const logger = new Logger('EmailModule');
|
|
15
14
|
const CONTROLLERS = [
|
|
16
15
|
EmailConfigController,
|
|
17
16
|
EmailTemplateController,
|
|
@@ -28,7 +27,6 @@ const EXPORTED_SERVICES = [
|
|
|
28
27
|
EmailProviderRegistry.register(EmailProviderTypeEnum.SMTP, SmtpProvider);
|
|
29
28
|
EmailProviderRegistry.register(EmailProviderTypeEnum.SENDGRID, SendGridProvider);
|
|
30
29
|
EmailProviderRegistry.register(EmailProviderTypeEnum.MAILGUN, MailgunProvider);
|
|
31
|
-
logger.log('Registered built-in email providers: SMTP, SendGrid, Mailgun');
|
|
32
30
|
export class EmailModule {
|
|
33
31
|
static forRoot(options) {
|
|
34
32
|
return {
|
|
@@ -17,8 +17,14 @@ function _ts_decorate(decorators, target, key, desc) {
|
|
|
17
17
|
else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
18
18
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
19
19
|
}
|
|
20
|
-
|
|
20
|
+
function _ts_metadata(k, v) {
|
|
21
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
22
|
+
}
|
|
23
|
+
import { LogAction, SYSTEM_MESSAGES } from '@flusys/nestjs-shared';
|
|
24
|
+
import { EMAIL_SEND_MESSAGES } from '../config';
|
|
25
|
+
import { Injectable, InternalServerErrorException, NotFoundException } from '@nestjs/common';
|
|
21
26
|
import { createHash } from 'crypto';
|
|
27
|
+
import { IEmailProviderConfig } from '../interfaces';
|
|
22
28
|
import { EmailProviderRegistry } from './email-provider.registry';
|
|
23
29
|
export class EmailFactoryService {
|
|
24
30
|
// ─── Public API ─────────────────────────────────────────────────────────────
|
|
@@ -28,26 +34,36 @@ export class EmailFactoryService {
|
|
|
28
34
|
if (cached) return cached;
|
|
29
35
|
const ProviderClass = EmailProviderRegistry.get(config.provider);
|
|
30
36
|
if (!ProviderClass) {
|
|
31
|
-
throw new NotFoundException(
|
|
37
|
+
throw new NotFoundException({
|
|
38
|
+
message: `Email provider '${config.provider}' is not registered`,
|
|
39
|
+
messageKey: EMAIL_SEND_MESSAGES.CONFIG_NOT_FOUND,
|
|
40
|
+
messageParams: {
|
|
41
|
+
provider: config.provider,
|
|
42
|
+
available: EmailProviderRegistry.getAll().join(', ')
|
|
43
|
+
}
|
|
44
|
+
});
|
|
32
45
|
}
|
|
33
46
|
try {
|
|
34
47
|
const instance = new ProviderClass();
|
|
35
48
|
await instance.initialize?.(config.config);
|
|
36
49
|
this.providerCache.set(cacheKey, instance);
|
|
37
|
-
this.logger.log(`Created email provider: ${config.provider} (key: ${cacheKey})`);
|
|
38
50
|
return instance;
|
|
39
51
|
} catch (error) {
|
|
40
|
-
|
|
41
|
-
|
|
52
|
+
throw new InternalServerErrorException({
|
|
53
|
+
message: `Failed to initialize email provider '${config.provider}'`,
|
|
54
|
+
messageKey: SYSTEM_MESSAGES.SERVICE_NOT_AVAILABLE,
|
|
55
|
+
messageParams: {
|
|
56
|
+
provider: config.provider,
|
|
57
|
+
error: this.extractErrorMessage(error)
|
|
58
|
+
}
|
|
59
|
+
});
|
|
42
60
|
}
|
|
43
61
|
}
|
|
44
62
|
// ─── Lifecycle ──────────────────────────────────────────────────────────────
|
|
45
63
|
async onModuleDestroy() {
|
|
46
|
-
this.
|
|
47
|
-
const closePromises = Array.from(this.providerCache.entries()).map(([key, provider])=>this.closeProvider(key, provider));
|
|
64
|
+
const closePromises = Array.from(this.providerCache.entries()).map(([, provider])=>this.closeProvider(provider));
|
|
48
65
|
await Promise.allSettled(closePromises);
|
|
49
66
|
this.providerCache.clear();
|
|
50
|
-
this.logger.log('Email provider cleanup complete');
|
|
51
67
|
}
|
|
52
68
|
// ─── Private Helpers ────────────────────────────────────────────────────────
|
|
53
69
|
generateCacheKey(config) {
|
|
@@ -56,23 +72,32 @@ export class EmailFactoryService {
|
|
|
56
72
|
const hash = createHash('sha256').update(configString).digest('hex').substring(0, 16);
|
|
57
73
|
return `${config.provider}-${hash}`;
|
|
58
74
|
}
|
|
59
|
-
async closeProvider(
|
|
75
|
+
async closeProvider(provider) {
|
|
60
76
|
if (!provider.close) return;
|
|
61
77
|
try {
|
|
62
78
|
await provider.close();
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
this.logger.warn(`Failed to close provider ${key}: ${this.extractErrorMessage(err)}`);
|
|
79
|
+
} catch {
|
|
80
|
+
// Silent failure
|
|
66
81
|
}
|
|
67
82
|
}
|
|
68
83
|
extractErrorMessage(error) {
|
|
69
84
|
return error instanceof Error ? error.message : 'Unknown error';
|
|
70
85
|
}
|
|
71
86
|
constructor(){
|
|
72
|
-
_define_property(this, "logger", new Logger(EmailFactoryService.name));
|
|
73
87
|
_define_property(this, "providerCache", new Map());
|
|
74
88
|
}
|
|
75
89
|
}
|
|
90
|
+
_ts_decorate([
|
|
91
|
+
LogAction({
|
|
92
|
+
action: 'email.createProvider',
|
|
93
|
+
module: 'email'
|
|
94
|
+
}),
|
|
95
|
+
_ts_metadata("design:type", Function),
|
|
96
|
+
_ts_metadata("design:paramtypes", [
|
|
97
|
+
typeof IEmailProviderConfig === "undefined" ? Object : IEmailProviderConfig
|
|
98
|
+
]),
|
|
99
|
+
_ts_metadata("design:returntype", Promise)
|
|
100
|
+
], EmailFactoryService.prototype, "createProvider", null);
|
|
76
101
|
EmailFactoryService = _ts_decorate([
|
|
77
102
|
Injectable()
|
|
78
103
|
], EmailFactoryService);
|
|
@@ -11,7 +11,8 @@ function _define_property(obj, key, value) {
|
|
|
11
11
|
}
|
|
12
12
|
return obj;
|
|
13
13
|
}
|
|
14
|
-
import {
|
|
14
|
+
import { InternalServerErrorException } from '@nestjs/common';
|
|
15
|
+
import { SYSTEM_MESSAGES } from '@flusys/nestjs-shared/constants';
|
|
15
16
|
const MAILGUN_API_URL = 'https://api.mailgun.net';
|
|
16
17
|
const MAILGUN_EU_API_URL = 'https://api.eu.mailgun.net';
|
|
17
18
|
export class MailgunProvider {
|
|
@@ -28,10 +29,11 @@ export class MailgunProvider {
|
|
|
28
29
|
key: config.apiKey,
|
|
29
30
|
url
|
|
30
31
|
});
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
} catch {
|
|
33
|
+
throw new InternalServerErrorException({
|
|
34
|
+
message: 'Mailgun initialization failed. Install: npm install mailgun.js form-data',
|
|
35
|
+
messageKey: SYSTEM_MESSAGES.SDK_NOT_INSTALLED
|
|
36
|
+
});
|
|
35
37
|
}
|
|
36
38
|
}
|
|
37
39
|
async sendEmail(options) {
|
|
@@ -44,13 +46,15 @@ export class MailgunProvider {
|
|
|
44
46
|
try {
|
|
45
47
|
const messageData = this.buildMessageData(options);
|
|
46
48
|
const result = await this.client.messages.create(this.domain, messageData);
|
|
47
|
-
this.logger.log(`Email sent via Mailgun: ${result.id}`);
|
|
48
49
|
return {
|
|
49
50
|
success: true,
|
|
50
51
|
messageId: result.id
|
|
51
52
|
};
|
|
52
53
|
} catch (error) {
|
|
53
|
-
return
|
|
54
|
+
return {
|
|
55
|
+
success: false,
|
|
56
|
+
error: this.extractError(error)
|
|
57
|
+
};
|
|
54
58
|
}
|
|
55
59
|
}
|
|
56
60
|
async sendBulkEmails(options) {
|
|
@@ -95,16 +99,7 @@ export class MailgunProvider {
|
|
|
95
99
|
extractError(error) {
|
|
96
100
|
return error instanceof Error ? error.message : 'Unknown error';
|
|
97
101
|
}
|
|
98
|
-
handleError(context, error) {
|
|
99
|
-
const message = this.extractError(error);
|
|
100
|
-
this.logger.error(`${context}: ${message}`, error);
|
|
101
|
-
return {
|
|
102
|
-
success: false,
|
|
103
|
-
error: message
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
102
|
constructor(){
|
|
107
|
-
_define_property(this, "logger", new Logger(MailgunProvider.name));
|
|
108
103
|
_define_property(this, "client", null);
|
|
109
104
|
_define_property(this, "domain", null);
|
|
110
105
|
}
|