Skip to main content

Command Palette

Search for a command to run...

Build a Contact Form with React and Nodemailer

Published
Build a Contact Form with React and Nodemailer
V

I'm a solutions engineer lead, GitHub Star, Director of WomenDevsSG, and co founder of ragTech. I work at the intersection of tech, systems, and leadership, and this blog is where I share my journey through all three. Expect honest reflections, real experiences, and thoughts that are still forming rather than polished career advice.

A contact form is essential for any business to provide a convenient way for their customers to reach them. It is typically found in a business' contact us page. In this tutorial, I will show you how to create a contact form with React and Nodemailer.

Some prerequisites needed to follow this tutorial:

  • Basic understanding of React (class-based)
  • Basic understanding of back-end (server-side) programming
  • Node and npm installed in your machine
  • A code editor like VS Code

Step 1: Build the Form

You can be creative in how you want to make it. You can use Bootstrap or CSS and it's all up to you! Usually, a contact form has 3 input fields: name, email and message. But for my example, I added a Subject field too. Here's what mine looks like:

ex

And this is what it looks like in my contact.js. (sorry for the ugly formatting, it looks better on Visual Studio Code I promise):

render() {
        return (
            <div className="section">
                <div className="container">
                    <div className="row">
                        <div className="col-md-12">
                            <div className="section-title">
                                <h2 className="title">Contact Us</h2>
                                <p>Let us know what you think! In order to provide better service,
                                     please do not hesitate to give us your feedback. Thank you.</p><hr/>
                                <form id="contact-form" onSubmit={this.submitEmail.bind(this)} 
                                    method="POST">
                                <div className="form-group">
                                <div className="row">
                                <div className="col-md-6">
                                    <input placeholder = "Name"  id="name" type="text" 
                                       className="form-control" required value={this.state.name} 
                                       onChange={this.onNameChange.bind(this)}/>
                                </div>
                                <div className="col-md-6">
                                    <input placeholder = "Email"  id="email" type="email"
                                      className="form-control" aria-describedby="emailHelp"
                                      required value={this.state.email} onChange=
                                      {this.onEmailChange.bind(this)}/>
                                </div>
                                </div>
                                </div>
                                <div className="form-group">
                                    <input placeholder = "Subject"  id="subject" type="text"
                                      className="form-control" required value={this.state.subject}
                                      onChange={this.onSubjectChange.bind(this)}/>
                                </div>
                                <div className="form-group">
                                    <textarea placeholder = "Message"  id="message" 
                                       className="form-control" rows="1" 
                                       required value={this.state.message}
                                       onChange= {this.onMsgChange.bind(this)}/>
                                </div>
                                <button type="submit" className="primary-btn submit">Submit</button>
                                </form>
                            </div>
                        </div>

                    </div>

                </div>
            </div>
        );
    }

I used Bootstrap and custom CSS styling for my Contact Form. I like how it looks clean and simple!

Step 2: Adding Handler Functions

Right now, the contact form is nothing but a static page that cannot send emails or anything. We will have to add functions to prepare for the back-end stuff coming later.

First, create the state variables to keep track of the states name, email, subject and message.

class Contact extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
          name: '',
          email: '',
          subject:'',
          message: ''
        }
    }

Then, let's create the onChange events functions to update our state variables when a user changes the value of the 4 input fields. And of course, we have added the onChange handler to our input elements in the render function.

onNameChange(event) {
        this.setState({name: event.target.value})
    }

onEmailChange(event) {
        this.setState({email: event.target.value})
    }

onSubjectChange(event) {
        this.setState({subject: event.target.value})
    }

onMsgChange(event) {
        this.setState({message: event.target.value})
    }

Step 3: Submit Email Function

So with the handler functions done, we now have to create a function that executes when the user clicks on the Submit button.

Upon clicking the Submit button, the submitEmail() will send a HTTP POST request to the API. A good npm package called Axios can make HTTP requests and automatically transforms JSON data. Run npm install axios to install the package. Read its documentation here for details.

The submitEmail() function will be as follows:

submitEmail(e){
        e.preventDefault();
        axios({
          method: "POST", 
          url:"/send", 
          data:  this.state
        }).then((response)=>{
          if (response.data.status === 'success'){
              alert("Message Sent."); 
              this.resetForm()
          }else if(response.data.status === 'fail'){
              alert("Message failed to send.")
          }
        })
}

resetForm(){
        this.setState({name: '', email: '',subject:'', message: ''})
}

Step 4: Set up Nodemailer Server-Side

We will use Node.js for our back-end.

Install npm install express cors nodemailer dotenv.

Then, create a server.js file, which contains the back-end logic.

const express = require('express');
const nodemailer = require('nodemailer');
const cors = require('cors');
require("dotenv").config();

In order for Nodemailer to send mails, it needs to have an SMTP which is a protocol used by email hosts such as gmail, hotmail, etc. To set it up:

const transporter = nodemailer.createTransport({
  host: "smtp.example.com", //replace with your email provider
  port: 587,
  auth: {
    user: process.env.EMAIL,
    pass: process.env.PASSWORD
  }
});

For more info, documentation here.

Next, verify the SMTP connection using the verify(callback):

// verify connection configuration
transporter.verify(function(error, success) {
  if (error) {
    console.log(error);
  } else {
    console.log("Server is ready to take our messages");
  }
});

Finally, set up the POST route to send the content of the contact form.

app.post('/send', (req, res, next) => {
  var name = req.body.name
  var email = req.body.email
  var subject = req.body.subject
  var message = req.body.message

  var mail = {
    from: name,
    to: // receiver email,
    subject: subject,
    text: message
  }

  transporter.sendMail(mail, (err, data) => {
    if (err) {
      res.json({
        status: 'fail'
      })
    } else {
      res.json({
       status: 'success'
      })
    }
  })
})

Now that our server.js is complete, we can run the server with the code:

node server.js

Congratulations!

We have built a contact form that can send messages to your specified email!

If you find this tutorial helpful, please feel free to like and share it to anyone who is trying to make a contact form. Cheers!

T

Your blog was an invaluable resource! Clear, concise, and incredibly helpful. Thank you for sharing your expertise and making it so much easier to implement. Kudos to you!

1
V

Thank you THARINDU SATHSARA :) I appreciate it!

S

As we can see here, there is node set up as well. So do we need to start node server separately, or with the above given set up, npm start will work.

1
V

Thanks for the great question. npm start would start the front-end React app only. So you would need to start the server separately. I will revise the article to be more clear thanks.

C

Really helpful, thanks a lot Victoria.

1
M

excellent

1
D

Hey Victoria! Where can I see the full code of this blog? I'd like to see it in detail because I think it's very useful. Thanks!!

O

Please do a tutorial for nodeMailer using pure html and javascript

1
V

Sure, I would love to in the future :) Stay tuned!

O

Would have love if you can write about it soon as i am facing some challenge using node mailer with pure html and Javascript Victoria Lo

Random Projects to Build

Part 32 of 32

This series features step-by-step tutorials on how to build some quick and simple apps for beginners to practice their skills. From bulletin boards to messaging apps, let's build anything!

Start from the beginning

The Better Firebase? Introduction to Clerk.js

A comparison between 2 popular authentication services