Pass variable to html template in nodemailer

82,243

Solution 1

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

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

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

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

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.

Share:
82,243
Admin
Author by

Admin

Updated on July 09, 2022

Comments

  • Admin
    Admin almost 2 years

    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?

  • Pardeep Jain
    Pardeep Jain about 6 years
    Is there any another way for the same like we do in case of .pug file, we just pass object to map variable
  • Pardeep Jain
    Pardeep Jain about 6 years
    Is there any another way for the same like we do in case of .pug file, we just pass object to map variable
  • Gaurav Sharma
    Gaurav Sharma about 6 years
    Does this supports inline CSS styling?
  • Ananth Pai
    Ananth Pai about 6 years
    Yes it does, you can add the css styling to your html page
  • Abodesegun Ezekiel
    Abodesegun Ezekiel about 5 years
    This will come out as text now html.
  • Roko C. Buljan
    Roko C. Buljan about 5 years
    <!DOCTYPE html> for emails?... It's a bit longer than that.
  • Sam
    Sam almost 5 years
    This could be dangerous because the text will not be HTML-encoded
  • Bhagvat Lande
    Bhagvat Lande over 4 years
    Thanks, @AnanthPai, posted answer is really helpful. Initially, I was very much confused about dynamic email templates with handlebars, express-handlebars, etc. now having clear things.
  • Abdo-Host
    Abdo-Host about 4 years
    how i can use or print variable in view file ?
  • Johnny Navarro
    Johnny Navarro about 4 years
    Can you use local images in the HTML template this way? Tried using one but it wouldn't load. Using URLs does work of course.
  • umutyerebakmaz
    umutyerebakmaz about 4 years
    You can use it if you give absolute paths of the files on the server. for example: yourdomain.com/images/logo.png you can use it like traditional html. They explained a different way in the document on the offical site. community.nodemailer.com/using-embedded-images I still find my way easier and more flexible. I prepare my html template first and then I include it in the work.
  • ublec
    ublec about 3 years
    Make sure that you don't put a space in between.
  • Jatinder
    Jatinder almost 3 years
    any examples links to this implementation codebox or codepen something to view the complete flow in action.
  • RollerCosta
    RollerCosta over 2 years
    tried but not working for me, any additional setting? @larachiwnl
  • rickster
    rickster over 2 years
    I did the same. But my CSS is not getting linked with html. What might be the reason ?
  • umutyerebakmaz
    umutyerebakmaz over 2 years
    If you are going to use css for emails, make sure to use inline style.
  • Sehrish Waheed
    Sehrish Waheed about 2 years
    the best answer