How to Integrate twillio SendGrid web API with Nextjs?
Tags: nextjs, sendgrid, javascript, react
Published: 2021-04-18 11:56:42

Whenever developing any web app whether it be some static site or some dynamic site, in most of the cases we require some type of contact form.

## What is Next.js?
>It is used to build server-side rendering and static web applications using React.

## What is SendGrid?
> SendGrid is a cloud-based SMTP provider that allows you to send email without having to maintain email servers. SendGrid manages all of the technical details, from scaling the infrastructure to ISP outreach and reputation monitoring to whitelist services and real-time analytics. In short, **it is used to send emails.**

Assuming that you already have a next.js app setup let's start with integrating SendGrid API to send emails, if you don't have one check out this [guide](https://nextjs.org/docs/api-reference/create-next-app "create new next app"), on how to create next.js app.

There are two ways in which you can achieve this, one is by using external [library](https://www.npmjs.com/package/@sendgrid/mail "@sendgrid/mail") from SendGrid and the second is by making a `POST` request to `https://api.sendgrid.com/v3/mail/send` with all the required data, this is more suitable if you don't want to include any new library in your project for just sending emails.

Let's see how can you send emails with SendGrid web API in Nextjs, create a file `sendMail.js` in the `utils` folder of your project's root directory. Now, your project's directory structure should look like this,

![directory structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/au4ex7ktafhg89l96k1m.png)

add the following code to your `sendMail.js` file

```javascript
import fetch from "node-fetch";

const SENDGRID_API_URL = "https://api.sendgrid.com/v3/mail/send";
const SENDGRID_API_KEY = process.env.NEW_SENDGRID_API_KEY;

const sendMailToMe = async (
   recepient_email, // email_address to send mail
  name_, // from name on email
  subject = "sample subject",
  client_message, // value we receive from our contact form
  client_email // value we receive from our contact form
) => {
  const sgResponse = await fetch(SENDGRID_API_URL, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${SENDGRID_API_KEY}`,
    },
    body: JSON.stringify({
      personalizations: [
        {
          to: [
            {
              email: recepient_email,
            },
          ],
          subject: subject,
        },
      ],
      from: {
        email: "YOUR VERIFIED SENDGRID MAIL HERE",
        name: "YOUR NAME",
      },
      content: [
        {
          type: "text/html",
          value: `<strong>Client Name: ${name_} </strong> \n <p> 
                  sent you a query regarding <strong>${subject} </strong></p>
                  \n <p>Client's Message: <strong>${client_message}</strong><\p> 
                  <p>Client's Email : <strong> ${client_email} </strong></p>`,
        },
      ],
    }),
  });
  return sgResponse;
};

export { sendMailToMe };

```

here we are using `node-fetch` for making a `POST` request so you need to install it through `npm i node-fetch` it is a lightweight module that brings window.fetch to Node.js, and also this function expects some values that we will include from our contact form. You will need SendGrid [API key](https://sendgrid.com/docs/ui/account-and-settings/api-keys/ "SendGrid API keys") and store it in `next.config.js` as env variable to send emails and also verify a [Sender Identity](https://sendgrid.com/docs/ui/sending-email/sender-verification/ "Single sender verification") 

Then, we need to create an API endpoint in Next.js that we will use to send data from our contact form, this is done by creating a new file in `pages/api` folder. This `api` folder is a special folder in Nextjs which is used to create all the api endpoints of your Nextjs app, and these endpoints are only invoked when they are required.   

so add `senMail.js` to the `pages/api` folder of your app like this.


![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/clnocn74k3cuh3bvpm2w.png)

add following code into this file,

```javascript
import { sendMailQueryToMe } from "../../utils/sendMailToMe";

export default async function handler(req, res) {
  if (req.method === "POST") {
    // req.body carries all the data

    try {
      const { email, name_, subject, client_message } = req.body;

      if (
        typeof (email || name_ || subject || client_message) === "undefined"
      ) {
        console.log(" ************* Invalid Data received ************ ");

        return res
          .status(400)
          .send({ error: "bad request, missing required data!" });
      } else {
        //  Data received as expected
        try {
          const sendGridResponse = await sendMailQueryToMe(
            "your_mail@gmail.com",
            name_,
            subject,
            client_message,
            email
          );

          return res.status(200).send({
            sg_response: sendGridResponse,
          });
        } catch (err) {
          console.log(
            "ERROR WHILE SENDING MAIL TO *YOU* THROUGH WEB API >> ",
            err
          );

          return res.status(400).send({
            err_message: "bad request",
          });
        }
      }
    } catch (err) {
      console.log("Err while sending Mail through send grid >> ", err);
      return res
        .status(400)
        .send({ error: "Error in sendgrid Service.", errMsg: err });
    }
  }

  res.status(400).send({ error: "bad request" });
}
``` 
now finally we need to create some UI form from which users can send mail. For this, Create a `contact.js` file in the `pages` folder of your app and add the following code to it.

```javascript
import React, { useState } from "react";
import MailOutlineIcon from "@material-ui/icons/MailOutline";
import { MenuItem, Input } from "@material-ui/core";
import TextField from "@material-ui/core/TextField";
import https from "https";

function contact() {
  const [formError, setFormError] = useState({ error: "" });
  const [querySubject, setQuerySetsubject] = useState("");
  const [name_, setName_] = useState("");
  const [clientEmail, setClientEmail] = useState("");
  const [clientMsg, setClientMsg] = useState("");

  const serviceOptions = [
    {
      value: "option1",
      label: "option1",
    },
    {
      value: "option2",
      label: "option2",
    },
    {
      value: "option3",
      label: "option3",
    },
    {
      value: "option4",
      label: "option4",
    },
  ];

  const sendMail = async (
    client_name,
    client_email,
    client_message,
    client_subject
  ) => {
    const data = JSON.stringify({
      name_: client_name,
      email: client_email,
      client_message: client_message,
      subject: client_subject,
    });
 
    const options = {
      path: "/api/sendMail",
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "Content-Length": data.length,
      },
    };

    const req = https.request(options, (res) => {
      // console.log(`statusCode: ${res.statusCode}`);

      res.on("data", (d) => {
        // process.stdout.write(d);
        // console.log("data  from API >> ", JSON.parse(d));
      });
    });

    req.on("error", (error) => {
      setFormError({
        error: "Unable to send your message please try after some time.",
      });
    });

    req.write(data);
    req.end();
  };

  return (
    <div>
      <form
        style={{ display: "flex", flexDirection: "column", padding: "50px" }}
      >
        <Input
          style={{ width: "100%", color: "black" }}
          type="text"
          value={name_}
          placeholder="What is your name ?"
          onChange={(e) => setName_(e.target.value)}
          required
        />
        <Input
          style={{ width: "100%", color: "black" }}
          value={clientEmail}
          type="email"
          placeholder="What is your email ?"
          onChange={(e) => setClientEmail(e.target.value)}
          required
        />
        <TextField
          style={{ width: "100%", color: "black" }}
          id="standard-select-Interest"
          select
          label="What are you interested in ?"
          value={querySubject}
          onChange={(e) => setQuerySetsubject(e.target.value)}
          required
        >
          {serviceOptions.map((option) => (
            <MenuItem key={option.value} value={option.value}>
              {option.label}
            </MenuItem>
          ))}
        </TextField>

        <TextField
          style={{ width: "100%", color: "black" }}
          id="client-message-textarea"
          label="Message"
          multiline
          rows={4}
          value={clientMsg}
          onChange={(e) => setClientMsg(e.target.value)}
        />
        {formError.error ? (
          <div className="form__error">
            <span style={{ color: "black" }}>{formError.error}</span>
          </div>
        ) : (
          ""
        )}
        <div>
          <button
            disabled={!name_ || !clientEmail || !clientMsg || !querySubject}
            type="submit"
            style={
              !name_ || !clientEmail || !clientMsg || !querySubject
                ? {
                    backgroundColor: "#878a8f",
                    color: "white",
                    transform: "scale(1)",
                    cursor: "default",
                    margin: "50px 0",
                  }
                : { margin: "50px 0" }
            }
            onClick={(e) => {
              e.preventDefault();
              sendMail(name_, clientEmail, clientMsg, querySubject);
            }}
          >
            <MailOutlineIcon /> Send
          </button>
        </div>
      </form>
    </div>
  );
}

export default contact;

```

And that's all folks you have a full-featured contact form from which you can send or receive emails.

I have implemented this in my contact form which you can try at my [Site](https://www.lalitvavdara.me/contact "Contact Lalit Vavdara")