DEV Community

Cover image for How to Integrate twillio SendGrid web API with Nextjs?
Lalit Vavdara
Lalit Vavdara

Posted on • Edited on

How to Integrate twillio SendGrid web API with Nextjs?

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, on how to create next.js app.

There are two ways in which you can achieve this, one is by using external library 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

add the following code to your sendMail.js file

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 };

Enter fullscreen mode Exit fullscreen mode

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 and store it in next.config.js as env variable to send emails and also verify a Sender Identity

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

add following code into this file,

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" });
}
Enter fullscreen mode Exit fullscreen mode

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.

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;

Enter fullscreen mode Exit fullscreen mode

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

Top comments (4)

Collapse
 
dkodeit profile image
dkodeit

No need for node-fetch.

nextjs.org/blog/next-9-4#improved-...

Collapse
 
professor833 profile image
Lalit Vavdara

Thanks, for the info buddy๐Ÿ‘๐Ÿผ

Collapse
 
steve-lebleu profile image
Steve Lebleu

Thanks for sharing ! Here a package which can help with email sending in node.js environment. One library for many providers.

GitHub logo konfer-be / cliam

Agnostic transactional email sending in Node.js environment

Cliam

Build Status Coverage Status CodeFactor Grade Requires.io (branch) GPL Licence

Transactional emails with a kick

Agnostic transactional email sending in Node.js environment ๐Ÿ’ฅ ๐Ÿ’ช ๐Ÿ’Š

> Why ?

To improve and facilitate the implementation, flexibility and maintenance of transactional emailing tasks.

> Features

  • Agnostic transactional email sending using web API or SMTP server. One input, one output.
  • Configuration based, not implementation based : easy switch between different modes.
  • Normalized transactions events.
  • Securized payloads.
  • Customisable default templates.

> Table of contents

> Requirements

  • Node.js >= 14.16.0
  • NPM >= 6.14.11

> Getting started

Install

> npm i cliam --save
Enter fullscreen mode Exit fullscreen mode

Configure

Create a .cliamrc.json file on the root of your project.

> touch .cliamrc.json
Enter fullscreen mode Exit fullscreen mode

Define a minimalist configuration in .cliamrc.json newly created:

{
  "consumer": {
    "domain": "https://www.john-doe.com"
  }
  "mode": {
    "api": {
      "name"
โ€ฆ
Enter fullscreen mode Exit fullscreen mode
Collapse
 
2567910 profile image
Lukas Seyfarth

I think it should be 'sendMailToMe' instead of 'sendMailQueryToMe'?