# Email contact form using NextJS (App router)

### An overview of what we’ll be doing here

You must have come across contact forms on a lot of websites on the internet. We will be building a similar contact form. We will be using [**NextJS**](https://nextjs.org) with the app router and first, build our Contact Form UI. Then we will use route handlers to create an API route to send an email to our gmail with the form details using [**Nodemailer**](https://nodemailer.com).

### Create a new NextJS project

I’m using NextJS version 13.4 for this tutorial. The app router is now stable from this version onwards. To create a new project type:

```bash
pnpm create next-app
```

Provide a project name and continue with the defaults. TailwindCSS will be now installed by default which we can use for styling the form. Open the project folder in **VSCode** (or any IDE that you are using).

![Initial project structure](https://cdn.hashnode.com/res/hashnode/image/upload/v1690273108185/8ed2d8d5-6c72-4a43-a998-c1e6e5885687.png align="center")

This is the basic project structure. Now let's start the NextJS development server using:

npm run dev

The server now starts at [http://localhost:3000](http://localhost:3000/). You can view the website by going to this URL.

![Default NextJS starting page](https://cdn.hashnode.com/res/hashnode/image/upload/v1690273110789/faf86f3c-1442-43dd-82cc-c4dba0d64c02.png align="center")

### Creating a simple contact form

Let's start by editing **app/page.tsx**. Now let's remove the boilerplate code and just retain the **main** tag. We will be building our form inside it. Since will be doing some client-side interactions with our form, It must be a client component. So we can either convert the file **page.tsx** into a **client component** (which is not recommended as we usually use components in that file as server components) or we can create a new file and then make it a client component which is what we’re going to do. Let’s create a **component** folder and then new file **contact.tsx** where we will be creating the form. We will be installing [**react-hook-form**](https://www.react-hook-form.com) for managing our forms.

To install **react-hook-form**:

```bash
pnpm i react-hook-form
```

Also, we will be separating the email sending logic into a separate file in the **utils** folder for simplifying our codebase. Check the following images to remove any confusion as of now.

![Current project structure](https://cdn.hashnode.com/res/hashnode/image/upload/v1690273113114/4735098a-dc22-456f-92c7-ea2c32f1f3ec.png align="center")

![Basic UI flow](https://cdn.hashnode.com/res/hashnode/image/upload/v1690273115742/42282f6d-2bf6-44a2-921f-aad9b9e0e79a.png align="center")

I will be adding here the code snippets for **page.tsx** and **contact.tsx** below for your reference

%[https://gist.github.com/ByteCrak07/a6cbb910233cb170f2750528eea41300] 

*<mark>app/page.tsx</mark>*

%[https://gist.github.com/ByteCrak07/64cbe56d338a073d897c2db64e358b3d] 

*<mark>components/contact.tsx</mark>*

> Note that I have added **‘use client’;** to the first line which makes **Contact** a client component. We need to use this syntax from now on in NextJS if we are using app router because by default every components are server components. Go to [this link](https://nextjs.org/docs/getting-started/react-essentials) to know more about server and client components.

%[https://gist.github.com/ByteCrak07/a5697e68f29bfd2ae74b25939c59c64b] 

*<mark>utils/send-email.ts</mark>*

For now our form UI is completed, and as you can see the data from the form will be just logged to the console by the **sendEmail** function as of now. We just need to call an api to send the email inside that function. As you can see in the snippet I have added some styling for our components using **tailwindcss** classes just that it looks nice. Also the logic for the form is handled by **react-hook-form** which simplifies a lot of stuff regarding handling of forms in react. Right here I have used only a basic implementation of the library. You can go to [react-hook-form.com](https://www.react-hook-form.com) or read through this [tutorial from freecodecamp](https://www.freecodecamp.org/news/how-to-create-forms-in-react-using-react-hook-form) to learn more about it.

This is how our form looks now:

![Form UI](https://cdn.hashnode.com/res/hashnode/image/upload/v1690273117974/9aef6eae-5ac4-4747-91c8-31998bfc8dd3.png align="center")

### Setting up Nodemailer and API

Now that our basic form is completed, let’s build our API using **route handlers** in NextJS. But first, we need to install **nodemailer**. Nodemailer is a module for Node.js that makes sending emails from a server an easy task. To install it along with its types:

```bash
pnpm i nodemailer @types/nodemailer
```

Create a new folder **api** and another folder **email** inside it. Now create a new file **route.ts** inside it. The file path will be **app/api/email/route.ts**. It is done this way to create our api with the endpoint as **“api/email”**. Check out [this doc](https://nextjs.org/docs/app/building-your-application/routing/router-handlers) for more information. The current project structure will be as follows:

![Current project structure](https://cdn.hashnode.com/res/hashnode/image/upload/v1690273120242/137c586a-4adf-4d8e-9aa4-8ef7b0808faa.png align="center")

We can create a simple POST req route using the following snippet:

```typescript
import { type NextRequest, NextResponse } from 'next/server';

export async function POST(request: NextRequest) {
  return NextResponse.json('Hello from API!');
}
```

We will be building the rest inside this function. But first we need our Gmail credentials for nodemailer which we will store as environment variables in a .env file.

```plaintext
MY_EMAIL=youremail@gmail.com
MY_PASSWORD=*******(App password)
```

From now onwards we cannot provide our actual gmail password for this purpose. Previously we could have enabled **less secure apps** option and continue with our actual password. But from now on we need **App password** to be used here. For getting an app password we need to first enable **2FA (2 Factor Authentication)** in our google account. For that we need to go to [myaccount.google.com](https://myaccount.google.com/) and enable 2FA first which is a simple process. After that go to [myaccount.google.com/apppasswords](https://myaccount.google.com/apppasswords) to setup app password. You might be asked to verify its you again.

![App password](https://cdn.hashnode.com/res/hashnode/image/upload/v1690273122588/f36d6e3e-cfb8-4123-b9fd-ae10011d0ad3.png align="center")

From the UI select app as **Mail** and device as **custom** and then provide any name you want. (I provided **nodemailer** here).

![Generated app password](https://cdn.hashnode.com/res/hashnode/image/upload/v1690273124811/b55e09b1-60c8-44c4-9e71-633d17412888.png align="center")

Copy the generated app password and then paste it in your **.env** file. Now we can continue setting up nodemailer.

We need to create and **SMTP transport** with nodemailer to configure it to send emails from our gmail. For that we will use the following snippet:

```typescript
import nodemailer from 'nodemailer';

const transport = nodemailer.createTransport({
  service: 'gmail',
  /* 
      setting service as 'gmail' is same as providing these setings:

      host: "smtp.gmail.com",
      port: 465,
      secure: true
      
      If you want to use a different email provider other than gmail, you need to provide these manually.
      Or you can go use these well known services and their settings at
      https://github.com/nodemailer/nodemailer/blob/master/lib/well-known/services.json
  */
  auth: {
    user: process.env.MY_EMAIL,
    pass: process.env.MY_PASSWORD,
  },
});
```

Next we need to set up the mail options which includes the message we are sending via email. For that we will use the following snippet:

```typescript
import Mail from 'nodemailer/lib/mailer';

const mailOptions: Mail.Options = {
  from: process.env.MY_EMAIL,
  to: process.env.MY_EMAIL,
  // cc: email, (uncomment this line if you want to send a copy to the sender)
  subject: `Message from ${name} (${email})`,
  text: message,
};
```

We are basically sending an email from our address to our own address itself. If we want to send a copy of this mail back to the sender, we can use **cc (Carbon Copy)** option in the mailOptions and provide in the email. We can then use **transport.sendMail** function along with these mailOptions to send our email. The **sendMail** function is a synchronous function and hence we will be wrapping it with a promise to make it asynchronous. The snippet for it will be as follows:

```typescript
const sendMailPromise = () =>
  new Promise<string>((resolve, reject) => {
    transport.sendMail(mailOptions, function (err) {
      if (!err) {
        resolve('Email sent');
      } else {
        reject(err.message);
      }
    });
  });
```

The fully complete code for **route.ts** will be as follows:

%[https://gist.github.com/ByteCrak07/309136d1dd8bfd6a31e1f0ebee732c07] 

*<mark>app/api/email/route.ts</mark>*

### Completing our form

Now our api is complete and the only thing left is to send the data from our form. Remember we had created a function **sendEmail** previously right? Now we just have to send the form data to our endpoint **api/email** via a POST request which can be done easily with the fetch function. The completed **send-email.ts** file will be as follows:

%[https://gist.github.com/ByteCrak07/38cd9429d14a9ec65d55932c5769cdba] 

*<mark>utils/send-email.ts</mark>*

You can see that I’m sending alerts for confirmation. You can customise this behaviour in whatever way you like. Here is a sample message that I sent from the form:

![This is how the email looks like](https://cdn.hashnode.com/res/hashnode/image/upload/v1690273127753/ce048e77-aba1-4909-bc15-acd4ee8d12c7.png align="center")

This tutorial is complete and we have a fully working form😌. You can check this repository for the entire project.

%[https://github.com/ByteCrak07/nextjs-contact-form] 

### Further reading

You can optimise the form logic by adding loading states to improve user experience. Also check out libraries like [SWR](https://swr.vercel.app) and [React-Query](https://tanstack.com/query/latest) to improve data fetching and sending. Also check out [React Email](https://react.email) to send beautiful emails using react rather than just sending plain text messages.

Go check out my website at [abilsavio.dev](https://abilsavio.dev/) to know more about me. I have used SWR and React Email to send emails from my contact form. This is how an email from my website by filling the contact form looks like which was built using **React Email**.

![Email from abilsavio.tech](https://cdn.hashnode.com/res/hashnode/image/upload/v1690273130065/a47614ed-483d-4530-b071-0e755cada79f.png align="center")
