How to trigger an email on event confirmation with Netlify

Demola Malomo - Nov 24 '22 - - Dev Community

Over the years, emails have been the go-to medium for developers to send event RSVPs, authentication codes, and application runtime notifications, among others. The implementation process is also daunting for developers as they need to cater to the adopted mail provider and deployment mechanism.

In this post, we will learn how to quickly build an event confirmation application with Netlify, Xata, SendGrid, and Cloudinary using Next.js.

Technology overview

Netlify is a platform for deploying and building highly-performant and dynamic websites, e-commerce stores, and web applications.

Xata is an HTTP API-based serverless database for building scalable applications. It supports a built-in search engine, branching, scalability, and durability without manually managing database configuration and deployment.

SendGrid is a cloud-based email marketing tool developers and marketers use to manage mailing lists, A/B testing, predefined templates, and image libraries used in campaign management and audience engagement.

Cloudinary is a visual media service for uploading, storing, managing, transforming, and delivering images and videos for websites and applications.

GitHub and Deployment link

The project source codes and deployment link are below:

Prerequisites

To follow along with this tutorial, the following requirements apply:

Getting started

We need to create a Next.js starter project by navigating to the desired directory and running the command below in our terminal.

npx create-next-app event-confirmation && cd event-confirmation
Enter fullscreen mode Exit fullscreen mode

The command creates a Next.js project called event-confirmation and navigates into the project directory.

Installing TailwindCSS and Node-Fetch
TailwindCSS is a utility-first CSS framework packed with classes to help us style our web pages. To use it in our application, run the command below:

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
Enter fullscreen mode Exit fullscreen mode

The command installs TailwindCSS and its dependencies and generates tailwind.config.js and postcss.config.js files.

Next, we need to update tailwind.config.js file with the snippet below:

module.exports = {
  content: [
    './app/**/*.{js,ts,jsx,tsx}',
    './pages/**/*.{js,ts,jsx,tsx}',
    './components/**/*.{js,ts,jsx,tsx}',
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
Enter fullscreen mode Exit fullscreen mode

Finally, we need to add TailwindCSS directives to our application. The directives give our application access to TailwindCSS utility classes. To do this, navigate to the styles folder and update the globals.css files in it with the snippet below:

@tailwind base;
@tailwind components;
@tailwind utilities;
Enter fullscreen mode Exit fullscreen mode

Lastly, we need to install node-fetch, a package for making HTTP requests. To do this, we need to run the command below:

npm i node-fetch
Enter fullscreen mode Exit fullscreen mode

Set up a Database on Xata

To create a database for storing our event confirmation data, we need to log into our Xata’s workspace, click the Add a Database button, input events as the database name, and Create.

Add a Database
input database name

Next, we need to create a table in our database. To do this, click the Start from scratch menu, input confirmed as the table name, and Add table.

click the start from scratch
input and create

PS: Xata auto-generates an ID column (a unique identifier) for our table.

With that done, we need to add a name of type String and email of type Email columns to our table. To do this, click on the Plus icon, select type accordingly, input column name, and Create column.

plus icon
select string
input name

After creating the columns, our updated table should be similar to the screenshot below:

updated table

Get Database URL and set up API Key
By default, Xata provides a unique and secure URL for accessing the database. To get our database URL, click the Get code snippet button, copy the URL, and then click the Set up API key button to generate API key. We need the API key for authentication when using the database.

Get code snippet

URL and Set up API key

PS: The URL we need to copy starts from the *https://……* section

Click the Add a key button, input xata-function as the name, and Save.

Add a key
Copy API Key

Both the URL and API key will come in handy when deploying our application.

Set up SendGrid as an email provider

To get started, we need to log into our Sendgrid account and create a sender identity for sending emails. To do this, click the Create a Single Sender button and fill in the required details.

Click on single sender
Fill details

PS: We will also be required to verify the email filled in as the sender's identity.

Next, we need to create an API Key to securely access our SendGrid account and send emails from a client. To do this, navigate to the API Key tab under the Settings menu and click the Create API Key button.

Create API Key

Input event-conf as the API Key Name and click the Create & View button.

Input detail and create

SendGrid will generate an API Key. We also need to copy and keep the generated key, as it will come in handy later on.

Building the event confirmation application

Create email template
To get started, we need to create a reusable template for sending the event confirmation email to our users. To do this, first, we need to create an emails folder in the root directory, and in this folder create another folder confirmed.

folder structure

Lastly, we need to create an index.html file inside the confirmed folder and add the snippet below:

<html>
    <body
        style="
            font-family: 'Open Sans', 'Helvetica Neue', sans-serif;
            margin: 0 auto;
        "
    >
        <div
            style="
                background-color: white;
                display: inline-block;
                text-align: center;
                padding: 10px;
            "
        >
            <img
                style="height: 200px; width: 100vw"
                src="https://res.cloudinary.com/dtgbzmpca/image/upload/v1667575091/photo-1498931299472-f7a63a5a1cfa.jpg"
                alt="mars"
            />
            <h1>Welcome, {{name}}</h1>
            <p>
                We promised this will be the best sessions you have ever
                experienced!
            </p>
            <p>Thanks for subscribing!</p>
        </div>
    </body>
</html>
Enter fullscreen mode Exit fullscreen mode

The snippet above creates and styles a template by using an optimized image hosted on Cloudinary as the template header and accepts a name variable to personalize the registered user’s name.

Create Serverless Function
With that done, we need to create a function that saves the details of interested users on Xata and sends a confirmation email. To get started; first, we need to create a netlify folder and create a functions folder in this folder.

Updated folder

Secondly, we need to create a saveandconfirm.js file inside the functions folder and add the snippet below:

import fetch from 'node-fetch';

exports.handler = async function (event, context, callback) {
    let bodyRequest = JSON.parse(event.body);
    const body = {
        name: bodyRequest.name,
        email: bodyRequest.email,
    };

    //save user on the database
    await fetch(`${process.env.XATA_URL}:main/tables/confirmed/data`, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            Authorization: `Bearer ${process.env.XATA_API_KEY}`,
        },
        body: JSON.stringify(body),
    });

    //send confirmation email
    await fetch(`${process.env.URL}/.netlify/functions/emails/confirmed`, {
        headers: {
            'netlify-emails-secret': process.env.NETLIFY_EMAILS_SECRET,
        },
        method: 'POST',
        body: JSON.stringify({
            from: process.env.SEND_FROM_EMAIL,
            to: body.email,
            subject: "You've been confirmed!",
            parameters: {
                name: body.name,
            },
        }),
    });

    return {
        statusCode: 200,
        body: JSON.stringify({ data: 'Email confirmation sent successfully!' }),
    };
};
Enter fullscreen mode Exit fullscreen mode

The snippet above does the following:

  • Imports the required dependency
  • Lines 4-8: Gets the request body
  • Lines 11-18: Creates a POST request to the Xata database by passing the URL as an environment variable with the database details and API key
  • Lines 21-34: Creates a POST request that sends a request with the required parameters to the email handler and creates the email body
  • Lines 36-39: Returns the appropriate response.

We also constructed the Xata database URL by passing in the branch, table name, and endpoint type.

process.env.XATA_URL:<BRANCH NAME>/tables/<TABLE NAME>/ENDPOINT TYPE
Enter fullscreen mode Exit fullscreen mode

We can get the required details from our workspace

Branch name and Table name

In our case, we filled it using an environment variable. We will add it when deploying our application to Netlify. An adequately filled URL is below:

process.env.XATA_URL:main/tables/userDetails/data
Enter fullscreen mode Exit fullscreen mode

Similarly, we appended our email directory confirmed to the email handler as shown below:

process.env.URL/.netlify/functions/emails/confirmed
Enter fullscreen mode Exit fullscreen mode

Lastly, we need to add a deployment file that instructs Netlify to build our application effectively. To do this, we need to create a netlify.toml file in the root directory of our project and add the snippet below:

[functions]
  node_bundler = "esbuild"
Enter fullscreen mode Exit fullscreen mode

Building the User Interface
With that done, we can call the Serverless Function from our application UI. To do this, first, we need to update the index.js file inside the pages folder as shown below:

import Head from 'next/head';
import { useState } from 'react';

export default function Home() {
  const [value, setValue] = useState({
    name: '',
    email: '',
  });
  const [isLoading, setIsloading] = useState(false);

  const handleChange = (e) => {
    setValue({ ...value, [e.target.name]: e.target.value });
  };

  const handleSubmit = (e) => {
    setIsloading(true);
    e.preventDefault();
    const body = {
      name: value.name,
      email: value.email,
    };
    fetch('./.netlify/functions/saveandconfirm', {
      method: 'POST',
      body: JSON.stringify(body),
    }).then((_) => {
      alert('Confirmed successfully!');
      setValue({ ...value, name: '', email: '' });
      setIsloading(false);
    });
  };

  return (
    <div>
      <Head>
        <title>Event confirmation</title>
        <meta
          name='description'
          content='Generated by create next app'
        />
        <link rel='icon' href='/favicon.ico' />
      </Head>
      <main className='py-4 px-4 lg:py-10 lg:px-10 w-full'>
        <section className='flex justify-center'>
          <div className='px-4 py-2 border rounded-lg w-full lg:w-2/4'>
            <div className='border-b h-8 mb-4'>
              <h3 className='text-gray-700'>
                Confirm Attendance
              </h3>
            </div>
            <form onSubmit={handleSubmit}>
              <fieldset>
                <label className='text-sm text-gray-400 mb-4 block'>
                  Name
                </label>
                <input
                  name='name'
                  className='border w-full rounded-sm mb-6 p-2'
                  required
                  value={value.name}
                  onChange={handleChange}
                />
              </fieldset>
              <fieldset>
                <label className='text-sm text-gray-400 mb-4 block'>
                  Email
                </label>
                <input
                  name='email'
                  className='border w-full rounded-sm mb-6 p-2'
                  type='email'
                  required
                  value={value.email}
                  onChange={handleChange}
                />
              </fieldset>
              <button
                className='text-sm text-white px-8 py-2 rounded-sm bg-teal-600 hover:bg-teal-700'
                disabled={isLoading}
              >
                Submit
              </button>
            </form>
          </div>
        </section>
      </main>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

The snippet above does the following:

  • Imports the required dependencies
  • Lines 5-9: Create state properties to manage application state
  • Lines 11-13: Creates handleChange to control the input fields
  • Lines 15-30: Makes a POST request to the Serverless Function we created earlier and pass in the required parameter
  • Updates the UI accordingly

Putting it all together on Netlify

Pushing our source code to GitHub
We need to push our source code to GitHub to enable a seamless deployment process. To get started, we need to log into our GitHub account, create a repository, input event-confirmation as the name and Create repository.

Next, we initialize a git project and save recent changes in our project by running the command below:

git init
git add .
git commit -m "event confirmation source code"
Enter fullscreen mode Exit fullscreen mode

To push our changes, copy and run the highlighted commands on the terminal:

Push changes to GitHub

Deploying to Netlify
To get started, we need to log into our Netlify dashboard. Click on Add new site dropdown and select Import an existing project.

Create site

Select GitHub as the Git provider and authorize Netlify.

select Github

Search for event-confirmation and select the repository.

select repository

Click on Show advanced, click the New variable button and add the XATA_URL, XATA_API_KEY, SEND_FROM_EMAIL, and NETLIFY_EMAIL_SECRET environment variables as key and their corresponding values.

Show advanced
input env variable

As earlier mentioned we can get the needed values from Xata workspace and SendGrid dashboard.

URL
API KEY

Click the Deploy site button to start deployment. It might take a few minutes.

Configure email integration
To do this, click the Site settings button to view the deployed site settings.

site setting

Navigate to the Emails tab and click the Enable emails button.

Email tab
Enable emails

Select SendGrid as the email provider, input the API key we generated earlier on SendGrid, and Save.

Input SendGrid details

Finally, to sync the latest changes with our deployed application, we need to navigate to the Deploys tab and trigger redeployment by clicking the Clear cache and deploy site option.

Trigger deployment

With that done, we can test our application by clicking on the deployed URL

Test application

https://media.giphy.com/media/ORKNdc9G18aDPzrjBw/giphy.gif

Conclusion

This post discussed how to save event details and trigger an email in a Netx.js application using Xata, SendGrid, and Netlify. With this approach, developers can streamline their architectural process by leveraging out-of-the-box solutions to cater to storing users' data and sending dynamic emails.

These resources might be helpful:

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .