@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.
- package/Config.js +40 -39
- package/Logger.js +5 -5
- package/README.md +18 -18
- package/constants/StatusMessageConstants.js +38 -38
- package/enum/EmailProvider.js +7 -7
- package/index.js +77 -77
- package/model/Connect.js +23 -23
- package/model/EmailTemplate.js +51 -51
- package/package.json +53 -53
- package/providers/AmazonSESProvider.js +83 -76
- package/providers/BaseProvider.js +85 -73
- package/providers/NodeMailerProvider.js +52 -51
- package/providers/PostmarkProvider.js +61 -61
- package/providers/SendgridProvider.js +60 -60
- package/service/EmailService.js +101 -98
- package/utils/TemplateEngine.js +98 -98
|
@@ -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
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
|
|
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
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
this.
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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;
|