How and where to insert email template into NextJS

Hi All,

Is there a way to insert an email template into NextJS?

I tried adding a https://nextjs.org/docs/messages/no-title-in-document-head but somehow it was not included in .next after npm run build.

I keep having this error despite placing the /pages/_document.js into my /webhooks/cms-event folder when I run npm start.

I am currently using the App router instead of the pages router.

Error sending email notification: Error: ENOENT: no such file or directory, open 'C:\Users\Harold\OneDrive\Desktop\Course notes\next-reviews\.next\server\app\webhooks\app\webhooks\cms-event\pages\index.js'

Code snippets as follows:

./nodemailer/index,js

const nodemailer = require("nodemailer");
const ejs = require("ejs");
const fs = require("fs");
const path = require("path");

export async function sendEmail(options) {
    try {

        const template = fs.readFileSync(
            path.resolve(__dirname, `../app/webhooks/cms-event/pages/index.js`),
            "utf-8"
        );
        const html = ejs.render(template, options.templateVariables);
        const transporter = nodemailer.createTransport({
            host: process.env.EMAIL_HOST,
            port: process.env.EMAIL_PORT,
            auth: {
                user: "apikey",
                pass: process.env.SENDGRID_API_KEY,
            },
        });
        const mailOptions = {
            from: process.env.EMAIL_FROM,
            // to: options.email,
            to: process.env.EMAIL_TO,
            subject: options.subject,
            html: html,

        };
        //   console.log(mailOptions.html);
        await transporter.sendMail(mailOptions);
    } catch (error) {
        console.error(`Error sending email notification: ${error}`)
    }

};

.app/webhooks/cms-event/route.js

import { NextResponse } from "next/server";
import { revalidateTag } from 'next/cache'
import { CACHE_TAG_REVIEWS } from "lib/reviews";
import { sendEmail } from "../../../nodemailer/index.js";


export async function POST(request) {
  try {

    const payload = await request.json();
    console.log(`payload: ${JSON.stringify(payload, null, 2)}`)
    if (payload.model === 'review') {
      revalidateTag(CACHE_TAG_REVIEWS)
      await sendEmail({
        email: process.env.EMAIL_FROM,
        subject: `Game reviews - ${payload.event} for title: ${payload.title}`,
        templateName: "email_notification",
        templateVariables: payload
      })

    }
    console.log('revalidated:', CACHE_TAG_REVIEWS);
    return new Response(null, { status: 204 });
  } catch (error) {
    console.error('Error processing request:', error);
    return new Response('Error processing request', { status: 500 });
  }
}

.app/webhooks/cms-event/pages/index.js

import Head from 'next/head'

export default function Document({ event, entry }) {
  return (
    <>
      <Head>
        <meta charSet="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Email Notification on changes made to Game reviews</title>
      </Head>
      <body style={{ backgroundColor: '#f5f5f5', padding: '20px', fontFamily: 'Arial, sans-serif' }}>

        <div
          style={{
            maxWidth: 600,
            margin: "auto",
            backgroundColor: "#fff",
            padding: 20,
            borderRadius: 4,
            boxShadow: "0 0 10px rgba(0,0,0,.1)"
          }}
        >
          <h1
            style={{
              color: "#333",
              fontSize: 24,
              fontWeight: "bold",
              marginBottom: 20
            }}
          >
            Game Reviews - {event} for title: {entry.title}
          </h1>
          <p style={{ color: "#333", fontSize: 16, lineHeight: "1.5" }}>
            {entry.body}
          </p>
        </div>

      </body>
    </>
  )
}


Screenshot of the file directory

I went to do some research and came across react-email library.

Background info:
Currently using Strapi as CMS and wanting to have the webhook to be sent out as an email notification, therefore the file directory (./app/webhooks/cms-event/route.js) is where the payload would be executed whenever there is an update done.

So I tried using react-email library and have gotten this error as follows:

Error processing request: Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
    at Qc (C:\Users\Harold\OneDrive\Desktop\Course notes\next-reviews\.next\server\chunks\631.js:23726:15)
    at Z (C:\Users\Harold\OneDrive\Desktop\Course notes\next-reviews\.next\server\chunks\631.js:23734:17)
    at Mc (C:\Users\Harold\OneDrive\Desktop\Course notes\next-reviews\.next\server\chunks\631.js:23842:25)
    at fd (C:\Users\Harold\OneDrive\Desktop\Course notes\next-reviews\.next\server\chunks\631.js:24192:5)
    at exports.renderToStaticMarkup (C:\Users\Harold\OneDrive\Desktop\Course notes\next-reviews\.next\server\chunks\631.js:24246:12)
    at render (C:\Users\Harold\OneDrive\Desktop\Course notes\next-reviews\.next\server\chunks\631.js:1034:35)
    at sendEmail (C:\Users\Harold\OneDrive\Desktop\Course notes\next-reviews\.next\server\app\webhooks\cms-event\route.js:179:38)
    at POST (C:\Users\Harold\OneDrive\Desktop\Course notes\next-reviews\.next\server\app\webhooks\cms-event\route.js:219:19)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async C:\Users\Harold\OneDrive\Desktop\Course notes\next-reviews\.next\server\chunks\501.js:5632:37

Code snippets as follows:

Email template (./emails/index.tsx)

import { Html, Head, Body, Section } from '@react-email/components';
import * as React from 'react';

type EmailProps = {
  payloadBody: string,
}

const Email = (props: EmailProps) => {
  const {
    payloadBody = JSON.stringify(props.payloadBody, null, 2)
  } = props

  return (

    <Html lang="en" dir="ltr">
      <Head>
        <meta charSet="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Email Notification on changes made to Game reviews</title>
      </Head>
      <Body className="bg-gray-700 my-auto mx-auto font-sans">
        <Section className='mt-8 text-white'>


          {payloadBody}

        </Section>
      </Body>
    </Html>

  )
}

export default Email

sendEmail function (.nodemailer/index.js)

const nodemailer = require("nodemailer");
import { render } from '@react-email/render';
const Email = require('../emails/index.tsx');

export async function sendEmail(options, payload) {
    const emailHtml = render(<Email payloadBody={payload}/>,
    {
        pretty: true,
    });

    console.log(`emailHtml: ${emailHtml}`);
    try {
        const transporter = nodemailer.createTransport({
            host: process.env.EMAIL_HOST,
            port: process.env.EMAIL_PORT,
            auth: {
                user: "apikey",
                pass: process.env.SENDGRID_API_KEY,
            },
        });
        const mailOptions = {
            from: process.env.EMAIL_FROM,
            to: process.env.EMAIL_TO,
            subject: options.subject,
            html: emailHtml ,

        };
        // console.log(`mailOptions.subject: ${mailOptions.subject}`);
        await transporter.sendMail(mailOptions);
    } catch (error) {
        console.error(`Error sending email notification: ${error}`)
    }

};

Data to be parsed into email body (./app/webhooks/cms-event/route.js)

import { NextResponse } from "next/server";
import { revalidateTag } from 'next/cache'
import { CACHE_TAG_REVIEWS } from "lib/reviews";
import { sendEmail } from "../../../nodemailer/index.js";


export async function POST(request) {
  try {

    const payload = await request.json();
    // console.log(`payload: ${JSON.stringify(payload, null, 2)}`)
    if (payload.model === 'review') {
      revalidateTag(CACHE_TAG_REVIEWS)
      await sendEmail({
        email: process.env.EMAIL_FROM,
        subject: `Game reviews - ${payload.event} for title: ${payload.entry.title}`,
        // templateVariables: {
        //   html: payload.html
        // }
      }, payload)

    }
    // console.log('revalidated:', CACHE_TAG_REVIEWS);
    return new Response(null, { status: 204 });
  } catch (error) {
    console.error('Error processing request:', error);
    return new Response('Error processing request', { status: 500 });
  }
}

Do I need to convert the email body into a jsx/tsx format to resolve the error?

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.