Search code examples
javascriptnode.jsexpresshandlebars.jsnodemailer

How to populate a express handlebars page and have it send as email


I am using node.js, express, express-handlebars and nodemailer. I want to populate a HBS template, and than send it to email, as styled email... The result is the following (rendered in the browser first): enter image description here

Is a really simple page, where I inserted two images (as 64 base) and some text (following)..

The setup I used:

app.use(express.json());
app.set('view engine', 'hbs');
app.set('views', path.join(__dirname, 'views'));
app.use('/public', express.static(path.join(__dirname, 'public')));

Now, inside the controller, I just used some dummy data to display and render the view. I also used some FS functions to make the images to strings, which I will refactor later (for now functionality is my goal).


import { NextFunction, Request, Response } from "express";
import { CustomErrorRouteHandler } from "../../errors/CustomErrorRoute";
import * as fs from 'fs';
import path = require("path");
import { sendEmailHTML } from "../../helpers/sendBasicEmials/nodemailer";
import * as expressHandlebars from 'express-handlebars';
import { compile } from 'handlebars';


export const registerClientInvitation = async (req: Request, res: Response, next: NextFunction) => {
    try {
        const { clientName, clientEmail, content, invitationLink } = req.body;

        // get the path and stringfy the image to base64
        let imagePath = path.join(__dirname, '..', '..', '/public', '/images', 'main-icon-email.png');
        let logoImage = await fs.promises.readFile(imagePath);
        let string64ImageBase = Buffer.from(logoImage).toString('base64');
        
        // get the path and stringfy the image to base64
        let imageDemoEmail = path.join(__dirname, '..', '..', '/public', '/images', 'account-email.jpg');
        let imageDemo = await fs.promises.readFile(imageDemoEmail);
        let string64ImageDemoBase = Buffer.from(imageDemo).toString('base64');        


        // get the htmlTemplate path and make it a string
        let hbsTemplatePAth = path.join(__dirname, '..', 'views', 'emails', 'invitaion.hbs');
        // let compiled = compile(hbsTemplatePAth, {data})
        

        res.render('emails/invitation', { 
            title:              'Account invitation',
            clientEmail:        clientEmail, 
            clientName:         'Daniel Daniel', 
            content:            'Welcome! We extend our warm invitation for you to create an account on our platform. Your participation in this step is vital as it facilitates the process of document review and signature. By creating an account, you gain access to our platform where you can seamlessly review and sign your documents. Thank you for choosing our platform; we look forward to your participation!',
            invitationLink:     invitationLink,
            logo:               string64ImageBase,
            additionalImage:    string64ImageDemoBase
        });   
    } 
    catch (error) {
        console.log(error);
        next(new CustomErrorRouteHandler('Error while creating an invitation', 500, 'failed'));
    }
}

Instead of using render method, and just render it to the screen, I would like to send it to the email... I am thinking to use puppeteer to render on backend, create PDFs and send it like that, but that would be an overkill and would not reach my goal.

How can I do this? many thanks, Daniel


Solution

  • Since in your code you are importing a sendEmailHTML i'm going to assume that this method sends the email giving an HTML string.

    To obtain the HTML content of the email you can use the third parameter of the response.render method, which receives the generated HTML from the handlebars template:

    res.render(
        'emails/invitation',
        { 
            title: 'Account invitation',
            clientEmail: clientEmail, 
            clientName: 'Daniel Daniel', 
            content: 'Welcome! We extend our warm invitation for you to create an account on our platform. Your participation in this step is vital as it facilitates the process of document review and signature. By creating an account, you gain access to our platform where you can seamlessly review and sign your documents. Thank you for choosing our platform; we look forward to your participation!',
            invitationLink: invitationLink,
            logo: string64ImageBase,
            additionalImage: string64ImageDemoBase
        },
        (error, html) => {
            if (error) {
                // Treat here any error related with the html generation.
            } else {
                // Send email otherwise
                sendEmailHTML(clientEmail, html);
            }
    
            // Other code (send response to client?)
        }
    );