Home

Send HTML mails with NodeJS

Feb 12, 2022

When you search for "sending html mail with nodeJS", you'll find several articles and code snippets but none of them is explaining the implementation. I needed this feature in a project and want to share my experience with you, and may be show one of the simplest ways to do it. I'm using NodeJS with Typescript for the examples in this article.

Install dependencies

We will need Nodemailer for configuring and sending emails, and ejs for using mail templates. So let's install them:

npm install --save nodemailer ejs #if types are needed npm install --save-dev @types/nodemailr @types/ejs

Configure Nodemailer

In order to configure Nodemailer we have first to import it, and then configure the Transport Object (mailConfig in Code). There are many way to configure Nodemailer, If you already have a custom SMTP-Server you can use it. Please check https://nodemailer.com/about/ for more details. Many developers use Mailgun (https://www.mailgun.com/) oder sendGrid (https://sendgrid.com/) for this but you're fully free.

import nodemailer from 'nodemailer'; const mailConfig = { host: 'host', port: 25, secure: false, auth: { user: 'user', pass: 'password' }, tls: { rejectUnauthorized: false } }; // create the transport object const transporter = nodemailer.createTransport(mailConfig); // check if our server is ready to transporter.verify((error, success) => { if (error) { console.error(`[ERROR VERIFYING]: ${error}`); } else { console.log('Server is ready to handle messages'); } });

Generate an HTML-Mail template

EJS is a simple templating language that lets you generate HTML markup with plain JavaScript. There are a plenty of services for generating mail-temaplates like https://beefree.io/ or https://stripo.email/... You can use them, rename the ".html" file to a ".ejs" and then replace your dynamic values/placeholders inside. In our example we want to keep things simple, so let's create a new file (templates/mail.ejs):

<html> <head></head> <body> <div style="margin:0 auto;max-width:600px;"> <!-- Please take care of the <%= userName %> in the next Line. this will be replaced with real Data when rendering the HTML --> <p>Hi, <%= userName %></p> <p>This is an html test mail</p> </br></br> Thanks </div> </body> </html>

In this ejs file, we defined an html template with a placeholder. Later when we we'll send the email, we will render the template and give it a specific value for userName to replace the placeholder.

Send the email

Send the email with the transport Object

import fs from 'fs'; import path from 'path'; import { promisify } from 'util'; const readFile = promisify(fs.readFile); const userName = 'Joe Doe'; // define a value for the variable userName const templateDir = path.join(__dirname, "../", 'templates'); let html = 'Fallback html'; // Fallback if template cannot be loaded. try { // read the ejs file const mailTemplate = await readFile(`${templateDir}/mail.ejs`, 'utf-8'); // render the HTML and replace userName in ejs with "Joe Doe" html = ejs.render(mailTemplate, { userName }); } catch (error) { console.error('[ERROR LOADING]: cannot load template.'); } ... try { const sendMail = await transporter.sendMail({ from: 'sender@mail.com', to: 'reciever@mil.com', subject: 'mail-Subject', html: html, // user the rendered HTML }); if (sendMail) { console.log('mail sent successfully!'); } else { console.log('[ERROR SENDING]: cannot send Mail.'); } } catch (error) { console.error(`[GENERAL ERROR]: ${error}`); }

In the code above we read the file "mail.ejs" using "fs", "path" and "promisify". With the line ejs.render(mailTemplate, { userName }) we generate an HTML from ejs and replace userName with Joe Doe. With await transporter.sendMail(...) we then trigger the email sending process.

Conclusion

Sending an HTML-email with NodeJS needs a bit of researches and patience :-). But you can achieve it with no extra libraries (like email-templates, foundation-mails..) whereby I think it's worth to have a look at them, in order to see what possibilities are . So I hope that I was able to show you the first steps in sending an html-email with Nodemailer.

(BONUS) copy non-ts files in a Typescript Project

As you seen, in this example project I'm using Typescript for the development. But there's no built in function for considering non-ts files. So when using "tsc" to compile TS-Files, all generated files will be created in i.e. [root]/dist/ folder. we want to have the ability to move our template folder (containing the ejs file) to the dist folder. For this Im using copyfiles (https://www.npmjs.com/package/copyfiles) and then use these scripts (package.json) to generate my dist folder:

"clean": "rimraf dist/", "copy-files": "copyfiles -u 1 src/templates/html.ejs src/templates/**/*.* dist/", "build": "npm run clean && tsc && npm run copy-files",

rimraf is used to clean the dist folder everytime we build the project.

PS: please be aware of what version of nodeJS you're using. The code in this article works fine with node 16.14.0 and the latest versions of all mentioned libraries. (Using Node 17 can cause some problems).

Made with ❤️ by Marouen Mhiri