Pass variable to html template in nodemailer

JavascriptHtmlnode.jsExpressNodemailer

Javascript Problem Overview


I want to send email with nodemailer using html template. In that template I need to inject some dynamically some variables and I really can't do that. My code:

var nodemailer = require('nodemailer');
var smtpTransport = require('nodemailer-smtp-transport');

smtpTransport = nodemailer.createTransport(smtpTransport({
	host: mailConfig.host,
	secure: mailConfig.secure,
	port: mailConfig.port,
	auth: {
		user: mailConfig.auth.user,
		pass: mailConfig.auth.pass
	}
}));
var mailOptions = {
	from: '[email protected]',
	to : '[email protected]',
	subject : 'test subject',
	html : { path: 'app/public/pages/emailWithPDF.html' }
};
smtpTransport.sendMail(mailOptions, function (error, response) {
	if (error) {
		console.log(error);
		callback(error);
	}
});

Let's say I want in emailWithPDF.html something like this:

Hello {{username}}!

I've found some examples, where was smth like this:

...
html: '<p>Hello {{username}}</p>'
...

but I want it in separate html file. Is it possible?

Javascript Solutions


Solution 1 - Javascript

What you can do is read the HTML file using fs module in node and then replace the elements that you want changed in the html string using handlebars

var nodemailer = require('nodemailer');
var smtpTransport = require('nodemailer-smtp-transport');
var handlebars = require('handlebars');
var fs = require('fs');

var readHTMLFile = function(path, callback) {
    fs.readFile(path, {encoding: 'utf-8'}, function (err, html) {
        if (err) {
           callback(err); 
           throw err;
            
        }
        else {
            callback(null, html);
        }
    });
};

smtpTransport = nodemailer.createTransport(smtpTransport({
    host: mailConfig.host,
    secure: mailConfig.secure,
    port: mailConfig.port,
    auth: {
        user: mailConfig.auth.user,
        pass: mailConfig.auth.pass
    }
}));

readHTMLFile(__dirname + 'app/public/pages/emailWithPDF.html', function(err, html) {
    var template = handlebars.compile(html);
    var replacements = {
         username: "John Doe"
    };
    var htmlToSend = template(replacements);
    var mailOptions = {
        from: '[email protected]',
        to : '[email protected]',
        subject : 'test subject',
        html : htmlToSend
     };
    smtpTransport.sendMail(mailOptions, function (error, response) {
        if (error) {
            console.log(error);
            callback(error);
        }
    });
});

Solution 2 - Javascript

I use it in all my projects. more clean and up to date and understandable. callback hell doesn't exist. sendMail.ts The html file reads with handlebar, puts the relevant variables into the contents, and sends.

import * as nodemailer from 'nodemailer';
import * as handlebars from 'handlebars';
import * as fs from 'fs';
import * as path from 'path';

export async function sendEmail(email: string, subject: string, url: string) {
  const filePath = path.join(__dirname, '../emails/password-reset.html');
  const source = fs.readFileSync(filePath, 'utf-8').toString();
  const template = handlebars.compile(source);
  const replacements = {
    username: "Umut YEREBAKMAZ"
  };
  const htmlToSend = template(replacements);
  const transporter = nodemailer.createTransport({
    host: "smtp.mailtrap.io",
    port: 2525, // 587
    secure: false,
    auth: {
      user: "fg7f6g7g67",
      pass: "asds7ds7d6"
    }
  });
  const mailOptions = {
    from: '"[email protected]" <[email protected]>',
    to: email,
    subject: subject,
    text: url,
    html: htmlToSend
  };
  const info = await transporter.sendMail(mailOptions);
  console.log("Message sent: %s", info.messageId);
  console.log("Preview URL: %s", "https://mailtrap.io/inboxes/test/messages/");

}

Solution 3 - Javascript

String replace isn't a good idea because you'll have to restore old strings or create a backup file to be able to change them another time, also it won't be asynchrone and it will cause a problem in every way! you can do it much easier and more cleaner:

just go to your mail options and add context with your variables:

var mailOptions = {
  from: '[email protected]',
  to: '[email protected]',
  subject: 'Sending email',
  template: 'yourTemplate',
  context: {                  // <=
    username: username,
    whatever: variable
  }
};

next thing to do is openning your html file and call your variables like:

{{username}}

Solution 4 - Javascript

If you're using Nodemailer 2.0.0 or higher, check this documentation: https://community.nodemailer.com/2-0-0-beta/templating/ There they explain how to make use of external rendering with templates like that:

// external renderer
var EmailTemplate = require('email-templates').EmailTemplate;
var send = transporter.templateSender(new EmailTemplate('template/directory'));

They also give this example:

// create template based sender function
// assumes text.{ext} and html.{ext} in template/directory
var sendPwdReminder = transporter.templateSender(new EmailTemplate('template/directory'), {
    from: '[email protected]',
});

where you see how to pass variables.

You will need the email-templates module: https://github.com/crocodilejs/node-email-templates and a template engine of your choice.

Also in the documentation of email-templates you'll find how to make your file structure in order that your templates can be found:

> html.{{ext}} (required) - for html format of email > > text.{{ext}} (optional) - for text format of email style. > > {{ext}}(optional) - styles for html format subject. > > {{ext}}(optional) - for subject of email > > See supported template engines for possible template engine extensions (e.g. .ejs, .jade, .nunjucks) to use for the value of {{ext}} above. > > You may prefix any file name with anything you like to help you identify the files more easily in your IDE. The only requirement is that the filename contains html., text., style., and subject. respectively.

Solution 5 - Javascript

For those using pug as templating engine

Just a quick way to render a template in a separate file using pug's render function:

// function to send an e-mail. Assumes you've got nodemailer and pug templating engine installed. 
// transporter object relates to nodemailer, see nodemailer docs for details
const nodemailer = require('nodemailer');
const pug = require('pug');
function send_some_mail(iterable){
var message = {
  from: '[email protected]',
  to: '[email protected]',
  subject: 'Message title',
  html: pug.renderFile(__dirname + 'path_to_template.pug', {iterable: iterable})
};
transporter.sendMail(message, function(err, info){...})
}

// template.pug
each item in iterable
li
  p #{item.name}

See https://pugjs.org/api/getting-started.html for further details. Note that this will cause template re-compilation every time a message is sent. That is fine for occasional e-mail deliveries. If you send tons of e-mails, you can cache the compiled template to work around that. Check out pug docs for that set up if you need it.

Solution 6 - Javascript

Create one file emailTemplates.js there yo can store each template as a function

emailTemplates.js

const newsLetterEmail = (clientName) => `<p>Hi ${clientName}, here you have today news.</p>`
const welcomeEmail = (clientName, username) => `<p>Welcome ${clientName}, your username is ${username}.</p>`

export {newsLetterEmail, welcomeEmail}

Then in the controllers call any templateFunction and store in output varaible

controller.js

import {welcomeEmail} from './emailTeamplates.js'

const registerUser = async(req, res) => {
    const {name, usename, email} = req.body
    // User register code....
    const output = welcomeEmail(name, username)

    let mailOptions = {
        from: '"Welcome" <[email protected]>',
        to: '[email protected]',
        subject: 'Welcome email!',
        text: 'Hello World',
        html: output,
    }
 

Solution 7 - Javascript

You can use a Web Request to build an html template using handlebars or any other engine.

Create a template

First you must create an html template for the email body. In this example I used a handlebars hbs file.

enter image description here

Do your design stuff with html and add the variables that you will need in the message:

   <!DOCTYPE html>
   <html>
    <head>
        <meta name="viewport" content="width=device-width">
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Welcome Email Template</title>
    </head>
    <body>
     <p style="font-size: 14px; font-weight: normal;">Hi {{data.name}}</p>
    </body>
   </html>

Create a template request

You must create the access to this view. Then a request is created where we can send the template name as an url parameter to make the request parameterizable for other templates.

const web = express.Router()

web.post('/template/email/:template', function(req, res) {
  res.render(`templates/email/${req.params.template}`, {
    data: req.body        
  })
})

Mail function

Finally you can send the email after making the request to the template. You can use a function like the following:

const nodemailer = require('nodemailer')
const request = require("request")

function sendEmail(toEmail, subject, templateFile) {
	var options = {
		uri: `http://localhost:3000/template/email/${templateFile}`,
		method: 'POST',
		json: { name: "Jon Snow" } // All the information that needs to be sent
	};	
	request(options, function (error, response, body) {
		if (error) console.log(error)
		var transporter = nodemailer.createTransport({
			host: mailConfig.host,
			port: mailConfig.port,
			secure: true,
			auth: {
				user: mailConfig.account,
				pass: mailConfig.password
			}
		})
		var mailOptions = {
			from: mailConfig.account,
			to: toEmail,
			subject: subject,
			html: body
		}		
		transporter.sendMail(mailOptions, function(error, info) {
			if (error) console.log(error)
		})
	})
}

Solution 8 - Javascript

This can be done without templates.

Try changing it to this:

`Hello ${username}!`

Make sure that these are not inverted commas but back ticks.

Solution 9 - Javascript

There is one easy way to insert variable inside html in nodemailer.

    html:"<p>Your message "+variable1+".Message continueous "+variable 2+"</p>"

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionWacław ŁabudaView Question on Stackoverflow
Solution 1 - JavascriptAnanth PaiView Answer on Stackoverflow
Solution 2 - JavascriptumutyerebakmazView Answer on Stackoverflow
Solution 3 - JavascriptlarachiwnlView Answer on Stackoverflow
Solution 4 - JavascriptMichael TrogerView Answer on Stackoverflow
Solution 5 - Javascriptwondersz1View Answer on Stackoverflow
Solution 6 - JavascriptCesar MoranView Answer on Stackoverflow
Solution 7 - JavascriptJ.C. GrasView Answer on Stackoverflow
Solution 8 - JavascriptOmkar KulkarniView Answer on Stackoverflow
Solution 9 - JavascriptRanjit Kumar PanditView Answer on Stackoverflow