@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.
Files changed (44) hide show
  1. package/README.md +1 -1
  2. package/cjs/config/index.js +1 -0
  3. package/cjs/config/message-keys.js +70 -0
  4. package/cjs/controllers/email-config.controller.js +1 -0
  5. package/cjs/controllers/email-send.controller.js +2 -0
  6. package/cjs/controllers/email-template.controller.js +3 -0
  7. package/cjs/modules/email.module.js +0 -2
  8. package/cjs/providers/email-factory.service.js +37 -12
  9. package/cjs/providers/mailgun-provider.js +10 -15
  10. package/cjs/providers/sendgrid-provider.js +10 -16
  11. package/cjs/providers/smtp-provider.js +7 -21
  12. package/cjs/services/email-datasource.provider.js +6 -2
  13. package/cjs/services/email-provider-config.service.js +1 -1
  14. package/cjs/services/email-send.service.js +77 -21
  15. package/cjs/services/email-template.service.js +1 -2
  16. package/config/index.d.ts +1 -0
  17. package/config/message-keys.d.ts +82 -0
  18. package/controllers/email-config.controller.d.ts +7 -7
  19. package/dtos/email-config.dto.d.ts +2 -2
  20. package/dtos/email-send.dto.d.ts +1 -1
  21. package/fesm/config/index.js +1 -0
  22. package/fesm/config/message-keys.js +47 -0
  23. package/fesm/controllers/email-config.controller.js +1 -0
  24. package/fesm/controllers/email-send.controller.js +2 -0
  25. package/fesm/controllers/email-template.controller.js +3 -0
  26. package/fesm/modules/email.module.js +1 -3
  27. package/fesm/providers/email-factory.service.js +38 -13
  28. package/fesm/providers/mailgun-provider.js +11 -16
  29. package/fesm/providers/sendgrid-provider.js +11 -17
  30. package/fesm/providers/smtp-provider.js +7 -21
  31. package/fesm/services/email-datasource.provider.js +7 -3
  32. package/fesm/services/email-provider-config.service.js +1 -1
  33. package/fesm/services/email-send.service.js +78 -22
  34. package/fesm/services/email-template.service.js +1 -2
  35. package/interfaces/email-config.interface.d.ts +1 -1
  36. package/interfaces/email-provider.interface.d.ts +2 -2
  37. package/interfaces/email-template.interface.d.ts +1 -1
  38. package/package.json +3 -3
  39. package/providers/email-factory.service.d.ts +0 -1
  40. package/providers/mailgun-provider.d.ts +0 -2
  41. package/providers/sendgrid-provider.d.ts +0 -2
  42. package/providers/smtp-provider.d.ts +0 -2
  43. package/services/email-datasource.provider.d.ts +0 -2
  44. 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
- const result = await provider.sendEmail({
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
- const result = await provider.sendEmail({
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) throw new _common.NotFoundException('Email configuration not found');
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) throw new _common.BadRequestException('Email configuration is inactive');
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) throw new _common.NotFoundException('No default email configuration found');
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('templateId or templateSlug is required');
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
@@ -1 +1,2 @@
1
1
  export * from './email.constants';
2
+ export * from './message-keys';
@@ -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/interfaces").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared/dtos").SingleResponseDto<EmailConfigResponseDto>>;
6
- insertMany(addDto: CreateEmailConfigDto[], user: import("@flusys/nestjs-shared/interfaces").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared/dtos").BulkResponseDto<EmailConfigResponseDto>>;
7
- getById(id: string, body: import("@flusys/nestjs-shared/dtos").GetByIdBodyDto, user: import("@flusys/nestjs-shared/interfaces").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared/dtos").SingleResponseDto<EmailConfigResponseDto>>;
8
- update(updateDto: UpdateEmailConfigDto, user: import("@flusys/nestjs-shared/interfaces").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared/dtos").SingleResponseDto<EmailConfigResponseDto>>;
9
- updateMany(updateDtos: UpdateEmailConfigDto[], user: import("@flusys/nestjs-shared/interfaces").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared/dtos").BulkResponseDto<EmailConfigResponseDto>>;
10
- getAll(filterAndPaginationDto: import("@flusys/nestjs-shared/dtos").FilterAndPaginationDto, user: import("@flusys/nestjs-shared/interfaces").ILoggedUserInfo | null, search?: string): Promise<import("@flusys/nestjs-shared/dtos").ListResponseDto<EmailConfigResponseDto>>;
11
- delete(deleteDto: import("@flusys/nestjs-shared/dtos").DeleteDto, user: import("@flusys/nestjs-shared/interfaces").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared/dtos").MessageResponseDto>;
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, any>;
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, any>;
19
+ config: Record<string, unknown>;
20
20
  fromEmail: string | null;
21
21
  fromName: string | null;
22
22
  isActive: boolean;
@@ -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, any>;
30
+ variables?: Record<string, unknown>;
31
31
  }
32
32
  export declare class TestEmailDto {
33
33
  emailConfigId: string;
@@ -1 +1,2 @@
1
1
  export * from './email.constants';
2
+ export * from './message-keys';
@@ -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 { Logger, Module } from '@nestjs/common';
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
- import { Injectable, InternalServerErrorException, Logger, NotFoundException } from '@nestjs/common';
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(`Email provider '${config.provider}' is not registered. Available: ${EmailProviderRegistry.getAll().join(', ')}`);
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
- this.logger.error(`Failed to create provider ${config.provider}:`, error);
41
- throw new InternalServerErrorException(`Failed to initialize email provider '${config.provider}': ${this.extractErrorMessage(error)}`);
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.logger.log('Cleaning up email provider connections...');
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(key, provider) {
75
+ async closeProvider(provider) {
60
76
  if (!provider.close) return;
61
77
  try {
62
78
  await provider.close();
63
- this.logger.debug(`Closed provider: ${key}`);
64
- } catch (err) {
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 { Logger } from '@nestjs/common';
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
- this.logger.log(`Mailgun Provider initialized for domain: ${config.domain}`);
32
- } catch (error) {
33
- this.logger.error('Failed to initialize Mailgun:', this.extractError(error));
34
- throw new Error('Mailgun initialization failed. Install: npm install mailgun.js form-data');
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 this.handleError('Mailgun send failed', error);
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
  }