In my 6 years of experience as a developer, one of the biggest issues I have was how to easily send email using NodeJS. when I started at first I was using libraries like ejs and handlebars. But this was not that easy to do, coupled with the fact that I was using Typescript for my backend.
Whenever I'm building an application architecture I get excited, but when I get to the part of emails. My energy drops, because I know the level of setup I have to do for this will be quite much.
So one day I was going through laravel framework and I came to realize that laravel was using something like a templating pattern(All tools are already created for usage) needed for creating a smooth email is already there for you to just call and us it. So I decided to stop using any libraries for my email setup. And I decided to try out the templating pattern.
So the first thing I did was to get my email template which was in pure HTML. Then I split the code into components. Like I have a button component, a TEXT component, and BOX and so many other components. Then I was left with 3 layers namely
The header
The Body
The Footer
These three layers were used to achieve the templating pattern
Enough of the storytelling let's dive into how this can be implemented
let's bootstrap our project. I will be using ExpressJS for this, but if the pattern is properly followed you can get the same result on any backend framework you are using
Email
components
layouts
Templates
Components
body.ts
button.ts
text.ts
box.ts
Layouts
header.ts
footer.ts
main.ts
layout.ts
Templates
reset.password.template.ts
two.factor.template.ts
So lets say we want to send an OTP for password reset. I will be using mailgun for this tutorial. Our layout.ts file will look like this
layout.ts
import {header} from "./header.template";
import {footer} from "./footer.template";
import mainTemplate from "./main.template";
import {head} from "./head.template";
import {body} from "../components/body.component";
export default (payload: any) =>
`
${head}
${header}
${body}
${mainTemplate(payload)}
${footer}
`
reset.password.template.ts
import layoutTemplate from "../layouts/layout.template";
module.exports = ( data:{ name: string, otp: string} ) => {
return layoutTemplate(
`<p class="MsoNormal" style="margin: 0px 0px 11px; line-height: 107%; font-size: 15px; font-family: Calibri, sans-serif;"><span lang="EN-US" style="font-family: Aptos, sans-serif;">Dear ${data.name},</span></p> <p class="MsoNormal" style="margin: 0px 0px 11px; line-height: 107%; font-size: 15px; font-family: Calibri, sans-serif;"><span lang="EN-US" style="font-family: Aptos, sans-serif;">You requested to change the password for your Payluk account. Use the code below to reset your password:</span></p> <p class="MsoNormal" style="margin: 0px 0px 11px; line-height: 107%; font-size: 15px; font-family: Calibri, sans-serif;"><b><span lang="EN-US" style="font-family: Aptos, sans-serif;">${data.otp}</span></b></p> <p class="MsoNormal" style="margin: 0px 0px 11px; line-height: 107%; font-size: 15px; font-family: Calibri, sans-serif;"><span lang="EN-US" style="font-family: Aptos, sans-serif;">If you did not initiate this request, please disregard this email.</span></p> <p class="MsoNormal" style="margin: 0px 0px 11px; line-height: 107%; font-size: 15px; font-family: Calibri, sans-serif;"><span lang="EN-US" style="font-family: Aptos, sans-serif;">Warm regards,</span></p> <p class="MsoNormal" style="margin: 0px 0px 11px; line-height: 107%; font-size: 15px; font-family: Calibri, sans-serif;"><span lang="EN-US" style="font-family: Aptos, sans-serif;">The Payluk Team.</span></p> <p class="MsoNormal" style="margin: 0px 0px 11px; line-height: 107%; font-size: 15px; font-family: Calibri, sans-serif;"><span lang="EN-US"> </span></p> <p class="MsoNormal" align="center" style="margin: 0px 0px 11px; line-height: 107%; font-size: 15px; font-family: Calibri, sans-serif; text-align: center;"><span lang="EN-US" style="font-family: Aptos, sans-serif;">If you have any questions or concerns, reach out to us at support@payluk.com</span></p>`
);
}
email.provider.ts
export class EmailProvider {
private static temp = (arg: argProps) => require(`../../email/templates/${arg.template}`)(arg.data);
public static async send(data: IEmail): Promise<MessagesSendResult | undefined> {
try {
const content = EmailProvider.temp({ template: data.template, data:data.data });
return await sendMail(data.to, data.subject, content);
}
catch (e) {
console.log(e);
}
}
}
mailgun.ts
import formData from 'form-data';
import Mailgun from 'mailgun.js';
import env from '../utils/env';
const mailgun = new Mailgun(formData);
export const sendMail = async (to: string[] | string, subject: string, template: any) => {
try {
const mg = mailgun.client({username: 'api', key: env.MAILGUN_API_KEY });
return mg.messages.create(env.DOMAIN_NAME, {
from: "Domain <mailgun@domain.com>",
to: to,
subject,
html: template
});
}
catch (e) {
throw e;
}
}
Now let's say we want to send the email now since our setup is completed we can just call the observer function if your email service is registered inside an observer or just simply call the emailProvider.send function to trigger the email
await EmailProvider.send({
to: 'jerozeek2@gmail.com',
subject: 'email subject',
template: 'reset.password.template',
data: {
name:'Ezumah Jeremiah',
otp: '123456'
}
})
The parameter is sent to emailProvider.send function. Note: the template is the name of the email you want to send. In my case am sending it to reset.password.template while the data is the props that the reset.password.template accept which in my case is the name and otp
I hope you find this handy because it going to save a lot of time and you will find data passing and display very easy compared to when you use a library like handlebars or ejs