Search code examples
node.jsexpressnodemailerbody-parser

reference error prop not defined, body parser not working, node, express, nodemailer


I have a form that I want to send data to an email subscriber via STMP using nodemailer in express. I am not permitted to use a database, and I am getting an error with the body-parser middleware.

Errors I got from the client: Request failed with status code 404,ERR_BAD_REQUEST.

Errors I got from server: ReferenceError: firstnameprop is not defined when attempting to start server `

The only time I can send the test email I wrote in nodemailer is when the server restarts. My goal is to send the data from the form only when the request is sent, not by restarting the server.

In the past using a database, controllers, and routes I was successful in integrating client and server side to communicate. Without a database, I am not able to declare the prop.

My question is what is wrong with the body-parser? (yes it is installed) How else can I troubleshoot? Am I missing anything?


UPDATE: I added headers to Axios req, and updated `server.js

2ND UPDATE: got the client to work, I changed app.get to app.post, server still returning undefined


package.json

server error

index.js

const express = require("express");

// app

const app = express();
const bodyParser = require("body-parser");
const jsonParser = bodyParser.json();
const cors = require("cors");
const morgan = require("morgan");
const nodemailer = require("nodemailer");

// morgan
app.use(morgan("tiny"));

app.use(jsonParser); // use it globally
app.use(bodyParser.urlencoded({ extended: false }));

app.use(cors());

// server routee
app.get("/", (req, res) => {
  res.json({ message: "Hello world" });
});

// send route route
app.post("/send-email", jsonParser, (req, res) => {
  const { firstnameprop } = req.body;
  console.log("response", res);
}); 

let transporter = nodemailer.createTransport({
  host: "smtp.office365.com",
  port: 465,
  secure: false,
  auth: {
    user: "...",
    pass: "...",
  },
});

let mailOptions = {
  from: "someemail.com",
  to: "someemail.com",
  subject: "Sending Email using Node.js",
  text: `Name: ${firstnameprop}`,

  //ERROR IS BELOW, PROP IS NOT DELARED, HOW CAN I FIX THIS?
  html: `<html><body><h1>Hello ${firstnameprop} !</h1><p>This is a test from development server from website.com/</p></body></html>`,
  };

  transporter.sendMail(mailOptions, function (error, info) {
    if (error) {
      console.log(error);
    } else {
      console.log("Email sent: " + info.response);
    }
  });

  app.listen(5000, () => {
    console.log("Server started on port 5000");
  });

HireingForm.js

import { useNavigate } from "react-router-dom";
import { Card, Col, Form, Row } from "react-bootstrap";
import { useRef, useState } from "react";
import axios from "axios";
//some more imports

const HiringForm = () => {
const matchSm = useMediaQuery("(max-width: 728px)");
const refForm = useRef();

// props
const [firstnameprop, setFirstNameProp] = useState("");

const sendEmailHandler = (e) => {
     e.preventDefault();
     console.log("submitted list", firstnameprop);

 axios
    .post(
      "http:.localhost:5000/send-email", 
       { firstnameprop },
        {
          headers: {
          "Content-Type": "application/json",
        },
      }
    )
    .then((response) => {
      console.log(response.data);
    })
    .catch((error) => {
      console.log(error);
    });
};


   {/* NOTE, THE FORM WORKS, I CONSOLED THE PROP AND WAS SUCCESSFUL WITH THE LOG */}
   return (
   <>
     <Form
       ref={refForm}
       onSubmit={sendEmailHandler}
       className={hiring}
       autoComplete="on"
      >
       <FirstName
       firstnameprop={firstnameprop}
       setFirstNameProp={setFirstNameProp}
       />
       {!checked ? <SubmitButton /> : <SubmitButtonDisabled />}
     </Form>
    </>
  
  export default HiringForm;

Solution

  • got the answer:

    The problem was in both the client where I had /send-email endpoint, and I changed it to http://localhost5000/send-email I also added a header"

     axios
          .post(
            "http://localhost:5000/send-email",
            { firstnameprop },
            {
              headers: {
                "Content-Type": "application/json",
              },
            }
          )
          .then((response) => {
            console.log(response.data);
          })
          .catch((error) => {
            console.log(error);
          });
      };
    

    Solution for the server, after researching and finding this question: I implemented the code and made some additional changes, I will paste it below:

    As you see I changed the app.post to a try and catch including some plain HTML, and smtpTransport.sendMail function Notice the smtpTransport = nodemailer.createTransport function was OUTISDE the try catch function. I passed the firstnameprop with req.body.firstnameprop and not const {firstnameprop} = req.body I found not using a HTML template in this case was best.

    const express = require("express");
    const app = express();
    const bodyParser = require("body-parser");
    const jsonParser = bodyParser.json();
    const cors = require("cors");
    const morgan = require("morgan");
    
    // morgan
    app.use(morgan("tiny"));
    const nodemailer = require("nodemailer");
    let smtpTransport = require("nodemailer-smtp-transport");
    
    app.use(jsonParser); // use it globally
    app.use(bodyParser.json()); // to support JSON-encoded bodies
    app.use(bodyParser.urlencoded({ extended: true })); // to support URL-encoded bodies
    app.use(cors());
    
    //server route
    app.get("/", (req, res) => {
      res.json({ message: "Hello world" });
    });
    
    //CHANGES START HERE --------------------------------------
    app.post("/send-email", (req, res) => {
      console.log(req.body);
      try {
        const mailOptions = {
          from: "…",
          to: "…",
          subject: "Sending Email Test",
          html: `
          <p>You have a new contact request.</p>
          <h3>Contact Details</h3>
          <ul>
            <li>Name: ${req.body.firstnameprop}</li>
          </ul>
          `,
        };
    
        smtpTransport.sendMail(mailOptions, (err, info) => {
          if (err) {
            res.status(500).send({
              success: false,
              message: "Something went wrong. Try again later",
            });
          } else {
            res.send({
              success: true,
              message: "Thanks for contacting us. We will get back to you shortly",
            });
          }
        });
      } catch (error) {
        res.status(500).send({
          success: false,
          message: "Something went wrong. Try again later",
        });
      }
    });
    
    smtpTransport = nodemailer.createTransport(
      smtpTransport({
        host: "...",
        port: 465,
        secure: true,
        auth: {
          user: "...",
          pass: "...",
        },
      })
    );
    
    app.listen(5000, () => {
      console.log("Server started on port 5000");
    });