Sending ejs template using nodemailer

Blue Bird picture Blue Bird · Dec 23, 2016 · Viewed 10.3k times · Source

I'm trying to build a web application using express.js. In my application, I'm using nodemailer for sending mail. If I just use it to send basic mail it work ok; however, when I try to use nodemailer to send a rendered ejs file, the recipient only receive an empty mail. So here the details of my code:

var transporter = nodemailer.createTransport({
                host: 'smtp.zoho.com',
                port: 465,
                secure: true, // use SSL
                auth: {
                    user: '[email protected]',
                    pass: '123456'
                }
            });
fs.readFile('/test.ejs', 'utf8', function (err, data) {
                if (err) {
                    return console.log(err);
                }
                var mainOptions = {
                    from: '"Tester" [email protected]',
                    to: email,
                    subject: 'Hello, world'
                    html: ejs.render(data, {name: 'Stranger'});
                };
                console.log(mainOptions.html);
});
transporter.sendMail(mainOptions, function (err, info) {
                            if (err) {
                                console.log(err);
                            } else {
                                console.log('Message sent: ' + info.response);
                            }
                        });

Here the test.ejs (also, the result console.log(mainOptions.html) is fine because it print out the string of the rendered ejs file correctly (<%= name %> replaced with 'Stranger')

<style type="text/css">
  .header {
    background: #8a8a8a;
  }
  .header .columns {
    padding-bottom: 0;
  }
  .header p {
    color: #fff;
    padding-top: 15px;
  }
  .header .wrapper-inner {
    padding: 20px;
  }
  .header .container {
    background: transparent;
  }
  table.button.facebook table td {
    background: #3B5998 !important;
    border-color: #3B5998;
  }
  table.button.twitter table td {
    background: #1daced !important;
    border-color: #1daced;
  }
  table.button.google table td {
    background: #DB4A39 !important;
    border-color: #DB4A39;
  }
  .wrapper.secondary {
    background: #f3f3f3;
  }
</style>



<wrapper class="header">
  <container>
    <row class="collapse">
      <columns small="6">
        <img src="http://placehold.it/200x50/663399">
      </columns>
      <columns small="6">
        <p class="text-right">BASIC</p>
      </columns>
    </row>
  </container>
</wrapper>

<container>

  <spacer size="16"></spacer>

  <row>
    <columns small="12">

      <h1>Hi, <%= name %></h1>
      <p class="lead">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Magni, iste, amet consequatur a veniam.</p>
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ut optio nulla et, fugiat. Maiores accusantium nostrum asperiores provident, quam modi ex inventore dolores id aspernatur architecto odio minima perferendis, explicabo. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minima quos quasi itaque beatae natus fugit provident delectus, magnam laudantium odio corrupti sit quam. Optio aut ut repudiandae velit distinctio asperiores?</p>
      <callout class="primary">
        <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Reprehenderit repellendus natus, sint ea optio dignissimos asperiores inventore a molestiae dolorum placeat repellat excepturi mollitia ducimus unde doloremque ad, alias eos!</p>
      </callout>
    </columns>
  </row>
  <wrapper class="secondary">

    <spacer size="16"></spacer>

    <row>
      <columns large="6">
        <h5>Connect With Us:</h5>
        <button class="facebook expand" href="http://zurb.com">Facebook</button>
        <button class="twitter expand" href="http://zurb.com">Twitter</button>
        <button class="google expand" href="http://zurb.com">Google+</button>
      </columns>
      <columns large="6">
        <h5>Contact Info:</h5>
        <p>Phone: 408-341-0600</p>
        <p>Email: <a href="mailto:[email protected]">[email protected]</a></p>
      </columns>
    </row>
  </wrapper>
</container>

If I replace the mainOptions.html with simple content, for instance: <b>Hello, world!</b> the recipient will receive the content accurately. However, if I use the above code, the recipient will only receive an email with empty content (the recipient still receive sender, subject and other informations correctly). I have try to replace the html with text to send the rendered string as plain text instead of html but the received mail still have empty content. That all the details of my problem I can provide at the moment. So if anyone know what is wrong with my code please point it out for me.

Thanks in advance for any help you are able to provide.

Answer

notionquest picture notionquest · Dec 27, 2016

The problem is sendMail gets executed before the fs.readFile gets completed.

Actually, the readFile can be replaced with ejs.renderFile which reads file and renders the HTML string. Please try the below refactored code.

var fs = require("fs");
var nodemailer = require("nodemailer");
var ejs = require("ejs");
var transporter = nodemailer.createTransport({
    host: 'smtp.zoho.com',
    port: 465,
    secure: true, // use SSL
    auth: {
        user: '[email protected]',
        pass: '123456'
    }
});

ejs.renderFile(__dirname + "/test.ejs", { name: 'Stranger' }, function (err, data) {
if (err) {
    console.log(err);
} else {
    var mainOptions = {
        from: '"Tester" [email protected]',
        to: "[email protected]",
        subject: 'Hello, world',
        html: data
    };
    console.log("html data ======================>", mainOptions.html);
    transporter.sendMail(mainOptions, function (err, info) {
        if (err) {
            console.log(err);
        } else {
            console.log('Message sent: ' + info.response);
        }
    });
}

});