Integrating 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, from which we can send or receive emails.
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 the Next.js app.
There are two ways in which you can achieve this, one is by using the 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,
add the following code to your sendMailToMe.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 };
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.
add the following code to your sendMail.js
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" });
}
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;
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 the contact form of my portfolio, which you can try out at my Portfolio