nodejs #express #ejs
I’ve been building a social links website 8link, which requires me to interact with my users at different levels. So the type of email interaction with my users, I’ve narrowed it down to the following categories of emails:
Welcome email (With verify link)
Password reset link
Automated response to user queries
The actual response to User queries
Occasional promo or newsletters
I’ve been using a Node.js +Express back-end and I wanted to achieve it with same frame-work. So I started using SendGrid Email API to achieve this goal.
SendGrid already has a Templating service, if you are interested you can check it here.
Back to Templating with EJS,
in This article, we’ll see how can we create Re-Usable HTML Templates with EJS and then deliver them with SendGrid.
We’ll start by creating a simple node project:
npm init sendgrid-mailer
Install following dependencies,
npm i --save express cors ejs
Our Package.json should look like:
Let’s create a simple endpoint to serve our email “/hello”
Notice //set express view engine to ejs
app.set(“view engine”, “ejs”);
const express = require("express"); | |
const cors = require("cors"); | |
const port = process.env.PORT || 4000; | |
const app = express(); | |
//to enable cors | |
app.use(cors()); | |
//set express view engine | |
app.set("view engine", "ejs"); | |
//routes which handles the requests | |
app.get("/hello", (req, res, next) => { | |
res.send("Hello There!!"); | |
}); | |
app.use((req, res, next) => { | |
const error = new Error("Not Found"); | |
error.status = 404; | |
next(error); | |
}); | |
app.use((error, req, res, next) => { | |
res.status(error.status || 500); | |
res.json({ | |
error: { | |
message: error.message | |
} | |
}); | |
}); | |
app.listen(port, () => { | |
console.log(`listening on port ${port}..`); | |
}); |
it should give us the following response:
We are halfway there, Now create a welcome-mail.ejs file in views (Template) folder in the project root directory.
Now add some HTML code in there, which will serve as an underlying template for our welcome mail:
<table width="100%" cellpadding="0" cellspacing="0" border="0"> | |
<tbody> | |
<tr> | |
<td width="100%"> | |
<div style="max-width:600px;Margin:0 auto"> | |
<table | |
align="center" | |
cellpadding="0" | |
cellspacing="0" | |
style="border-spacing:0;font-family:gt-eesti,ArialMT,Helvetica,Arial,sans-serif;Margin:0 auto;padding:24px;width:100%;max-width:500px" | |
> | |
<tbody> | |
<tr> | |
<td> | |
<table style="margin-bottom:40px;width:100%" width="100%"> | |
<tbody> | |
<tr> | |
<td> | |
<a | |
href="http://8link.in/?ref=mail" | |
style="font-family:Helvetica,Arial,sans-serif;color:#0086bf" | |
target="_blank" | |
> | |
<img | |
src="http://8link.in/assets/mail/logo.png" | |
style="display:block" | |
alt="8link" | |
width="200" | |
height="65" | |
/> | |
</a> | |
</td> | |
</tr> | |
</tbody> | |
</table> | |
</td> | |
</tr> | |
<tr> | |
<td style="text-align:justify;word-break:break-word"> | |
<table style="margin-bottom:20px;width:100%" width="100%"> | |
<tbody> | |
<tr> | |
<td> | |
<table | |
style="width:100%;margin-bottom:20px" | |
width="100%" | |
cellpadding="0" | |
cellspacing="0" | |
> | |
<tbody> | |
<tr> | |
<td> | |
<strong style="font-family:Helvetica,Arial,sans-serif;color:#234567">Hi <%= user_firstname %>, </strong> | |
<h1 | |
style="font-size:26px;line-height:30px;color:#054752;word-break:normal" | |
> | |
Welcome to 8link! Please confirm your email. | |
</h1> | |
</td> | |
</tr> | |
</tbody> | |
</table> | |
</td> | |
</tr> | |
<tr> | |
<td> | |
<center> | |
<table | |
style="background-color:#fff;margin-bottom:20px;table-layout:fixed" | |
align="center" | |
width="" | |
cellspacing="0" | |
cellpadding="0" | |
> | |
<tbody> | |
<tr> | |
<td | |
style="background-color:#00aff5;color:#fff;text-align:center;border-radius:48px;padding:16px 24px;border-color:transparent;font-weight:bold;font-size:16px;line-height:1" | |
> | |
<a style="color: white; text-decoration: none;" href= <%= confirm_link %>> Confirm Email </a> | |
</td> | |
</tr> | |
</tbody> | |
</table> | |
</center> | |
</td> | |
</tr> | |
</tbody> | |
</table> | |
</td> | |
</tr> | |
<tr> | |
<td></td> | |
</tr> | |
<tr> | |
<td> | |
<table width="100%" style="margin-bottom:20px;width:100%"> | |
<tbody> | |
<tr> | |
<td width="100%"> | |
<div | |
style="width:100%;height:1px;background-color:#ddd" | |
color="#DDD" | |
width="100%" | |
></div> | |
</td> | |
</tr> | |
</tbody> | |
</table> | |
</td> | |
</tr> | |
<tr> | |
<td style="text-align:center"> | |
<img | |
src="http://8link.in/assets/mail/icon.png" | |
alt="8link_icon" | |
style="display:block;width:29px;height:auto;margin-left:auto;margin-right:auto;margin-bottom:10px" | |
height="auto" | |
/> | |
</td> | |
</tr> | |
<tr> | |
<td style="text-align:center;font-size:13px"> | |
<a | |
href="http://8link.in/?ref=mail" | |
style="color:#00aff5" | |
target="_blank" | |
> | |
Goto 8link.in | |
</a> | |
<span style="color:#00aff5">|</span> | |
<a | |
href="http://8link.in/FAQ" | |
style="color:#00aff5" | |
target="_blank" | |
> | |
FAQ | |
</a> | |
</td> | |
</tr> | |
<tr> | |
<td style="text-align:center"> | |
<table | |
style="max-width:100%;width:100%;text-align:center;font-family:ArialMT,Arial,sans-serif" | |
cellspacing="0" | |
cellpadding="0" | |
> | |
<tbody> | |
<tr> | |
<td style="text-align:center"> | |
<p | |
style="font-size:10px;color:#708c91;text-align:center;padding:0;margin-top:10px;margin-bottom:2px" | |
> | |
This email was sent to you by | |
welcome@8link.in (Do not reply) | |
</p> | |
</td> | |
</tr> | |
</tbody> | |
</table> | |
</td> | |
</tr> | |
</tbody> | |
</table> | |
</div> | |
</td> | |
</tr> | |
</tbody> | |
</table> | |
You will see the following syntax in this HTML, which is used to receive data before rendering it. We are using the following variables for manipulating data:
//these are EJS expressions to dynamically receive and display data while rendering an HTML
<%= user_firstname %>
<%= confirm_link %>
Now we need to make changes to our “/hello” endpoint
We’ll need to import following to our index.js file:
//imports
const path = require(“path”);
const ejs = require(“ejs”);
and our “/hello” app route function will change to :
app.get(“/hello”, (*req*, *res*, *next*) => {
let emailTemplate;
let capitalizedFirstName = “John”;
let userEmail = “John@example.com”;
ejs
.renderFile(path.join(__dirname, “views/welcome-mail.ejs”),
{
user_firstname: capitalizedFirstName,
confirm_link: “http://www.8link.in/confirm=" + userEmail
})
.then(*result* => {
emailTemplate = result;
res.send(emailTemplate);
})
.catch(*err* => {
res.status(400).json({
message: “Error Rendering emailTemplate”,
error: err
});
});
});
in here, ejs.renderFile() take .ejs file path and specify values for _user_firstname _and confirm_link
Now if we hit “/hello” we get:
Whoops.. we now have our welcome template, we just have to deliver it via email now.
Let's integrate SendGrid now:
First signup for SendGrid mail API, by clicking here and get the API -KEY
Now get @sendgrid/mail package from npm.
npm i --save @sendgrid/mail
Import following into index.js
const SGmail = require(“@sendgrid/mail”);
Now in our code first register the SendGrid API Key
SGmail.setApiKey(process.env.SendGrid_Key);
//Note: store SendGrid_Key in your projects' config file
and replace **res.send(emailTemplate); **with following code:
const message = {
to: userEmail,
from: { email: “welcome@8link.in”, name: “8link” },
subject: “Welcome link”,
html: emailTemplate
};
return SGmail.send(message).then(*sent* => {
// Awesome Logic to check if mail was sent
res.status(200).json({
message: “Welcome mail was sent”
});
}).catch(*err* => {
console.log(“Error sending mail”, err);
res.status(400).json({
message: “Welcome mail was not sent”,
error: err
});
});
Our final code should look like:
const express = require("express"); | |
const cors = require("cors"); | |
const path = require("path"); | |
const ejs = require("ejs"); | |
const SGmail = require("@sendgrid/mail"); | |
const port = process.env.PORT || 4000; | |
const app = express(); | |
//to enable cors | |
app.use(cors()); | |
//set ecpress view engine | |
app.set("view engine", "ejs"); | |
SGmail.setApiKey(process.env.SendGrid_Key); | |
//routes which handles the requests | |
app.get("/hello", (req, res, next) => { | |
let emailTemplate; | |
let capitalizedFirstName = "John"; | |
let userEmail = "John@example.com"; | |
ejs | |
.renderFile(path.join(__dirname, "views/welcome-mail.ejs"), { | |
user_firstname: capitalizedFirstName, | |
confirm_link: "http://www.8link.in/confirm=" + userEmail | |
}) | |
.then(result => { | |
emailTemplate = result; | |
const message = { | |
to: userEmail, | |
from: { email: "welcome@8link.in", name: "8link" }, | |
subject: "Welcome link", | |
html: emailTemplate | |
}; | |
return SGmail.send(message) | |
.then(sent => { | |
// Awesome Logic to check if mail was sent | |
res.status(200).json({ | |
message: "Welcome mail was sent" | |
}); | |
}) | |
.catch(err => { | |
console.log("Error sending mail", err); | |
res.status(400).json({ | |
message: "Welcome mail was not sent", | |
error: err | |
}); | |
}); | |
//res.send(emailTemplate); | |
}) | |
.catch(err => { | |
res.status(400).json({ | |
message: "Error Rendering emailTemplate", | |
error: err | |
}); | |
}); | |
}); | |
app.use((req, res, next) => { | |
const error = new Error("Not Found"); | |
error.status = 404; | |
next(error); | |
}); | |
app.use((error, req, res, next) => { | |
res.status(error.status || 500); | |
res.json({ | |
error: { | |
message: error.message | |
} | |
}); | |
}); | |
app.listen(port, () => { | |
console.log(`listening on port ${port}..`); | |
}); |
And if I hit my “/hello” endpoint again, I should see that mail was sent successfully:
Full Code on Github: https://github.com/far11ven/SendGrid-Mailer
Original article on: https://blog.kushalbhalaik.xyz/email-templating-with-ejs-node-express-sendgrid/
Top comments (1)
Is it possible to use global style in the email template, I used bootstrap in developing the email template but the unstyled version is getting delivered to clients.