How to use EmailJS for a Contact Us page

Table of contents

I remember some time ago while working on a side project. I was to implement a simple contact us page as part of the project. Initially, I used Google Firebase to store the responses. Then, I found EmailJS and it was so simple to use and very efficient.

In this article, you will learn how to set up a EmailJS account and integrate it into your ReactJS/NextJS application.

First, let’s start by creating a new React Project using Vite.
Open your VSCode or any other code editor, open the terminal and type in: yarn create vite or npm create vite@latest then follow the prompts. I will be using React with Typescript in this example.

You can checkout the official vite website for more information on Vite.

Next, let’s install some dependencies. In your terminal, type in yarn add @emailjs/browser react-hook-form. Then run yarn dev to start the project.
You can get more info on react-hook-form here

I will delete some default files in the directory and change some styles as seen below.

Next, in my App.tsx, I will put up a basic contact us form.

import styles from "./app.module.css";
import { useForm } from "react-hook-form";
import { useState } from "react";

interface IFormInput {
  firstName: string;
  lastName: string;
  email: string;
  phone: string;
  message: string;
}
function App() {
  const [loading, setLoading] = useState(false);

  const {
    register,
    handleSubmit,
    reset,
    formState: { errors },
  } = useForm<IFormInput>();
  const onSubmit = async (data: IFormInput) => {
    console.log(data);
  };

  return (
    <div className={styles.contact_form}>
      <h1>Contact Form</h1>
      <p>Our friendly team would love to hear from you.</p>

      <form className={styles.form} onSubmit={handleSubmit(onSubmit)}>
        <div className={styles.group}>
          <div className={styles.input_group}>
            <label htmlFor="firstName">First Name</label>
            <input
              type="text"
              {...register("firstName", { required: true })}
              placeholder="Enter your first name"
            />
            {errors.firstName && (
              <span className={styles.error}>This field is required</span>
            )}
          </div>
          <div className={styles.input_group}>
            <label htmlFor="lastName">Last Name</label>
            <input
              type="text"
              {...register("lastName", { required: true })}
              placeholder="Enter your last name"
            />
            {errors.lastName && (
              <span className={styles.error}>This field is required</span>
            )}
          </div>
        </div>
        <div className={styles.input_group}>
          <label htmlFor="email">Email Address</label>
          <input
            type="email"
            {...register("email", { required: true })}
            placeholder="Enter your email address"
          />
          {errors.email && (
            <span className={styles.error}>This field is required</span>
          )}
        </div>
        <div className={styles.input_group}>
          <label htmlFor="phone">Phone Number</label>
          <input
            type="tel"
            {...register("phone", { required: true })}
            placeholder="+2348123456789"
          />
          {errors.phone && (
            <span className={styles.error}>This field is required</span>
          )}
        </div>
        <div className={styles.input_group}>
          <label htmlFor="message">Message</label>
          <textarea
            {...register("message", { required: true })}
            placeholder="Leave us a message..."
          />
          {errors.message && (
            <span className={styles.error}>This field is required</span>
          )}
        </div>

        <button disabled={loading} className={styles.button} type="submit">
          {loading ? "Sending..." : "Send Message"}
        </button>
      </form>
    </div>
  );
}

export default App;

In the code snippet above, I’m using CSS module for my component alongside react-hook-form for my form validation. I declared a loading state set to false by default.

Next, I want to go to the official EmailJS website and signup for a free account. The signup is straightforward.

Next, I will sign in to my account and setup a new email service. For this example, we will use only Gmail. On your dashboard, select Add New Service and select Gmail. Then select Connect Service. This will take you to your Gmail account to link together with Emailjs. Once done, select Create Service.

Next, we need to create an Email Template. On your dashboard, select Email Templates and select Create New Template. For the free version, you can only create 2 Email Templates.

You can configure your Email Template as you want.

In the image above, template body corresponds with the payload I’m sending from my app. You should also specify the receiver email and you can add extra Bcc and CC.

Next, we need to get 3 important credentials. The service ID, the template ID and your public key.

To get the template ID, navigate to the settings tab of the template and you will find the template key. You can as well modify the template name here.

Next, go to the Email Services screen and you will find the service ID for the service we connected earlier.

Next, go to Account and under the General tab, you will find your public and private keys. We only need the public key.

Lastly, we go back to our code and update our onSubmit function and integrate emailjs into our code.
To do this, in your App.tsx, import emailjs from "@emailjs/browser";

Then modify your onSubmit function as follow:

Finally, your App.tsx should look like this:

import styles from "./app.module.css";
import { useForm } from "react-hook-form";
import { useState } from "react";
import emailjs from "@emailjs/browser";

interface IFormInput {
  firstName: string;
  lastName: string;
  email: string;
  phone: string;
  message: string;
}
function App() {
  const [loading, setLoading] = useState(false);

  const {
    register,
    handleSubmit,
    reset,
    formState: { errors },
  } = useForm<IFormInput>();
  const onSubmit = (data: IFormInput) => {
    setLoading(true);

    const templateParams = {
      ...data,
    };

    emailjs
      .send(
        "your_service_id",
        "your_template_id",
        templateParams,
        "your_public_key"
      )
      .then(() => {
        reset();
        setLoading(false);
        alert("One of our agents will contact you soon!");
      });
  };

  return (
    <div className={styles.contact_form}>
      <h1>Contact Form</h1>
      <p>Our friendly team would love to hear from you.</p>

      <form className={styles.form} onSubmit={handleSubmit(onSubmit)}>
        <div className={styles.group}>
          <div className={styles.input_group}>
            <label htmlFor="firstName">First Name</label>
            <input
              type="text"
              {...register("firstName", { required: true })}
              placeholder="Enter your first name"
            />
            {errors.firstName && (
              <span className={styles.error}>This field is required</span>
            )}
          </div>
          <div className={styles.input_group}>
            <label htmlFor="lastName">Last Name</label>
            <input
              type="text"
              {...register("lastName", { required: true })}
              placeholder="Enter your last name"
            />
            {errors.lastName && (
              <span className={styles.error}>This field is required</span>
            )}
          </div>
        </div>
        <div className={styles.input_group}>
          <label htmlFor="email">Email Address</label>
          <input
            type="email"
            {...register("email", { required: true })}
            placeholder="Enter your email address"
          />
          {errors.email && (
            <span className={styles.error}>This field is required</span>
          )}
        </div>
        <div className={styles.input_group}>
          <label htmlFor="phone">Phone Number</label>
          <input
            type="tel"
            {...register("phone", { required: true })}
            placeholder="+2348123456789"
          />
          {errors.phone && (
            <span className={styles.error}>This field is required</span>
          )}
        </div>
        <div className={styles.input_group}>
          <label htmlFor="message">Message</label>
          <textarea
            {...register("message", { required: true })}
            placeholder="Leave us a message..."
          />
          {errors.message && (
            <span className={styles.error}>This field is required</span>
          )}
        </div>

        <button disabled={loading} className={styles.button} type="submit">
          {loading ? "Sending..." : "Send Message"}
        </button>
      </form>
    </div>
  );
}

export default App;

And that is it. You can now get new contact us messages directly in the receiver email you specified.

Thank you for reading. If this was helpful, leave a like, share and comment.
Cheers

1
Subscribe to my newsletter

Read articles from Olufeyimi Samuel directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Olufeyimi Samuel
Olufeyimi Samuel

Self-taught Frontend Developer passionate about clean, responsive and scalable codes. I speak Typescript, JavaScript, Next.JS, ReactJS and everything CSS