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.
EJS: EJS or Embedded Javascript Templating is a templating engine used by Node.js. Template engine helps to create an HTML template with minimal code. Also, it can inject data into HTML template at the client side and produce the final HTML.
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);
}
});
}
});
I have updated the answer using ES6 and ES8 features, just in case anyone needs it.
Don't forget to use it in an async function.
const fs = require("fs");
const nodemailer = require("nodemailer");
const ejs = require("ejs");
const transporter = nodemailer.createTransport({
host: 'smtp.zoho.com',
port: 465,
secure: true,
auth: {
user: '[email protected]',
pass: '123456'
}
});
const data = await ejs.renderFile(__dirname + "/test.ejs", { name: 'Stranger' });
const mainOptions = {
from: '"Tester" [email protected]',
to: '[email protected]',
subject: 'Hello, world!',
html: data
};
transporter.sendMail(mainOptions, (err, info) => {
if (err) {
console.log(err);
} else {
console.log('Message sent: ' + info.response);
}
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With