How to Create a Secure Contact Form for Your Website using reCAPTCHA and EmailJS

Samuel Peters
7 min readApr 27, 2023

In this tutorial, we’ll guide you through the process of adding reCAPTCHA verification to a contact form built with React. You don’t need to be an expert in web development or security to follow along, but having some knowledge of React would be helpful.

By the end of the tutorial, you’ll have a fully-functional and secure contact form that you can use on your website. So, if you’re ready to get started, let’s dive in!

What is EmailJS

EmailJS is a cloud-based service that enables sending automated emails directly from your website’s front-end without needing a back-end infrastructure.

EmailJS supports Google reCAPTCHA verification before sending an email, and it can restrict submission if the data does not meet the required object. To enable this feature, first set up Google reCAPTCHA and link it to your EmailJS account.

Setting up Google reCaptcha

  1. Go to https://www.google.com/recaptcha and select “Admin Console” in the top-right corner.
  2. Choose “Register a new site” and fill in the necessary details.
  3. Save your site key and secret key, we’ll be needing it later in the course of this tutorial.
Make sure you select reCAPTCHA v2 as EmailJS does not support v3

Note that EmailJS only supports reCAPTCHA v2. When setting up your Google reCAPTCHA application, make sure to select reCAPTCHA v2.

Setting up EmailJS

  1. Go to the EmailJS website https://www.emailjs.com/ and sign up for an account.
  2. Once you’re logged in, click on “Email Services” in the left-hand menu.
  3. Choose your email service provider and follow the on-screen instructions to connect it to your EmailJS account.
  4. After you’ve connected your email service, click on “Email Templates” in the left-hand menu.
  5. Click the “Create new template” button and select your email service from the drop-down menu and Save

Connecting Google reCAPTCHA and EmailJS

  1. Log in to your EmailJS account and go to the “Email Template” tab.
  2. Choose “Settings” from the list of services.
  3. Enter your site key and secret key from your Google reCaptcha account.
  4. Save your settings.
  5. Copy your template_Id, Service_id and key we’ll use them as we progress

Adding reCaptcha to React for Secure Form Submissions with EmailJS

In this section, we’ll show you how to modify your React application to send the reCaptcha code along with your form data to EmailJS. To display the reCaptcha box, we’ll be using the react-google-recaptcha component.

This modification will enable you to include an extra layer of security to your contact form by validating the reCaptcha code before sending the email through EmailJS.

Here are the steps to add reCaptcha to a React application:

  1. Install the “react-google-recaptcha” package using npm or yarn.
  2. Import the “ReCAPTCHA” component into your component file.
  3. Add the component to your contact form, and pass in your site key as a prop.

Here is how the ContactForm Looks Like

import { useState, useRef, useEffect, createRef } from "react";
import ReCAPTCHA from "react-google-recaptcha";
import emailjs from "emailjs-com";

This code block imports the necessary modules to use in the React component. useState, useRef, and useEffect are React hooks that allow the component to manage state, create references, and perform side effects respectively. createRef creates a reference to the ReCAPTCHA component, while ReCAPTCHA is a React component that displays the ReCAPTCHA widget. emailjs is the module that enables sending emails using EmailJS.

export const ContactForm = () => {
const [status, setStatus] = useState(null);
const [formValue, setFormValue] = useState({
user_name: "",
message: "",
user_email: "",
});

This code block exports a React component named ContactForm. It initializes state using the useState hook with the status and formValue variables. status is used to determine the status of sending the email (whether it's successful or not), while formValue holds the values of the form inputs.

 const refCaptcha = createRef();
const form = useRef();

These lines create two references to be used in the component. refCaptcha is a reference to the ReCAPTCHA component, while form is a reference to the HTML form element.

useEffect(() => {
let timeout;

if (status === true || false) {
// Show the info message for 10 seconds
timeout = setTimeout(() => {
setAlertPrompt(null);
}, 10000);
}

return () => {
if (timeout) {
clearTimeout(timeout);
setStatus(null);
}
};
}, [status]);

This code uses the useEffect hook to perform side effects in the component. It sets a timer using setTimeout to show an info message for 10 seconds when the status is true or false. The return function is used to clean up any side effects when the component is unmounted.

const handleSubmit = (e) => {
e.preventDefault();
const token = refCaptcha.current.getValue();
setStatus(true);

const params = {
...formValue,
"g-recaptcha-response": token,
};
}

This code defines the SubmitForm function, which is called when the form is submitted. It prevents the default form submission behavior using, e.preventDefault() gets the token from the ReCAPTCHA component using refCaptcha.current.getValue(), and sets the status to true. It then creates a new params object that combines the formValue and g-recaptcha-response token.

Switch(true){
case formValue.user_name === "":
setAlertMessage("Name cannot be Blank");
setStatus(false);

break;

case formValue.user_email === "":
setAlertMessage("Email Address cannot be Blank");
setStatus(false);

break;

case token === undefined:
setAlertMessage("Recaptche Error... ");
setStatus(false);

break;

default:
emailjs
.send(
secret_key.mail_service_id,
secret_key.mail_template_id,
params,
secret_key.mail_public_key
)
.then(
(response) => {
if (response.status === 200) {

setAlertMessage("Sent SUCCESSFULLY");
setStatus(false);
setFormValue({});
}
// console.log("SUCCESS!", response.status

}

This code block is a switch statement that checks different conditions when the user submits the form.

First, it checks if the user did not provide their name, and if so, it sets an error message and sets the status to false, indicating that the form submission has failed.

Then, it checks if the user did not provide their email address, and if so, it sets an error message and sets the status to false.

Next, it checks if there is an error with the reCAPTCHA verification, and if so, it sets an error message and sets the status to false.

Finally, if all of the above conditions are not met, it calls the emailJs. send function to send the form data to the specified EmailJS service, passing in the required parameters such as the service ID, email template ID, public key, and form data. If the submission is successful (status code 200), it sets a success message and resets the form.

Adding the block of codes together

import { useState, useRef, useEffect, createRef } from "react";
import ReCAPTCHA from "react-google-recaptcha";
import emailjs from "emailjs-com";

export const ContactForm = () => {
const [status, setStatus] = useState(null);
const [formValue, setFormValue] = useState({
user_name: "",
message: "",
user_email: "",
});

const refCaptcha = createRef();
const form = useRef();

useEffect(() => {
let timeout;

if (status === true || false) {
// Show the info message for 9 seconds
timeout = setTimeout(() => {
setAlertPrompt(null);
}, 10000);
}

return () => {
if (timeout) {
clearTimeout(timeout);
setStatus(null);
}
};
}, [status]);

const handleSubmit = (e) => {
e.preventDefault();
const token = refCaptcha.current.getValue();
setStatus(true);

const params = {
...formValue,
"g-recaptcha-response": token,
};

switch (true) {
case formValue.user_name === "":
setAlertMessage("Name cannot be blank");
setStatus(false);
break;

case formValue.user_email === "":
setAlertMessage("Email address cannot be blank");
setStatus(false);
break;

case token === undefined:
setAlertMessage("reCAPTCHA error");
setStatus(false);
break;

default:
emailjs
.sendForm(
secret_key.mail_service_id,
secret_key.mail_template_id,
form.current,
secret_key.mail_public_key
)
.then(
(response) => {
if (response.status === 200) {
setAlertMessage("Sent successfully");
setStatus(false);
setFormValue({});
}
// console.log("SUCCESS!", response.status, response.text);
},
(err) => {
setAlertMessage(`Failed: ${err.text}`);
setStatus(false);
setFormValue({});
console.log("FAILED...", err.text);
}
);
}
};

return (
<form ref={form} onSubmit={handleSubmit}>
<input
type="text"
name="user_name"
placeholder="Name"
value={formValue.user_name}
onChange={(e) =>
setFormValue({ ...formValue, user_name: e.target.value })
}
/>
<input
type="email"
name="user_email"
placeholder="Email"
value={formValue.user_email}
onChange={(e) =>
setFormValue({ ...formValue, user_email: e.target.value })
}
/>
<textarea
name="message"
placeholder="Message"
value={formValue.message}
rols="5"
onChange={(e) =>
setFormValue({ ...formValue, message: e.target.value })
}
></textarea>
<ReCAPTCHA
sitekey={secret_key.recaptcha_site_key}
ref={refCaptcha}
onChange={() => setStatus(null)}
/>
<button type="submit">Send</button>
</form>
);
};

form{
display:flex;
flex-direction:column;
justify-content:center;
margin:2em 5em;
}
input, textarea{
padding:2em;
margin:1em;
border-radius:1em;
outline:none;
}

Import the CSS in your ContactForm Component.

Note: When sending an email using EmailJS, you need to make sure that the variables you pass in the params object have the same names as the ones defined in your EmailJS email template. This is because EmailJS uses these variable names to replace the corresponding values in your email template before sending it. If you use different variable names, the values won't be replaced correctly, and your email will not contain the expected content.

--

--

Samuel Peters
0 Followers

Web Developer, Open Source Contributor,