Search code examples
reactjsexpresscorsnodemailer

POST http://localhost:5000/ 403 (Forbidden) error


Currently running into an error when attempting to submit to a button. Back story here is that I am creating a contact me section for my portfolio and I am using nodemailer to make it happen. But when I submit i run into a couple of errors:

POST http://localhost:5000/ 403 (Forbidden) Contact.js:37 Uncaught (in promise) SyntaxError: Unexpected end of input (at Contact.js:37:1) at handleSubmit (Contact.js:37:1)

Below is my Contact.j for my react application:

import { useState } from "react";
import { Col, Container, Row } from "react-bootstrap";
import contactImg from "../assets/img/contact-img.svg";

export const Contact = () => {
    const formInitialDetails = {
        firstName: '',
        lastName: '',
        email: '',
        phone: '',
        message: ''
    }

    const [formDetails, setFormDetails] = useState(formInitialDetails);
    const [buttonText, setButtonText] = useState('Send');
    const [status, setStatus] = useState({});

    const onFormUpdate = (category, value) => {
        setFormDetails({
            ...formDetails,
            [category]: value
        });
    }

    const handleSubmit = async (e) => {
        e.preventDefault();
        setButtonText('Sending...');
        let response = await fetch("http://localhost:5000/#connect", {
            mode: "no-cors",
            method: "POST",
            headers: {
                "Content-Type": "Application/json;charset=utf-8",
            },
            body: JSON.stringify(formDetails),
        });
        setButtonText("Send");
        let result = response.json();
        setFormDetails(formInitialDetails);
        if (result.code ===200) {
            setStatus({ success: true, message: "Message sent successfully!"});
        } else {
            setStatus({ success: false, message: "Message was not sent. Please try again."})
        }

    };

    return(
        <section className="contact" id="connect">
            <Container>
                <Row className="align-items-center">
                    <Col md={6}>
                        <img src={contactImg} alt="Contact Us"/>
                    </Col>
                    <Col md={6}>
                        <h2>Get in Touch</h2>
                        <form onSubmit={handleSubmit}>
                            <Row>
                                <Col sm={6} className="px-1">
                                    <input type="text" value={formDetails.firstName} placeholder="First Name" onChange={(e) => onFormUpdate('firstName', e.target.value)}/>
                                </Col>
                                <Col sm={6} className="px-1">
                                <input type="text" value={formDetails.lastName} placeholder="Last Name" onChange={(e) => onFormUpdate('lastName', e.target.value)}/>
                                </Col>
                                <Col sm={6} className="px-1">
                                <input type="email" value={formDetails.email} placeholder="Email Address" onChange={(e) => onFormUpdate('email', e.target.value)}/>
                                </Col>
                                <Col sm={6} className="px-1">
                                <input type="tel" value={formDetails.phone} placeholder="Phone Number" onChange={(e) => onFormUpdate('phone', e.target.value)}/>
                                </Col>
                                <Col size={12} className="px-1">
                                    <textarea rows="6" value={formDetails.message} placeholder="Message" onChange={(e) => onFormUpdate('message', e.target.value)}/>
                                    <button type="submit"><span>{buttonText}</span></button>
                                </Col>
                                {
                                    status.message &&
                                    <Col>
                                        <p className={status.success === false ? "danger" : "success"}>{status.message}</p>
                                    </Col>
                                }
                            </Row>
                        </form>
                    </Col>
                </Row>
            </Container>
        </section>
    )
}

And below is my server.js file which contains the nodemailer:

const express = require("express");
const router = express.Router();
const cors = require("cors");
const nodemailer = require("nodemailer");

// server used to send email
const app = express();
app.use(cors());
app.use(express.json());
app.use("/", router);
app.listen(5000, () => console.log("Server Running"));
console.log(process.env.EMAIL_USER);
console.log(process.env.EMAIL_PASS);

const contactEmail = nodemailer.createTransport({
    service: 'yahoo',
    auth: {
        user: "exampleemail@yahoo.com",
        pass: "examplepassword"
    },
});

contactEmail.verify((error) => {
    if (error) {
        console.log(error);
    } else {
        console.log("Ready to Send!");
    }
});

router.post("/connect", (req, res) => {
    const name = req.body.firstName + req.body.lastName;
    const email = req.body.email;
    const message = req.body.message;
    const phone = req.body.phone;
    const mail = {
      from: name,
      to: "exampleemail@yahoo.com",
      subject: "Contact Form Submission - Portfolio",
      html: `<p>Name: ${name}</p>
             <p>Email: ${email}</p>
             <p>Phone: ${phone}</p>
             <p>Message: ${message}</p>`,
    };
    contactEmail.sendMail(mail, (error) => {
      if (error) {
        res.json(error);
      } else {
        res.json({ code: 200, status: "Message Sent!" });
      }
    });
  });

On my package.json I did add the "proxy": "http://127.0.0.1:5000", not sure if that affected something.

It's my first time using nodemailer so I would like to see what I am doing wrong or if im missing/overlooking something? I would greatly appreciate anyones feedback!

Not sure what I could be doing wrong but would like to learn from this!


Solution

  • Since you make a cross-origin request with mode: "no-cors", you will not be able to see the response body, even if the server supports CORS. No-cors mode gives you a so-called an "opaque response". As a consequence, response.json() reports an "Unexpected end of input".

    You can try this out in the browser console of this page:

    > await (await fetch("http://httpbin.org/json",{mode:"no-cors"})).json()
    Uncaught SyntaxError: Unexpected end of input
    

    Ensure that your server localhost:5000 supports CORS and use mode: "cors" (the default) instead. Compare this to:

    > await (await fetch("http://httpbin.org/json")).json()
    {slideshow: {…}}