Refactor EmailService to inject dependencies
This commit is contained in:
1 parent
ab0f4e49bc
commit
17ed90f76b
1 file changed
+123
-122
+123
-122
@@ -1,11 +1,6 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import nodemailer from "nodemailer";
|
||||
import pkg from "handlebars";
|
||||
const { compile } = pkg;
|
||||
import mjml2html from "mjml";
|
||||
import logger from "../utils/logger.js";
|
||||
import { fileURLToPath } from "url";
|
||||
import path from "path";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
@@ -15,128 +10,134 @@ const SERVICE_NAME = "EmailService";
|
||||
* Represents an email service that can load templates, build, and send emails.
|
||||
*/
|
||||
class EmailService {
|
||||
/**
|
||||
* Constructs an instance of the EmailService, initializing template loaders and the email transporter.
|
||||
*/
|
||||
constructor(settingsService) {
|
||||
this.settingsService = settingsService;
|
||||
/**
|
||||
* Loads an email template from the filesystem.
|
||||
*
|
||||
* @param {string} templateName - The name of the template to load.
|
||||
* @returns {Function} A compiled template function that can be used to generate HTML email content.
|
||||
*/
|
||||
this.loadTemplate = (templateName) => {
|
||||
try {
|
||||
const templatePath = path.join(
|
||||
__dirname,
|
||||
`../templates/${templateName}.mjml`
|
||||
);
|
||||
const templateContent = fs.readFileSync(templatePath, "utf8");
|
||||
return compile(templateContent);
|
||||
} catch (error) {
|
||||
logger.error("Error loading Email templates", {
|
||||
error,
|
||||
service: this.SERVICE_NAME,
|
||||
});
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Constructs an instance of the EmailService, initializing template loaders and the email transporter.
|
||||
* @param {Object} settingsService - The settings service to get email configuration.
|
||||
* @param {Object} fs - The file system module.
|
||||
* @param {Object} path - The path module.
|
||||
* @param {Function} compile - The Handlebars compile function.
|
||||
* @param {Function} mjml2html - The MJML to HTML conversion function.
|
||||
* @param {Object} nodemailer - The nodemailer module.
|
||||
* @param {Object} logger - The logger module.
|
||||
*/
|
||||
constructor(settingsService, fs, path, compile, mjml2html, nodemailer, logger) {
|
||||
this.settingsService = settingsService;
|
||||
this.fs = fs;
|
||||
this.path = path;
|
||||
this.compile = compile;
|
||||
this.mjml2html = mjml2html;
|
||||
this.nodemailer = nodemailer;
|
||||
this.logger = logger;
|
||||
|
||||
/**
|
||||
* A lookup object to access preloaded email templates.
|
||||
* @type {Object.<string, Function>}
|
||||
* TODO Load less used templates in their respective functions
|
||||
*/
|
||||
this.templateLookup = {
|
||||
welcomeEmailTemplate: this.loadTemplate("welcomeEmail"),
|
||||
employeeActivationTemplate: this.loadTemplate("employeeActivation"),
|
||||
noIncidentsThisWeekTemplate: this.loadTemplate("noIncidentsThisWeek"),
|
||||
serverIsDownTemplate: this.loadTemplate("serverIsDown"),
|
||||
serverIsUpTemplate: this.loadTemplate("serverIsUp"),
|
||||
passwordResetTemplate: this.loadTemplate("passwordReset"),
|
||||
};
|
||||
/**
|
||||
* Loads an email template from the filesystem.
|
||||
*
|
||||
* @param {string} templateName - The name of the template to load.
|
||||
* @returns {Function} A compiled template function that can be used to generate HTML email content.
|
||||
*/
|
||||
this.loadTemplate = (templateName) => {
|
||||
try {
|
||||
const templatePath = this.path.join(
|
||||
__dirname,
|
||||
`../templates/${templateName}.mjml`
|
||||
);
|
||||
const templateContent = this.fs.readFileSync(templatePath, "utf8");
|
||||
return this.compile(templateContent);
|
||||
} catch (error) {
|
||||
logger.error("Error loading Email templates", {
|
||||
error,
|
||||
service: this.SERVICE_NAME,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The email transporter used to send emails.
|
||||
* @type {Object}
|
||||
*/
|
||||
/**
|
||||
* A lookup object to access preloaded email templates.
|
||||
* @type {Object.<string, Function>}
|
||||
* TODO Load less used templates in their respective functions
|
||||
*/
|
||||
this.templateLookup = {
|
||||
welcomeEmailTemplate: this.loadTemplate("welcomeEmail"),
|
||||
employeeActivationTemplate: this.loadTemplate("employeeActivation"),
|
||||
noIncidentsThisWeekTemplate: this.loadTemplate("noIncidentsThisWeek"),
|
||||
serverIsDownTemplate: this.loadTemplate("serverIsDown"),
|
||||
serverIsUpTemplate: this.loadTemplate("serverIsUp"),
|
||||
passwordResetTemplate: this.loadTemplate("passwordReset"),
|
||||
};
|
||||
|
||||
const {
|
||||
systemEmailHost,
|
||||
systemEmailPort,
|
||||
systemEmailAddress,
|
||||
systemEmailPassword,
|
||||
} = this.settingsService.getSettings();
|
||||
/**
|
||||
* The email transporter used to send emails.
|
||||
* @type {Object}
|
||||
*/
|
||||
|
||||
const emailConfig = {
|
||||
host: systemEmailHost,
|
||||
port: systemEmailPort,
|
||||
secure: true,
|
||||
auth: {
|
||||
user: systemEmailAddress,
|
||||
pass: systemEmailPassword,
|
||||
},
|
||||
};
|
||||
const { systemEmailHost, systemEmailPort, systemEmailAddress, systemEmailPassword } =
|
||||
this.settingsService.getSettings();
|
||||
|
||||
this.transporter = nodemailer.createTransport(emailConfig);
|
||||
}
|
||||
const emailConfig = {
|
||||
host: systemEmailHost,
|
||||
port: systemEmailPort,
|
||||
secure: true,
|
||||
auth: {
|
||||
user: systemEmailAddress,
|
||||
pass: systemEmailPassword,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Asynchronously builds and sends an email using a specified template and context.
|
||||
*
|
||||
* @param {string} template - The name of the template to use for the email body.
|
||||
* @param {Object} context - The data context to render the template with.
|
||||
* @param {string} to - The recipient's email address.
|
||||
* @param {string} subject - The subject of the email.
|
||||
* @returns {Promise<string>} A promise that resolves to the messageId of the sent email.
|
||||
*/
|
||||
buildAndSendEmail = async (template, context, to, subject) => {
|
||||
const buildHtml = async (template, context) => {
|
||||
try {
|
||||
const mjml = this.templateLookup[template](context);
|
||||
const html = await mjml2html(mjml);
|
||||
return html.html;
|
||||
} catch (error) {
|
||||
logger.error("Error building Email HTML", {
|
||||
error,
|
||||
service: SERVICE_NAME,
|
||||
});
|
||||
}
|
||||
};
|
||||
this.transporter = this.nodemailer.createTransport(emailConfig);
|
||||
}
|
||||
|
||||
const sendEmail = async (to, subject, html) => {
|
||||
try {
|
||||
const info = await this.transporter.sendMail({
|
||||
to: to,
|
||||
subject: subject,
|
||||
html: html,
|
||||
});
|
||||
return info;
|
||||
} catch (error) {
|
||||
logger.error("Error sending Email", {
|
||||
error,
|
||||
service: SERVICE_NAME,
|
||||
});
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Asynchronously builds and sends an email using a specified template and context.
|
||||
*
|
||||
* @param {string} template - The name of the template to use for the email body.
|
||||
* @param {Object} context - The data context to render the template with.
|
||||
* @param {string} to - The recipient's email address.
|
||||
* @param {string} subject - The subject of the email.
|
||||
* @returns {Promise<string>} A promise that resolves to the messageId of the sent email.
|
||||
*/
|
||||
buildAndSendEmail = async (template, context, to, subject) => {
|
||||
const buildHtml = async (template, context) => {
|
||||
try {
|
||||
const mjml = this.templateLookup[template](context);
|
||||
const html = await this.mjml2html(mjml);
|
||||
return html.html;
|
||||
} catch (error) {
|
||||
logger.error("Error building Email HTML", {
|
||||
error,
|
||||
service: SERVICE_NAME,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
const info = await sendEmail(
|
||||
to,
|
||||
subject,
|
||||
await buildHtml(template, context)
|
||||
);
|
||||
return info.messageId;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
if (error.method === undefined) {
|
||||
error.method = "buildAndSendEmail";
|
||||
}
|
||||
logger.error("Error building and sending Email", {
|
||||
error,
|
||||
service: SERVICE_NAME,
|
||||
});
|
||||
}
|
||||
};
|
||||
const sendEmail = async (to, subject, html) => {
|
||||
try {
|
||||
const info = await this.transporter.sendMail({
|
||||
to: to,
|
||||
subject: subject,
|
||||
html: html,
|
||||
});
|
||||
return info;
|
||||
} catch (error) {
|
||||
logger.error("Error sending Email", {
|
||||
error,
|
||||
service: SERVICE_NAME,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
const info = await sendEmail(to, subject, await buildHtml(template, context));
|
||||
return info.messageId;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
if (error.method === undefined) {
|
||||
error.method = "buildAndSendEmail";
|
||||
}
|
||||
logger.error("Error building and sending Email", {
|
||||
error,
|
||||
service: SERVICE_NAME,
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
export default EmailService;
|
||||
Reference in new issue
Block a user