0

I'm trying to use handlebars with nodemailer in order to create a template for emails. Also, I'm trying to get the data from my mongodb database to be able to be displayed on this template. Nodemailer is working perfectly fine, but I've never used handlebars before, and I keep getting an error saying failed to lookup view \"orders\" in views directory. If anyone knows why this could be happening, I would really appreciate any help or guidance on how to fix this. Thank you!

mailer.js

import express from 'express';
import expressAsyncHandler from 'express-async-handler';
import nodemailer from 'nodemailer';
import hbs from 'nodemailer-express-handlebars';
import Order from './models/orderModel.js';

const mailerRouter = express.Router();

mailerRouter.post (
    '/order', 
expressAsyncHandler(async (req, res) => {
    const email = req.body.email
    const orderId = req.body.orderId 
    const em = req.body.em
    const sender = req.body.sender
    const emailBody = await Order.findById(orderId).exec((err, orderData) => {
      if (orderData) {
        res.render('orders', {data:orderData})
      }
    })
    const sub = `Order: ${orderId}`
    let transporter = nodemailer.createTransport({
      host: 'smtp.gmail.com',
      service: 'gmail',
      auth: {
        type: 'OAuth2',
        user: sender,
        pass: '',
        clientId: '',
        clientSecret: '',
        refreshToken: '',
      }
    })
   
    transporter.use('compile', hbs({
      viewEngine: 'express-handlebars',
      viewPath:'./views/'
    }))
        const mailOptions = {
        from: sender, 
        to: em, 
        subject: sub, 
        text: "Hello world?", // plain text body
        template: 'orders',
      }
      console.log(mailOptions.subject)
      transporter.sendMail(mailOptions, function (err, info) {
        if(err)
          console.log(err)
        else
          console.log(info);
     });
  
}))

export default mailerRouter;

server.js

import express from 'express';
import cors from 'cors';
import mongoose from 'mongoose';
import dotenv from 'dotenv';
import path from 'path';
import hbs from 'express-handlebars';
import returnRouter from './routers/returnRouter.js';
import mailerRouter from './mailer.js';

dotenv.config();

const app = express();
app.use(cors()); //and thisnp
app.use(express.json());
app.use(express.urlencoded({ extended: true }));


mongoose.connect(process.env.MONGODB_URL || 'mongodb://localhost/AM', {
    useNewUrlParser: true,
    useUnifiedTopology: true,
    useCreateIndex: true,
});


app.use('/api/orders', orderRouter);
app.use('/api/mailer', mailerRouter);

app.get('/', (req, res) => {
    res.send('Server is ready');
});

app.engine('hbs', hbs({
    defaultLayout: 'template',
    extname: '.hbs',
}));
app.set('views', __dirname + '/views');
app.set('view engine', 'hbs');

app.use((err, req, res, next) => {
    res.status(500).send({ message: err.message });
});

const port = process.env.PORT || 5000;
app.listen(port, () => {
    console.log(`Serve at http://localhost:${port}`);
});

orders.hbs (within a views folder)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>

    </style>
</head>
<body>
    {{#each data.orderItems}}
    <div>
        <h1>{{name}}</h1>
    </div>
    {{/each}}
</body>
</html>

Directory

- backend
    |-- modeles
    |     | -- orderModel.js
    |     | -- ... other files
    |
    |
    |-- routes
    |    | -- orderRoutes.js
    |    | -- ... other files
    |
    | 
    |-- views
    |    | -- orders.hbs       
    |
    | -- server.js
    | -- mailer.js
    | -- utils.js
    | ... other files
- frontend
    | -- other directories

pelotador.1
  • 195
  • 1
  • 12
  • I think it would help if you shared the structure of your views/ directory. It sounds like `orders` is not at the root and so you need to change the path in your `res.render` call. – 76484 Jun 26 '22 at 13:26
  • @76484 Hi, okay, I added my backend directory to the question. – pelotador.1 Jun 26 '22 at 23:03
  • I'm not sure, but my next guess is that the `viewPath:'./views/'` in your `transporter.use` call is pointing to the wrong place. Perhaps you need to use `__dirname + '/views'` as you do in server.js? – 76484 Jun 27 '22 at 00:14
  • so I ended up changing ```app.set('views', __dirname + '/views');``` to```app.set('views', path.join( __dirname, '/backend/views'));``` and that seems to have solved this problem, but the template is still not showing on the emails, so now I have to figure that out. Thank you for your help – pelotador.1 Jun 27 '22 at 02:40

0 Answers0