Search code examples
javascriptnode.jshtml-emailnodemailerexpress-handlebars

How to configure express-handlebars to link it with nodemailer?


Well I have an API which sends an email through Nodemailer. I want the emails to be rendered as HTMLs thus I tried to connect nodemailer-express-handlebars to my api:

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

const sendMail = async (options) => {
    try {
        const transporter = nodemailer.createTransport({
            host: process.env.EMAIL_HOST,
            port: process.env.EMAIL_PORT,
            auth: {
                user: process.env.EMAIL_USER,
                pass: process.env.EMAIL_PASS,
            },
        })

        transporter.use(
            'compile',
            hbs({
                viewEngine: {
                    extName: '.hbs',
                    partialsDir: './views/', 
                    layoutsDir: './views/layouts',
                    defaultLayout: '',
                },
                extName: '.hbs',
                viewPath: 'views',
            })
        )
        const mailOptions = {
            from: 'abc@abc.com',
            // to: 'cde@cde.com',
            to: options.email,
            bcc: 'me@me.com',
            subject: 'Booking confirmation',
            template: 'emailHtml',
        }

        await transporter.sendMail(mailOptions)
    } catch (err) {
        return new AppError(
            'There was an error while sending the email. Please, try again later.',
            500
        )
    }
}

Here is my files structure for that api (the api itself is in email.js, and the util folder is in the root):

The api itself is in email.js

In the main.hbs there is just standard html5 markup with {{{body}}} in its body and in emailHtml.hbs there is just hello world in h1 tag.

However, it doesn't work (I thought the problem could be in wrong path but I tried lots of combinations). I know there is a way to just specify html: <h1> hello world </h1> using styles and variables but this is not an appropriate solution for me, so a modular one would be very helpful to me. When I remove hbs configuration and put just plain text in mailOptions emails have been delivered, but once I put template it stops working. Dotenv is configured, I just didn't put it here.

Any ideas?


Solution

  • if email.js and layouts folder are in same folder than following code will work.

    const nodemailer = require('nodemailer') 
    const hbs =require('nodemailer-express-handlebars)
    
    const sendMail = async (options) => {
        try {
            const transporter = nodemailer.createTransport({
                host: process.env.EMAIL_HOST,
                port: process.env.EMAIL_PORT,
                auth: {
                    user: process.env.EMAIL_USER,
                    pass: process.env.EMAIL_PASS,
                },
            })
    
            transporter.use(
                'compile',
                hbs({
                    viewEngine: {
                        extName: '.hbs',
                        partialsDir: 'layouts/', 
                        layoutsDir: 'layouts/',
                        defaultLayout: 'emailHtml',
                    },
                    extName: '.hbs',
                    viewPath: 'layouts/',
                })
            )
            const mailOptions = {
                from: 'abc@abc.com',
                // to: 'cde@cde.com',
                to: options.email,
                bcc: 'me@me.com',
                subject: 'Booking confirmation',
                template: 'emailHtml',
            }
    
            await transporter.sendMail(mailOptions)
        } catch (err) {
            return new AppError(
                'There was an error while sending the email. Please, try again later.',
                500
            )
        } }