Creating a contact form with Next.js: A Simple Guide to Sending Emails for your blog

10 Jan 2023 / 2 min read

In this article, I will walk you through an easy way to create a form and collect user data via mail in Next.js. This is perfect when you have a portfolio website (like mine), and you want to have a way for people to get in touch with you.

One of my first blogs was built with Gatsby and hosted on Netlify, and there was one neat feature, the ability to collect form data with almost zero configs.

Recently, I rebranded my blog and decided to use the more popular and modern Next.js, which I've also been using for a couple of years at work. And decided to give Vercel a shot with all their smooth marketing and apple-like presentations.

It was smooth as butter, just as expected, but the sad thing was that I could no longer receive the form data so quickly, so I had to get creative.

And that's what we'll do for the next five minutes. We will build a form that collects user input and emails it back to us on our behalf.

Let's have a look into the tech stack:

  • 👉🏻

    Next.js - We're really interested in the back-end API routes here. Feel free to use whatever you like if you have a server up and running already

  • 👉🏻

    SendGrid - What we're going to use to send ourselves an email with the form data

  • 👉🏻

    Tailwindcss (optional) - Make sure that it looks pretty and the UX rocks :)

If you want to skip the tutorial and get straight to the point, here's the final code.

Step 1: Create the form

The first thing that we need to do is to create the React form. We want to collect the name, email, and message and then send a post request to an api /api/contact route we'll create later to handle the email delivery

1const Input = (props) => {
2  const className = `
3        w-full my-3 p-4 rounded-lg
4        text-zinc-50 placeholder:text-zinc-300
5        font-medium focus:outline-zinc-500 bg-zinc-200/50
6    `;
8   return props.isTextarea ? (
9    <textarea {...props} className={className} />
10  ) : (
11    <input {...props} className={className} />
12  );
15 export default Input;
1import { useState } from "react";
2import Input from "./Input";
4 export default function Home() {
5  const [data, setData] = useState({
6    name: "",
7    email: "",
8    message: "",
9  });
11   const onChange = (e) => setData({, []: });
13   const onSubmit = async (e) => {
14    e.preventDefault();
16     await fetch("/api/contact", {
17      method: "POST",
18      body: JSON.stringify(data),
19    });
21     setData({
22      name: "",
23      email: "",
24      message: "",
25    });
26  };
28   return (
29    <div className="bg-gradient-to-br from-blue-700 via-blue-800 to-gray-900">
30      <div className="max-w-[600px] mx-auto h-screen flex flex-col justify-center">
31        <form
32          className="p-20  border-4 border-white/60 rounded-xl"
33          onSubmit={onSubmit}
34        >
35          <h1 className="text-white text-5xl font-semibold mb-8">Contact</h1>
37           <Input
38            placeholder="Name"
39            name="name"
40            value={}
41            onChange={onChange}
42          />
43          <Input
44            placeholder="Email"
45            name="email"
46            value={}
47            onChange={onChange}
48          />
49          <Input
50            placeholder="Message"
51            name="message"
52            onChange={onChange}
53            isTextarea
54            rows={5}
55            value={data.message}
56          />
57          <button className="mt-3 py-4 px-10 bg-blue-600 text-white font-semibold rounded-lg shadow-lg hover:shadow-zinc-600/30 transition hover:bg-blue-700">
58            Submit
59          </button>
60        </form>
61      </div>
62    </div>
63  );

We've created an Input component and then built the Form as you would typically do.

Step 2: Set up the api route

Next we are going to create the api route and use SendGrid to send ourselves an email with the form data.

You can use other email delivery providers but I found that SendGrid is the most straightforward to use and requires the minimum effort to get it running.

It also has a generous free plan which makes it ideal for a blog.

1import sgMail from "@sendgrid/mail";
3 export default async function handler(req, res) {
4  const form = JSON.parse(req.body);
6   sgMail.setApiKey(process.env.SENDGRID_API_KEY);
8   try {
9    const message = {
10      to: process.env.CONTACT_EMAIL,
11      from: process.env.CONTACT_EMAIL,
12      subject: `Contact form - ${}`,
13      html: `
14        <div>name: ${}</div>
15        <div>email: ${}</div>
16        <div>message: ${form.message}</div>
17      `,
18    };
20     await sgMail.send(message);
22     res.status(200).json({ message: "Form submitted successfully" });
23  } catch (error) {
24    console.error(error);
25    res.status(400).json({ error });
26  }

There are few things that happen in here:

  • 👉🏻

    We set the send grid api key (I'll show you where to get it from the next section)

  • 👉🏻

    We create the message. Note the html field. That is the place to use a pretty template if needed

  • 👉🏻

    And lastly we send and wait.

Step 3: Get the SendGrid credentials

The last bit that we need is to create an account on SenGrid get the credentials.

Go create an account on SendGrid and then generate a new API key with full access and make sure to save the generated hash.

Now you can go and create an .env file and paste your key:


If you try to send an email now youre going to get a 403 and that's because there is one extra step that we need to make.

We need to authenticate our email. That's because SendGrid needs knows that it's us who's using the email and not some miscellaneous users.

Go to and follow the steps to add a new sender.

After all that is done you should be able to send emails 🎉

Happy Coding!