Send Emails from Next.js using SendGrid
Keep your users engaged with transactional email, powered by one of the most popular email services.
Sam Magura
Virtually all production web applications need to send transactional emails, e.g. for password reset, notifications, and order confirmations. SendGrid is one of the most popular services for sending transactional email, and it comes with an easy-to-use API. In this post, I'll walk you through building a Next.js application that sends email via SendGrid. We'll utilize the Zero secrets manager to securely retrieve the SendGrid API key at runtime.
In a previous post , I covered sending transactional email with Mailchimp ― that's another option you can consider for your transaction email needs. Though, in my experience, there is not much of a difference between the two services. An email is an email, after all.
🔗 The full code for this example is available in the zerosecrets/examples GitHub repository.
Secure your secrets conveniently
Zero is a modern secrets manager built with usability at its core. Reliable and secure, it saves time and effort.
Signing Up for SendGrid
You can sign up for SendGrid by following this link . Before sending an email, we'll need to configure a verified sender (an email address that we've proved ownership of). To do this, log in to the SendGrid console and select Settings > Sender Authentication in the left-hand side menu. Click "Verify a single sender", enter your personal email address, and complete the verification.
Now, we can create an API key by selecting Email API > Integration Guide from main menu. For the integration method, select Web API, and then Node.js. This will open a step-by-step integration guide, with a form for creating your API key. Create an API key and copy it to a temporary text file on your PC.
Next, create a Zero project to house the SendGrid API key. You should copy the project's token to your temporary text file, as we'll need to provide it to the Next.js app as an environment variable. Back in the Zero console, add a new secret and paste in the SendGrid API key:
Creating the Next.js App
To bootstrap a new Next.js application, run
npx create-next-app@latest nextjs-sendgrid
At the prompts, select TypeScript and the new App Router.
The example use case I'll be implementing is a purchase confirmation email, like you would find in an ecommerce site. So, let's create a simple HTML form that requests the user's email address, where they would like to receive the confirmation email.
Here's my barebones form:
export default function Home() {
const [email, setEmail] = useState('')
const [isSuccess, setIsSuccess] = useState(false)
async function submit() {
// TODO
}
return (
<main className={styles.main}>
<h4 className={styles.heading}>Enter your email address to confirm your purchase:</h4>
<form
onSubmit={(e) => {
e.preventDefault()
submit()
}}
noValidate
className={styles.form}
>
<input type="email" value={email} onChange={(e) => setEmail(e.target.value)} className={styles.input} />
<button type="submit">Submit</button>
</form>
{isSuccess && <p>Success!</p>}
</main>
)
}
With a few CSS tweaks, this is what it looks like:
In the next section, we'll create an API method at /api/purchase
, so we can fill in the submit
function to call that API method.
async function submit() {
const response = await fetch('/api/purchase', {
method: 'POST',
body: JSON.stringify({email}),
headers: {'Content-Type': 'application/json'},
})
setIsSuccess(response.ok)
}
Creating a Next.js Route Handler
With the old Next.js Pages Router, API routes allowed you to expose a public API from within a Next.js web application. With the new App Router, API routes have been replaced by Route Handlers . That said, if you're already familiar with API routes, you'll find that the developer experience with Route Handlers is almost the same.
Next.js uses filesystem routing, so to create the /api/purchase
API method, you'll create the directories app/api
and app/api/purchase
. Within the purchase
directory, create a route.ts
— this is where the Route Hander code will go. To start, let's just log the email address:
export async function POST(request: Request) {
const {email} = await request.json()
console.log(`Sending email to: ${email}`)
return Response.json(null)
}
Authorizing the SendGrid API Client
The easiest way to send an email via the SendGrid web API is to use the @sendgrid/mail npm package. We'll need to pass the SendGrid API key to @sendgrid/mail
, so that's where Zero comes in. Retrieving the API key from Zero is very straightforward, thanks to the Zero TypeScript SDK .
To install both packages, run
npm install @sendgrid/mail @zerosecrets/zero
Now, create a new file in the app/api/purchase
directory which pulls the secret down from Zero and passes it to the SendGrid API client:
import sgMail from '@sendgrid/mail'
import {zero} from '@zerosecrets/zero'
let initialized = false
export async function initializeSendGrid() {
if (initialized) {
return true
}
if (!process.env.ZERO_TOKEN) {
throw new Error('Did you forget to set the ZERO_TOKEN environment variable?')
}
const secrets = await zero({
token: process.env.ZERO_TOKEN,
pick: ['sendgrid'],
}).fetch()
if (!secrets.sendgrid) {
throw new Error('Did not receive an API key for SendGrid.')
}
sgMail.setApiKey(secrets.sendgrid.api_key)
initialized = true
}
This code follows our standard pattern for initializing API clients with Zero.
Completing the Route Handler
Now, all that's left to do is update the API Route Handler to call the function we defined in the previous section, and send the email. The completed Route Handler looks like this:
export async function POST(request: Request) {
const {email} = await request.json()
await initializeSendGrid()
console.log(`Sending email to: ${email}`)
await sgMail.send({
to: email,
from: 'YOUR_VERIFIED_SENDER@example.com',
subject: 'Purchase confirmation',
text: 'This is a sample email.',
})
return Response.json(null)
}
Make sure to replace YOUR_VERIFIED_SENDER@example.com
with the email address you verified when configuring the SendGrid verified sender.
Running the application works like normal, except you need to remember to pass the Zero token in as an environment variable:
ZERO_TOKEN='YOUR_ZERO_TOKEN' npm run dev
Now, if you enter your email address in the HTML form and click submit, you should receive an email!
Wrapping Up
Integrating with third party APIs can be a lot of work, but that's not the case with SendGrid. This post shows how you can get up and running with their API in just a few lines of code. Zero also comes in handy here by allowing you to store the SendGrid API key in a single secure location, which could also be accessed by other components of your application, e.g. background jobs that send notification emails.
Other articles
Use Pusher to Implement Real-Time Notifications
Pusher makes it easy to add pub-sub functionality to your web apps, allowing you to implement chat, notifications, and more.
Integrating Auth0 with Next.js for Authentication
Quickly set up authentication in a Next.js app with Auth0 so you don't have to code it yourself.
Secure your secrets
Zero is a modern secrets manager built with usability at its core. Reliable and secure, it saves time and effort.