Search code examples
javascriptreactjsnext.jsnodemailernext.js13

error TypeError: Cannot read properties of undefined (reading 'headers') - Nextjs 13


I'm having issue in the title with my post API endpoint created within Nextjs.

My endpoint is for a form submission, where I take the inputs and forward them to my email. My current code sends the email and I receive it just fine on my email, HOWEVER it keeps returning the error in the title every time I make the request.

import { NextResponse, NextRequest } from "next/server"
import nodemailer from "nodemailer"

export async function POST(request: NextRequest, response: NextResponse) {
  const formData = await request.formData()

  const emailValue = formData.get("email")
  const messageValue = formData.get("message")
  const numberValue = formData.get("phone_number")

  if (!messageValue || !numberValue || !emailValue) {
    return NextResponse.json({ message: "please fill all required fields!" }, { status: 400 })
  }

  const transporter = nodemailer.createTransport({
    service: "gmail",
    auth: {
      user: process.env.EMAIL,
      pass: process.env.PASSWORD,
    },
    tls: {
      rejectUnauthorized: false,
    },
  })

  const mailOptions = {
    from: `${emailValue}`,
    to: `${process.env.EMAIL}`,
    subject: `Message from contact me page from ${numberValue} - ${emailValue} `,
    text: `${messageValue}`,
  }

  transporter.sendMail(mailOptions, (err, info) => {
    if (err) {
      return NextResponse.json({ message: `${err}` }, { status: 500 })
    }
    return NextResponse.json({ message: "Email sent successfully!" }, { status: 200 })
  })
}

I'm not sure what I'm doing wrong. I read in one thread about executing the NextResponse in a return statement, and even that didn't work.

The error I'm getting

- error TypeError: Cannot read properties of undefined (reading 'headers')
    at eval (webpack-internal:///(sc_server)/./node_modules/next/dist/server/future/route-modules/app-route/module.js:261:61)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

Solution

  • I'd say the problem is related to this issue.

    Your last two return NextResponse... calls are within the transporter.sendMail() callback so they won't return from the POST() function.

    Take advantage of Nodemailer's ability to return a promise instead of using callbacks...

    If callback argument is not set then the method returns a Promise object.

    try {
      await transporter.sendMail(mailOptions);
      return NextResponse.json(
        { message: "Email sent successfully!" },
        { status: 200 },
      );
    } catch (err) {
      return NextResponse.json({ message: err.toString() }, { status: 500 });
    }
    

    The alternative is to promis-ify the Nodemailer callback though IMO it's not nearly as clean

    return new Promise((resolve) => {
      transporter.sendMail(mailOptions, (err) => {
        const status = err ? 500 : 200;
        const message = err?.toString() ?? "Email sent successfully!";
        resolve(NextResponse.json({ message }, { status }));
      });
    });