Setup a contact form in React that sends email using Node.js

In this tutorial we’ll be setting up a contact form in a React application that sends and email using Node.js upon successful submission.

Let’s get started by installing Axios which we’ll use to handle the form POST request:

npm install axios

Next create a new file for the contact form component called ContactForm.js and add the following code:

import React, { Component } from "react";
import axios from "axios";

class ContactForm extends Component {
  constructor() {
    super();
    this.state = {
      name: "",
      email: "",
      message: "",
      status: "Submit"
    };   
  } 
  // render() {}
}

export default ContactForm;

Our contact form will have three fields: name, email and message. We’ll store the values entered into these fields in the component state. status is used to change the submit button text on form submission.

Next add the render() method that contains the markup for the contact form:

render() {
    let buttonText = this.state.status;
    return (      
        <form onSubmit={this.handleSubmit.bind(this)} method="POST">
            <div>
            <label htmlFor="name">Name:</label>
            <input
                type="text"
                id="name"
                value={this.state.name}
                onChange={this.handleChange.bind(this)}
                required
            />
            </div>
            <div>
            <label htmlFor="email">Email:</label>
            <input
                type="email"
                id="email"
                value={this.state.email}
                onChange={this.handleChange.bind(this)}
                required
            />
            </div>
            <div>
            <label htmlFor="message">Message:</label>
            <textarea
                id="message"
                value={this.state.message}
                onChange={this.handleChange.bind(this)}
                required
            />
            </div>
            <button type="submit">{buttonText}</button>
        </form>      
    );
}

Each form field has a handleChange to capture the value so let’s create the function for that:

handleChange(event) {
    const field = event.target.id;
    if (field === "name") {
      this.setState({ name: event.target.value });
    } else if (field === "email") {
      this.setState({ email: event.target.value });
    } else if (field === "message") {
      this.setState({ message: event.target.value });
    }
  }

Finally the handleSubmit function for when the form has been submitted:

 handleSubmit(event) {
    event.preventDefault();  
    this.setState({ status: "Sending" });  
    axios({
      method: "POST",
      url: "http://localhost:5000/contact",
      data: this.state,
    }).then((response) => {
      if (response.data.status === "sent") {
        alert("Message Sent");
        this.setState({ name: "", email: "", message: "", status: "Submit" });
      } else if (response.data.status === "failed") {
        alert("Message Failed");
      }
    });
  }

Here we’re using axios to POST all the data from the component’s state.

Next we need to setup the url on a Node.js server that will handle the POST request and send the email.

Create a new folder called backend and run the following commands to initiate & install the required dependencies:

cd backend
npm init -y
npm install express cors nodemailer
  • express – handles the route (/contact) from the POST request.
  • cors – allows for cross origin resource sharing between the frontend and the server.
  • nodemailer – module for Node.js applications that simplifies sending emails via SMTP.

Now in the backend folder create a new file called index.js and add the following to setup a server on port 5000:

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

const app = express();
app.use(cors());
app.use(express.json());
app.use("/", router);
app.listen(5000, () => console.log("Server Running"));

We now need to provide the host, username, and password for the SMTP:

const contactEmail = nodemailer.createTransport({
  host: "smtp.example.com",
  port: 587,
  auth: {
    user: "username@example.com",
    pass: "password",
  },
});

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

Test the server and SMTP connection by running node index.js. If successful you’ll see “Server Running” & “Ready to Send” logged in the terminal. To complete the contact form functionality we just need to setup the router and send the email:

router.post("/contact", (req, res) => {
  const name = req.body.name;
  const email = req.body.email;
  const message = req.body.message; 
  const mail = {
    from: name,
    to: "username@example.com",
    subject: "Contact Form Message",
    html: `<p>Name: ${name}</p><p>Email: ${email}</p><p>Message: ${message}</p>`,
  };
  contactEmail.sendMail(mail, (error) => {
    if (error) {
      res.json({ status: "failed" });
    } else {
      res.json({ status: "sent" });
    }
  });
});

Now if you submit the form you’ll get a “Message Sent” alert and receive and email.