5

I am having an issue where nodemailer-express-handlebars is outputing the error:

[Error: ENOENT: no such file or directory, open ''] {
  errno: -2,
  code: 'ENOENT',
  syscall: 'open',
  path: '/Users/person/Code/app/api/controllers/templates/undefined.hbs'

My setup is as follows:

 const handlebarOptions = {
    viewEngine: {
      extName: ".hbs",
      partialsDir: path.resolve(__dirname, "templates"),
      defaultLayout: false
    },
    viewPath: path.resolve(__dirname, "templates"),
    extName: ".hbs"
  };

  transporter.use('compile', hbs(handlebarOptions));

and sending the email with:

 let mailOptions = await transporter.sendMail({
    from: '"Test - No Reply" <test@test.com>'
    to: 'someEmail@gmail.com, 
    subject: "Hello ✔",
    template: 'welcome',
  });

Oddly enough I still receive the email even though it says it cant find the file. How can I resolve this error and have nodemailer-express-handlebars not see the files as 'undefined.hbs'?

UPDATE:

I changed 'welcome' to 'welcome.hbs' in the nodemailer and now the error is saying it can't find 'welcome.hbs.hbs'. This makes sense, you would think the solution would be to remove the '.hbs' and make it 'welcome' but then we are back to the original error of 'undefined.hbs'.

Also, if i change the template to 'welcome2' it says it cant find 'welcome2.hbs'. Its weird... it's as though it becomes undefined only when the template file matches the filename which is what it should be.

emarel
  • 371
  • 7
  • 30
  • is welcome.hbs file present at the location? – kavigun Sep 23 '20 at 18:11
  • Yes. can confirm that /Users/person/Code/app/templates/ includes 'welcome.hbs' – emarel Sep 23 '20 at 18:12
  • okay. I think somehow it is not getting the file path as you are using handlebars here with nodemailer. Try changing the path of the html property value and also make it is a html propertu not template property, in the above code it still shows template as the property in sendMail() – kavigun Sep 23 '20 at 19:23
  • I changed 'welcome' to 'welcome.hbs' in the nodemailer and now the error is saying it can't find 'welcome.hbs.hbs'. This makes sense, you would think the solution would be to remove the '.hbs' and make it 'welcome' but then we are back to the original error of 'undefined.hbs'. Does this give you any insight on what you think the issue is? – emarel Sep 23 '20 at 19:38
  • Also, if i change the template to 'welcome2' it says it cant find 'welcome2.hbs'. Its weird... it's as though it becomes undefined only when the template file matches the filename which is what it should be – emarel Sep 23 '20 at 19:46
  • I've literally copied your handlebars settings into `index.js`, create a directory `templates` at same level, added `welcome.hbs` file inside, and it works. I would suggest reinstalling nodemailer, nodemailer-express-handlebars, and restarting your PC :) – Marian Sep 26 '20 at 21:48
  • Actually, there is another potential reason for this error: something inside `welcome.hbs` results in this error by trying to read a non-existent file. – Marian Sep 26 '20 at 21:50
  • I had exactly the same error. Your 'defaultLayout = false' helped me out. – Tichel Oct 04 '21 at 17:41

3 Answers3

5

My solution is:

const path = require('path')
const nodemailer = require('nodemailer');
const hbs = require('nodemailer-express-handlebars')

const { host, port, user, pass } = require('../config/mail.json')

var transport = nodemailer.createTransport({
    host,
    port,
    auth: { user, pass },
});

const handlebarOptions = {
    viewEngine: {
        extName: ".html",
        partialsDir: path.resolve('./src/resources/mail'),
        defaultLayout: false,
    },
    viewPath: path.resolve('./src/resources/mail'),
    extName: ".html",
};

transport.use('compile', hbs(handlebarOptions));

module.exports = transport;

The template folder in my project is: "src/resources/mail"

const mailer = require('../../modules/mailer');

mailer.sendMail({
            to: email,
            from: 'mail.example@examplemail.com',
            template: 'auth/forgot_password',
            context: { token },
        }, (err) => {
            if (err){
                console.log(err)
                return res.status(400).send({ error: 'Cannot send forgot password email'});
            }
            return res.send();
        })

My template file is "auth/forgot_password.html"

In my project a problem occurred by configs of handlebarOptions, and solution is:

const handlebarOptions = {
    viewEngine: {
        extName: ".html",
        partialsDir: path.resolve('./src/resources/mail'),
        defaultLayout: false,
    },
    viewPath: path.resolve('./src/resources/mail'),
    extName: ".html",
};
1

It should not be a template property rather it should be html property in the sendMail object:

 let mailOptions = await transporter.sendMail({
    from: '"Test - No Reply" <test@test.com>'
    to: 'someEmail@gmail.com, 
    subject: "Hello ✔",
    html: './templates/welcome.hbs',
  });
kavigun
  • 2,219
  • 2
  • 14
  • 33
1

Answering my own question. It looks as though the issue had to do with making it a async function with a callback which caused some type of undefined issue.

For an in depth answer with code reference you can see the solution here: https://github.com/yads/nodemailer-express-handlebars/issues/43

emarel
  • 371
  • 7
  • 30