@b2y/email-service 1.0.9 → 1.1.0

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.
@@ -1,77 +1,84 @@
1
- // providers/AmazonSES.js
2
- const { SESClient, SendEmailCommand } = require('@aws-sdk/client-ses');
3
- const BaseProvider = require('./BaseProvider');
4
- const Config = require('../Config');
5
- const logger = require('../Logger');
6
- const StatusMessage = require('../constants/StatusMessageConstants');
7
- const { EmailProvider } = require('../enum/EmailProvider');
8
-
9
- class AmazonSESProvider extends BaseProvider {
10
- constructor() {
11
- super();
12
- this.client = new SESClient({
13
- region: Config.awsRegion,
14
- credentials: {
15
- accessKeyId: Config.awsAccessKeyId,
16
- secretAccessKey: Config.awsSecretAccessKey
17
- }
18
- });
19
- }
20
-
21
- async sendEmail(options) {
22
- try {
23
- this.validateEmailOptions(options);
24
-
25
- const toAddresses = this.formatRecipients(options.to);
26
- const ccAddresses = options.cc ? this.formatRecipients(options.cc) : [];
27
- const bccAddresses = options.bcc ? this.formatRecipients(options.bcc) : [];
28
-
29
- const params = {
30
- Source: options.from || Config.awsFromEmail,
31
- Destination: {
32
- ToAddresses: toAddresses,
33
- ...(ccAddresses.length > 0 && { CcAddresses: ccAddresses }),
34
- ...(bccAddresses.length > 0 && { BccAddresses: bccAddresses })
35
- },
36
- Message: {
37
- Subject: {
38
- Data: options.subject,
39
- Charset: 'UTF-8'
40
- },
41
- Body: {
42
- Html: {
43
- Data: options.html,
44
- Charset: 'UTF-8'
45
- }
46
- }
47
- }
48
- };
49
-
50
- // Add attachments if present (SES requires using SendRawEmail for attachments)
51
- if (options.attachments && options.attachments.length > 0) {
52
- logger.warn('SES provider: Attachments require SendRawEmail. Consider implementing raw email support.');
53
- }
54
-
55
- const command = new SendEmailCommand(params);
56
- const result = await this.client.send(command);
57
-
58
- logger.info('Email sent successfully via Amazon SES', {
59
- messageId: result.MessageId,
60
- recipients: { to: options.to, cc: options.cc, bcc: options.bcc },
61
- tenantId: options.tenantId
62
- });
63
-
64
- return {
65
- success: true,
66
- messageId: result.MessageId,
67
- provider: EmailProvider.SES,
68
- tenantId: options.tenantId
69
- };
70
- } catch (error) {
71
- logger.error(`Amazon SES failed to send email: ${error.message}`);
72
- throw new Error(`${StatusMessage.AMAZON_SES_SEND_ERROR}: ${error.message}`);
73
- }
74
- }
75
- }
76
-
1
+ // providers/AmazonSES.js
2
+ const { SESClient, SendEmailCommand } = require('@aws-sdk/client-ses');
3
+ const BaseProvider = require('./BaseProvider');
4
+ const Config = require('../Config');
5
+ const logger = require('../Logger');
6
+ const StatusMessage = require('../constants/StatusMessageConstants');
7
+ const { EmailProvider } = require('../enum/EmailProvider');
8
+
9
+ class AmazonSESProvider extends BaseProvider {
10
+ constructor() {
11
+ super();
12
+ this.client = new SESClient({
13
+ region: Config.awsRegion,
14
+ credentials: {
15
+ accessKeyId: Config.awsAccessKeyId,
16
+ secretAccessKey: Config.awsSecretAccessKey
17
+ }
18
+ });
19
+ }
20
+
21
+ async sendEmail(options) {
22
+ try {
23
+ this.validateEmailOptions(options);
24
+
25
+ const toAddresses = this.formatRecipients(options.to);
26
+ const ccAddresses = options.cc ? this.formatRecipients(options.cc) : [];
27
+ const bccAddresses = options.bcc ? this.formatRecipients(options.bcc) : [];
28
+
29
+
30
+ const fromAddress = this.formatFromAddress(
31
+ options.from || Config.awsFromEmail,
32
+ options.fromName || Config.fromName
33
+ );
34
+
35
+ const params = {
36
+ Source: fromAddress,
37
+ Destination: {
38
+ ToAddresses: toAddresses,
39
+ ...(ccAddresses.length > 0 && { CcAddresses: ccAddresses }),
40
+ ...(bccAddresses.length > 0 && { BccAddresses: bccAddresses })
41
+ },
42
+ Message: {
43
+ Subject: {
44
+ Data: options.subject,
45
+ Charset: 'UTF-8'
46
+ },
47
+ Body: {
48
+ Html: {
49
+ Data: options.html,
50
+ Charset: 'UTF-8'
51
+ }
52
+ }
53
+ }
54
+ };
55
+
56
+ // Add attachments if present (SES requires using SendRawEmail for attachments)
57
+ if (options.attachments && options.attachments.length > 0) {
58
+ logger.warn('SES provider: Attachments require SendRawEmail. Consider implementing raw email support.');
59
+ }
60
+
61
+ const command = new SendEmailCommand(params);
62
+ const result = await this.client.send(command);
63
+
64
+ logger.info('Email sent successfully via Amazon SES', {
65
+ messageId: result.MessageId,
66
+ recipients: { to: options.to, cc: options.cc, bcc: options.bcc },
67
+ tenantId: options.tenantId,
68
+ from: fromAddress
69
+ });
70
+
71
+ return {
72
+ success: true,
73
+ messageId: result.MessageId,
74
+ provider: EmailProvider.SES,
75
+ tenantId: options.tenantId
76
+ };
77
+ } catch (error) {
78
+ logger.error(`Amazon SES failed to send email: ${error.message}`);
79
+ throw new Error(`${StatusMessage.AMAZON_SES_SEND_ERROR}: ${error.message}`);
80
+ }
81
+ }
82
+ }
83
+
77
84
  module.exports = AmazonSESProvider;
@@ -1,74 +1,86 @@
1
- // providers/BaseProvider.js
2
- const logger = require('../Logger');
3
- const StatusMessage = require('../constants/StatusMessageConstants');
4
- class BaseProvider {
5
- constructor() {
6
- if (new.target === BaseProvider) {
7
- throw new Error(StatusMessage.CANNOT_INSTANTIATE_BASE);
8
- }
9
- }
10
-
11
- async sendEmail(options) {
12
- logger.error('sendEmail method not implemented in BaseProvider');
13
- throw new Error(StatusMessage.PROVIDER_NOT_IMPLEMENTED);
14
- }
15
-
16
- validateEmailOptions(options) {
17
- const { to, subject, html, from } = options;
18
-
19
- if (!to || (Array.isArray(to) && to.length === 0)) {
20
- throw new Error(StatusMessage.RECIPIENTS_REQUIRED);
21
- }
22
-
23
- if (!subject) {
24
- throw new Error(StatusMessage.SUBJECT_REQUIRED);
25
- }
26
-
27
- if (!html) {
28
- throw new Error(StatusMessage.HTML_CONTENT_REQUIRED);
29
- }
30
-
31
- return true;
32
- }
33
-
34
- formatRecipients(recipients) {
35
- if (!recipients) return [];
36
-
37
- if (typeof recipients === 'string') {
38
- return recipients.split(',').map(r => r.trim());
39
- }
40
-
41
- if (Array.isArray(recipients)) {
42
- return recipients;
43
- }
44
-
45
- return [];
46
- }
47
-
48
- buildMailOptions(options) {
49
- const { to, cc, bcc, subject, html, from, attachments } = options;
50
-
51
- const mailOptions = {
52
- from,
53
- to: this.formatRecipients(to),
54
- subject,
55
- html,
56
- };
57
-
58
- if (cc && cc.length > 0) {
59
- mailOptions.cc = this.formatRecipients(cc);
60
- }
61
-
62
- if (bcc && bcc.length > 0) {
63
- mailOptions.bcc = this.formatRecipients(bcc);
64
- }
65
-
66
- if (attachments && attachments.length > 0) {
67
- mailOptions.attachments = attachments;
68
- }
69
-
70
- return mailOptions;
71
- }
72
- }
73
-
1
+ // providers/BaseProvider.js
2
+ const logger = require('../Logger');
3
+ const StatusMessage = require('../constants/StatusMessageConstants');
4
+ const Config = require('../Config');
5
+
6
+ class BaseProvider {
7
+ constructor() {
8
+ if (new.target === BaseProvider) {
9
+ throw new Error(StatusMessage.CANNOT_INSTANTIATE_BASE);
10
+ }
11
+ }
12
+
13
+ async sendEmail(options) {
14
+ logger.error('sendEmail method not implemented in BaseProvider');
15
+ throw new Error(StatusMessage.PROVIDER_NOT_IMPLEMENTED);
16
+ }
17
+
18
+ validateEmailOptions(options) {
19
+ const { to, subject, html, from } = options;
20
+
21
+ if (!to || (Array.isArray(to) && to.length === 0)) {
22
+ throw new Error(StatusMessage.RECIPIENTS_REQUIRED);
23
+ }
24
+
25
+ if (!subject) {
26
+ throw new Error(StatusMessage.SUBJECT_REQUIRED);
27
+ }
28
+
29
+ if (!html) {
30
+ throw new Error(StatusMessage.HTML_CONTENT_REQUIRED);
31
+ }
32
+
33
+ return true;
34
+ }
35
+
36
+ formatRecipients(recipients) {
37
+ if (!recipients) return [];
38
+
39
+ if (typeof recipients === 'string') {
40
+ return recipients.split(',').map(r => r.trim());
41
+ }
42
+
43
+ if (Array.isArray(recipients)) {
44
+ return recipients;
45
+ }
46
+
47
+ return [];
48
+ }
49
+
50
+ formatFromAddress(email, name = null) {
51
+ const fromName = name || Config.fromName;
52
+ const fromEmail = email || Config.fromEmail;
53
+
54
+ if (!fromEmail) {
55
+ throw new Error('FROM_EMAIL is required');
56
+ }
57
+ return fromName ? `"${fromName}" <${fromEmail}>` : fromEmail;
58
+ }
59
+
60
+ buildMailOptions(options) {
61
+ const { to, cc, bcc, subject, html, from, fromName, attachments } = options;
62
+
63
+ const mailOptions = {
64
+ from: this.formatFromAddress(from, fromName),
65
+ to: this.formatRecipients(to),
66
+ subject,
67
+ html,
68
+ };
69
+
70
+ if (cc && cc.length > 0) {
71
+ mailOptions.cc = this.formatRecipients(cc);
72
+ }
73
+
74
+ if (bcc && bcc.length > 0) {
75
+ mailOptions.bcc = this.formatRecipients(bcc);
76
+ }
77
+
78
+ if (attachments && attachments.length > 0) {
79
+ mailOptions.attachments = attachments;
80
+ }
81
+
82
+ return mailOptions;
83
+ }
84
+ }
85
+
74
86
  module.exports = BaseProvider;
@@ -1,52 +1,53 @@
1
- // providers/NodeMailerProvider.js
2
- const nodemailer = require('nodemailer');
3
- const BaseProvider = require('./BaseProvider');
4
- const Config = require('../Config');
5
- const logger = require('../Logger');
6
- const StatusMessage = require('../constants/StatusMessageConstants');
7
- const { EmailProvider } = require('../enum/EmailProvider');
8
-
9
- class NodeMailerProvider extends BaseProvider {
10
- constructor() {
11
- super();
12
- this.transporter = nodemailer.createTransport({
13
- service: Config.emailService,
14
- host: Config.emailHost,
15
- port: Config.smtpPort,
16
- secure: Config.smtpPort,
17
- auth: {
18
- user: Config.emailUser,
19
- pass: Config.emailPass,
20
- },
21
- });
22
- }
23
-
24
- async sendEmail(options) {
25
- try {
26
- this.validateEmailOptions(options);
27
- const mailOptions = this.buildMailOptions({
28
- ...options,
29
- from: options.from || Config.emailUser
30
- });
31
- const result = await this.transporter.sendMail(mailOptions);
32
-
33
- logger.info('Email sent successfully via Nodemailer', {
34
- messageId: result.messageId,
35
- recipients: { to: options.to, cc: options.cc, bcc: options.bcc },
36
- tenantId: options.tenantId
37
- });
38
-
39
- return {
40
- success: true,
41
- messageId: result.messageId,
42
- provider: EmailProvider.NODE_MAILER,
43
- tenantId: options.tenantId
44
- };
45
- } catch (error) {
46
- logger.error(`Nodemailer failed to send email: ${error.message}`);
47
- throw new Error(`${StatusMessage.NODEMAILER_SEND_ERROR}: ${error.message}`);
48
- }
49
- }
50
- }
51
-
1
+ // providers/NodeMailerProvider.js
2
+ const nodemailer = require('nodemailer');
3
+ const BaseProvider = require('./BaseProvider');
4
+ const Config = require('../Config');
5
+ const logger = require('../Logger');
6
+ const StatusMessage = require('../constants/StatusMessageConstants');
7
+ const { EmailProvider } = require('../enum/EmailProvider');
8
+
9
+ class NodeMailerProvider extends BaseProvider {
10
+ constructor() {
11
+ super();
12
+ this.transporter = nodemailer.createTransport({
13
+ host: Config.emailHost,
14
+ port: Config.smtpPort,
15
+ secure: Config.smtpPort,
16
+ auth: {
17
+ user: Config.emailUser,
18
+ pass: Config.emailPass,
19
+ },
20
+ });
21
+ }
22
+
23
+ async sendEmail(options) {
24
+ try {
25
+ this.validateEmailOptions(options);
26
+ const mailOptions = this.buildMailOptions({
27
+ ...options,
28
+ from: options.from || Config.fromEmail,
29
+ fromName: options.fromName || Config.fromName
30
+ });
31
+ const result = await this.transporter.sendMail(mailOptions);
32
+
33
+ logger.info('Email sent successfully via Nodemailer', {
34
+ messageId: result.messageId,
35
+ recipients: { to: options.to, cc: options.cc, bcc: options.bcc },
36
+ tenantId: options.tenantId,
37
+ from: mailOptions.from
38
+ });
39
+
40
+ return {
41
+ success: true,
42
+ messageId: result.messageId,
43
+ provider: EmailProvider.NODE_MAILER,
44
+ tenantId: options.tenantId
45
+ };
46
+ } catch (error) {
47
+ logger.error(`Nodemailer failed to send email: ${error.message}`);
48
+ throw new Error(`${StatusMessage.NODEMAILER_SEND_ERROR}: ${error.message}`);
49
+ }
50
+ }
51
+ }
52
+
52
53
  module.exports = NodeMailerProvider;
@@ -1,62 +1,62 @@
1
- // providers/PostmarkProvider.js
2
- const postmark = require('postmark');
3
- const BaseProvider = require('./BaseProvider');
4
- const Config = require('../Config');
5
- const logger = require('../Logger');
6
- const StatusMessage = require('../constants/StatusMessageConstants');
7
- const { EmailProvider } = require('../enum/EmailProvider');
8
-
9
- class PostmarkProvider extends BaseProvider {
10
- constructor() {
11
- super();
12
- this.client = new postmark.Client(Config.postmarkApiKey);
13
- }
14
-
15
- async sendEmail(options) {
16
- try {
17
- this.validateEmailOptions(options);
18
- const mailOptions = {
19
- From: options.from || Config.postmarkFromEmail,
20
- To: this.formatRecipients(options.to).join(','),
21
- Subject: options.subject,
22
- HtmlBody: options.html,
23
- };
24
-
25
- if (options.cc && options.cc.length > 0) {
26
- mailOptions.Cc = this.formatRecipients(options.cc).join(',');
27
- }
28
-
29
- if (options.bcc && options.bcc.length > 0) {
30
- mailOptions.Bcc = this.formatRecipients(options.bcc).join(',');
31
- }
32
-
33
- if (options.attachments && options.attachments.length > 0) {
34
- mailOptions.Attachments = options.attachments.map(att => ({
35
- Name: att.filename,
36
- Content: att.content,
37
- ContentType: att.contentType
38
- }));
39
- }
40
-
41
- const result = await this.client.sendEmail(mailOptions);
42
-
43
- logger.info('Email sent successfully via Postmark', {
44
- messageId: result.MessageID,
45
- recipients: { to: options.to, cc: options.cc, bcc: options.bcc },
46
- tenantId: options.tenantId
47
- });
48
-
49
- return {
50
- success: true,
51
- messageId: result.MessageID,
52
- provider: EmailProvider.POSTMARK,
53
- tenantId: options.tenantId
54
- };
55
- } catch (error) {
56
- logger.error(`Postmark failed to send email: ${error.message}`);
57
- throw new Error(`${StatusMessage.POSTMARK_SEND_ERROR}: ${error.message}`);
58
- }
59
- }
60
- }
61
-
1
+ // providers/PostmarkProvider.js
2
+ const postmark = require('postmark');
3
+ const BaseProvider = require('./BaseProvider');
4
+ const Config = require('../Config');
5
+ const logger = require('../Logger');
6
+ const StatusMessage = require('../constants/StatusMessageConstants');
7
+ const { EmailProvider } = require('../enum/EmailProvider');
8
+
9
+ class PostmarkProvider extends BaseProvider {
10
+ constructor() {
11
+ super();
12
+ this.client = new postmark.Client(Config.postmarkApiKey);
13
+ }
14
+
15
+ async sendEmail(options) {
16
+ try {
17
+ this.validateEmailOptions(options);
18
+ const mailOptions = {
19
+ From: options.from || Config.postmarkFromEmail,
20
+ To: this.formatRecipients(options.to).join(','),
21
+ Subject: options.subject,
22
+ HtmlBody: options.html,
23
+ };
24
+
25
+ if (options.cc && options.cc.length > 0) {
26
+ mailOptions.Cc = this.formatRecipients(options.cc).join(',');
27
+ }
28
+
29
+ if (options.bcc && options.bcc.length > 0) {
30
+ mailOptions.Bcc = this.formatRecipients(options.bcc).join(',');
31
+ }
32
+
33
+ if (options.attachments && options.attachments.length > 0) {
34
+ mailOptions.Attachments = options.attachments.map(att => ({
35
+ Name: att.filename,
36
+ Content: att.content,
37
+ ContentType: att.contentType
38
+ }));
39
+ }
40
+
41
+ const result = await this.client.sendEmail(mailOptions);
42
+
43
+ logger.info('Email sent successfully via Postmark', {
44
+ messageId: result.MessageID,
45
+ recipients: { to: options.to, cc: options.cc, bcc: options.bcc },
46
+ tenantId: options.tenantId
47
+ });
48
+
49
+ return {
50
+ success: true,
51
+ messageId: result.MessageID,
52
+ provider: EmailProvider.POSTMARK,
53
+ tenantId: options.tenantId
54
+ };
55
+ } catch (error) {
56
+ logger.error(`Postmark failed to send email: ${error.message}`);
57
+ throw new Error(`${StatusMessage.POSTMARK_SEND_ERROR}: ${error.message}`);
58
+ }
59
+ }
60
+ }
61
+
62
62
  module.exports = PostmarkProvider;