Introduction
I have different features in my app, like:
- Reset password (forgot password)
- Update user password
- Sign up
- Become premium
For each feature, when success, I want to send a custom HTML email to the user.
Generation of the emails
As the HTML main structure is the same (only the content (texts) changes), I have decided to implement my helper method generateEmailTemplate()
:
const { HEAD, BODY } = require("../utils");
module.exports = (main) => `
<!DOCTYPE html>
<html lang="en">
${HEAD}
${BODY(main)}
</html>
`;
And, in order to include the specific data to the generated template, I am using different methods for each feature:
const signUpWelcomeEmailTemplate = (name) =>
templateGenerator(`<p>Welcome, ${name}</p>`);
const premiumEmailTemplate = (name) =>
templateGenerator(`<h1>${name}, you are now premium!</h1>`);
// The html is more complex, I have reduced it for simiplicity
Sending emails
In order to send the emails to the users, I have the following method, which adds an email record to my database. Then, when the record is added, a custom extension connected to the MailGun
service sends the mail via SMTP.
This is the implementation of my method:
async function sendEmail(
to,
subject,
text = undefined,
html = undefined
) {
const mailsRef = db.collection("mails");
const mail = {
to,
message: {
subject,
...text && { text },
...html && { html },
},
};
await mailsRef.add(mail);
functions.logger.log("Queued email for delivery!");
};
Problem
Now, in order to use this method, in each feature, I have to do the following:
async function goPremium(user) {
try {
await purchasePremium(user.uid);
const html = premiumEmailTemplate(user.name);
sendEmail(user.email, "Premium purchase success!", undefined, html);
} catch(err) {
...
}
}
I am looking for a pattern which generalizes this call, I mean, some kind of email manager.
I have thought about two different ways to refactor this code:
#1 (I don't like this way, as the method might be super long, I mean, imagine 100 features...)
function emailManager(user, type) {
switch(type) {
"welcome":
sendEmail(user.email, "Welcome!", undefined, welcomeEmailTemplate(user.name));
break;
"premium":
sendEmail(user.email, "Premium purchase success!", undefined, premiumEmailTemplate(user.name));
break;
default:
break;
}
}
- Just create different methods and export them from a 'central' module.
...
const sendPremiumEmail = (user) => {
const title = "Premium purchase success!";
const html = premiumEmailTemplate(user.name);
return sendEmail(user.email, title, undefined, html);
};
...
module.exports = {
sendWelcomeEmail,
sendPremiumEmail,
...
}
But... maybe there is another way, a pattern which exactly solves this situation. Any ideas?