I am using node html-pdf
to generate a pdf and nodemailer
to automatically send an email containing the pdf every minute using node-cron
as demonstrated in the following code:
cron.schedule('* * * * *', () => {
// function to generate scan report using html-pdf
report.getScanReport();
// e-mail message options
let mailOptions = {
from: {{some_email}},
to: {{some_email}},
subject: 'Testing',
text: 'See PDF attachment',
attachments: [{
filename:'test.pdf',
path: 'C:/Users/test.pdf',
contentType: 'application/pdf'
}]
};
// Send e-mail
transporter.sendMail(mailOptions, function(error, info) {
if (error) {
console.log(error);
} else {
console.log('Email sent: ' + info.response);
}
});
})
The issue is that generating the pdf takes ~10 seconds or so, so the program tries to send the email before the generated pdf file exists and I then get the error: Error: ENOENT: no such file or directory
For reference here is how the getScanReport()
function works:
const getScanReport = () => {
Promise.all([
pool.query(query1),
pool.query(query2)
]).then(function([results1, results,]) {
var obj1 = results1.rows;
var obj2 = results2.rows;
ejs.renderFile('./views/pages/scanreport.ejs', {scanObj: scanObj, woObj: woObj}, (err, data) => {
if (err) {
console.log(err);
} else {
let options = {
"height": "11.25in",
"width": "8.5in",
"header": {
"height": "20mm"
},
"footer": {
"height": "20mm",
},
};
let filename = "test.pdf";
pdf.create(data).toFile(filename, function (err, data) {
let fileloc = 'C:/Users/' + filename;
if (err) {
console.log(err);
} else {
console.log("Successfully created pdf");
}
})
}
});
});
}
Is there a way make sure the pdf is generated before trying to send the email?
Assuming you can modify your getScanReport function, use a Promise. Then in your email function, use async / await to wait for that promise.
(You can click the links to read more about how promises and async / await work if you don't use them very often.)
For example (edited since post now includes getScanReport inner workings):
report.getScanReport = () => new Promise(
//announcePDFReady() is a function we call to resolve our promise
announcePDFReady => {
Promise.
all( [ /* ... */ ] ).
then( function( [ results1, results2 ] ) {
/* ... */
renderFile( /* ... */ ( err, data ) => {
/* ... */
pdf.create( data ).toFile( filename, ( err, data ) => {
let fileloc = 'C:/Users/' + filename;
if (err) {
console.log(err);
} else {
console.log("Successfully created pdf");
//announce ready right here!
announcePDFReady( data );
}
} )
} )
} )
}
);
//...
//we write 'async' before the cron job function definition
async () => {
//this is inside the cron job function
const pdfIsReady = await report.getScanReport();
//since report.getScanReport() returns a promise,
//'await' here means our code will stop until the promise resolves.
if( pdfIsReady === false ) {
//it failed. Do something? Ignore it?
} else {
//pdf is ready. We can send the email
//etc.
}
}