如何用SendGrid和Next.js建立一个联系表单

613 阅读12分钟

如果你希望你的用户能够通过电子邮件与你互动,那么联系表单在网站上是很有用的。而且有很多方法来建立它们。

传统上,你要么使用PHP在服务器上发送电子邮件,要么使用一些第三方服务来处理电子邮件的逻辑。

但在这篇文章中,我们将讨论如何使用SendGrid API从你的Next.js应用程序发送电子邮件。

我们将创建一个简单的页面--一个用React构建的联系表单--它有输入字段,我们将在发送前进行验证。我们将把这个表单连接到SendGrid API,它将负责向你发送电子邮件。然后,在一天结束的时候,你所要做的就是检查你的电子邮件,找到那些查询。

然而,如果你还没有Next.js项目,你可以轻松地创建一个,并通过下面提到的步骤将其与Vercel集成。

  1. Vercel上创建一个账户,然后点击New Project

2.选择模板为Next.js

3. 为你的仓库命名任何你想要的东西,然后点击创建项目。(选择GitHub、GitLab或BitBucket作为你的远程代码版本管理)

按照以上三点,你就会在你的版本管理账户上有一个仓库。

我们将使用的技术栈

  • Next.js用于创建联系表单登陆页面
  • TailwindCSS用于设计组件的样式
  • SendGrid用于使用其API发送电子邮件
  • Vercel用于托管我们的应用程序和CI/CD

我们将使用Nextjs的API路由来处理表单事件。API模块提供了一种灵活的方式来处理我们Next.js应用程序中的后端逻辑。

我们在API文件夹中编写的任何代码都将作为无服务器功能部署到Vercel上进行托管。你可以在这里阅读更多关于Next.js API路由的信息

如果你已经有了一个Next.js项目,想要建立一个可以使用的联系表单,那就太好了。在这种情况下,你将很容易创建页面并立即开始工作。

但如果你还没有建立一个项目,那也没关系--去Vercel创建一个Next.js的启动项目,然后克隆仓库。

应用流程

让我们来看看应用流程--或发送电子邮件的实际操作。

  • 终端用户填写规定的4个字段并点击提交。
  • 在提交时,handleSubmit 函数被触发。
  • handleSubmit 验证表单中的输入字段,并检查它们是否为空。
  • 如果表格中的字段不是空的,就会调用API到api/sendgrid ,那里有发送电子邮件的逻辑。
  • api/sendgrid@sendgrid/mail 模块初始化一个send 函数,该函数接受你的应用程序的API密钥并发送带有所需字段的电子邮件。
  • 如果电子邮件被成功发送,一个200 响应被发送到客户端,否则一个400 响应被发送到客户端。
  • 响应是在前端处理的,并显示适当的信息。

如何设置TailwindCSS

设置TailwindCSS是非常容易的,你可以通过两种简单的方式来完成。

  1. 将TailwindCSS作为一个依赖项安装在你的项目中。
npm install -D tailwindcss@latest postcss@latest autoprefixer@latest

2. 为你的项目初始化一个TailwindCSS配置文件。这将在根目录下创建一个tailwind.config.js 文件。

npx tailwindcss init

然后你需要编辑该配置文件,包括purge 路径,并启用jit 模式。

module.exports = {
   purge: [],
   mode: 'jit',
   purge: ['./pages/**/*.{js,ts,jsx,tsx}', './components/**/*.{js,ts,jsx,tsx}'],
    darkMode: false, // or 'media' or 'class'
    theme: {
      extend: {},
    },
    variants: {
      extend: {},
    },
    plugins: [],
  }

你使用purge ,在构建时从你的项目中删除不需要的样式。如果你想减少CSS包的大小,它是有帮助的。

jit 是新的TailwindCSS模式,你可以在代码本身中指定动态类名。

例如,如果你想让你的文本大小为10px (这在TailwindCSS模块中还没有),你可以在你的类名中写上text-[10px] ,它将自动反映。不需要再写自定义样式属性了。💯

接下来,在你的根_app.js 文件中导入Tailwind样式。

// pages/_app.js
 import '../styles/globals.css'
 import 'tailwindcss/tailwind.css'

  function MyApp({ Component, pageProps }) {
    return <Component {...pageProps} />
  }

  export default MyApp

然后像这样把Tailwind的核心CSS包含在你的根级样式表中。

/* ./styles/globals.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

这样,你已经成功地为你的项目设置了TailwindCSS。

联系页面的标记和风格设计

我们将完全用Tailwind构建网页。我直接从Tailwind Master Kit中获得了页面本身,这是一个用于Tailwind网页项目的组件和模板库。

让我们浏览一下该页面的HTML(基本上是联系表),以了解一切是如何实现的。

<form class="rounded-lg shadow-xl flex flex-col px-8 py-8 bg-white dark:bg-blue-500">
      <h1 class="text-2xl font-bold dark:text-gray-50">Send a message</h1>

      <label for="fullname" class="text-gray-500 font-light mt-8 dark:text-gray-50">Full name<span class="text-red-500 dark:text-gray-50">*</span></label>
      <input type="text" name="fullname" class="bg-transparent border-b py-2 pl-4 focus:outline-none focus:rounded-md focus:ring-1 ring-green-500 font-light text-gray-500" />

      <label for="email" class="text-gray-500 font-light mt-4 dark:text-gray-50">E-mail<span class="text-red-500">*</span></label>
      <input type="email" name="email" class="bg-transparent border-b py-2 pl-4 focus:outline-none focus:rounded-md focus:ring-1 ring-green-500 font-light text-gray-500" />

      <label for="subject" class="text-gray-500 font-light mt-4 dark:text-gray-50">Subject<span class="text-red-500">*</span></label>
      <input type="text" name="subject" class="bg-transparent border-b py-2 pl-4 focus:outline-none focus:rounded-md focus:ring-1 ring-green-500 font-light text-gray-500" />

      <label for="message" class="text-gray-500 font-light mt-4 dark:text-gray-50">Message<span class="text-red-500">*</span></label>
      <textarea name="message" class="bg-transparent border-b py-2 pl-4 focus:outline-none focus:rounded-md focus:ring-1 ring-green-500 font-light text-gray-500"></textarea>
      <div class="flex flex-row items-center justify-start">
        <button class="px-10 mt-8 py-2 bg-[#130F49] text-gray-50 font-light rounded-md text-lg flex flex-row items-center">
          Send
          <svg width="24" height="24" viewBox="0 0 24 24" class="text-cyan-500 ml-2" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
            <path d="M9.00967 5.12761H11.0097C12.1142 5.12761 13.468 5.89682 14.0335 6.8457L16.5089 11H21.0097C21.562 11 22.0097 11.4477 22.0097 12C22.0097 12.5523 21.562 13 21.0097 13H16.4138L13.9383 17.1543C13.3729 18.1032 12.0191 18.8724 10.9145 18.8724H8.91454L12.4138 13H5.42485L3.99036 15.4529H1.99036L4.00967 12L4.00967 11.967L2.00967 8.54712H4.00967L5.44417 11H12.5089L9.00967 5.12761Z" fill="currentColor" />
          </svg>
        </button>
      </div>
    </form>

该表格有4个字段。

  • 全名
  • 电子邮件
  • 主题
  • 留言

所有的字段都是强制性的--以后我们也会对它们进行验证。你希望你的用户在发送邮件时向你提供他们所有的细节。

为了捕捉这些字段,我们将使用React的useState()钩子来确保我们的数据在应用程序中被持久化。

export default function ContactUs() {
  const [fullname, setFullname] = useState("");
  const [email, setEmail] = useState("");
  const [subject, setSubject] = useState("");
  const [message, setMessage] = useState("");

    return (
		<form
          onSubmit={handleSubmit}
          className="rounded-lg shadow-xl flex flex-col px-8 py-8 bg-white dark:bg-blue-500"
        >
          <h1 className="text-2xl font-bold dark:text-gray-50">
            Send a message
          </h1>

          <label
            htmlFor="fullname"
            className="text-gray-500 font-light mt-8 dark:text-gray-50"
          >
            Full name<span className="text-red-500 dark:text-gray-50">*</span>
          </label>
          <input
            type="text"
            value={fullname}
            onChange={(e) => {
              setFullname(e.target.value);
            }}
            name="fullname"
            className="bg-transparent border-b py-2 pl-4 focus:outline-none focus:rounded-md focus:ring-1 ring-green-500 font-light text-gray-500"
          />
         

          <label
            htmlFor="email"
            className="text-gray-500 font-light mt-4 dark:text-gray-50"
          >
            E-mail<span className="text-red-500">*</span>
          </label>
          <input
            type="email"
            name="email"
            value={email}
            onChange={(e) => {
              setEmail(e.target.value);
            }}
            className="bg-transparent border-b py-2 pl-4 focus:outline-none focus:rounded-md focus:ring-1 ring-green-500 font-light text-gray-500"
          />
          

          <label
            htmlFor="subject"
            className="text-gray-500 font-light mt-4 dark:text-gray-50"
          >
            Subject<span className="text-red-500">*</span>
          </label>
          <input
            type="text"
            name="subject"
            value={subject}
            onChange={(e) => {
              setSubject(e.target.value);
            }}
            className="bg-transparent border-b py-2 pl-4 focus:outline-none focus:rounded-md focus:ring-1 ring-green-500 font-light text-gray-500"
          />
         
          <label
            htmlFor="message"
            className="text-gray-500 font-light mt-4 dark:text-gray-50"
          >
            Message<span className="text-red-500">*</span>
          </label>
          <textarea
            name="message"
            value={message}
            onChange={(e) => {
              setMessage(e.target.value);
            }}
            className="bg-transparent border-b py-2 pl-4 focus:outline-none focus:rounded-md focus:ring-1 ring-green-500 font-light text-gray-500"
          ></textarea>
          
          <div className="flex flex-row items-center justify-start">
            <button
              type="submit"
              className="px-10 mt-8 py-2 bg-[#130F49] text-gray-50 font-light rounded-md text-lg flex flex-row items-center"
            >
              Submit
              <svg
                width="24"
                height="24"
                viewBox="0 0 24 24"
                className="text-cyan-500 ml-2"
                fill="currentColor"
                xmlns="http://www.w3.org/2000/svg"
              >
                <path
                  d="M9.00967 5.12761H11.0097C12.1142 5.12761 13.468 5.89682 14.0335 6.8457L16.5089 11H21.0097C21.562 11 22.0097 11.4477 22.0097 12C22.0097 12.5523 21.562 13 21.0097 13H16.4138L13.9383 17.1543C13.3729 18.1032 12.0191 18.8724 10.9145 18.8724H8.91454L12.4138 13H5.42485L3.99036 15.4529H1.99036L4.00967 12L4.00967 11.967L2.00967 8.54712H4.00967L5.44417 11H12.5089L9.00967 5.12761Z"
                  fill="currentColor"
                />
              </svg>
            </button>
          </div>
        </form>
	)
}

注意表单属性onSubmit={handleSubmit} 。这就是我们要通过SendGrid实际发送电子邮件的函数。但是在这之前,让我们创建一个SendGrid项目并检索API keys

如何建立一个SendGrid项目

首先,你只需要前往SendGrid的主页并注册一个账户(如果你还没有的话)。

在成功创建一个账户之后,注册一个API密钥。你可以在这里做。

Sendgrid要求你创建一个发送者身份,以防止垃圾邮件和恶意邮件。要做到这一点,请到Sendgrid身份页面,点击Create New Sender ,创建一个发件人身份。

你将被要求填写一份详细的表格。只要完成表格并点击提交即可。最后,只要验证你的电子邮件地址,你就完成了。

一旦你检索到API keys ,在你的本地环境中创建一个.env.local 文件并粘贴以下代码。

SENDGRID_API_KEY= YOUR_API_KEY_HERE

用你刚刚检索到的API密钥替换YOUR_API_KEY_HERE

如何创建无服务器API路由

使用Next.js创建无服务器API路由是非常容易的。

进入/pages/api ,在api 文件夹中创建一个名为sendgrid.js 的文件。

import sendgrid from "@sendgrid/mail";

sendgrid.setApiKey(process.env.SENDGRID_API_KEY);

async function sendEmail(req, res) {
  try {
    // console.log("REQ.BODY", req.body);
    await sendgrid.send({
      to: "mannuarora7000@gmail.com", // Your email where you'll receive emails
      from: "manuarorawork@gmail.com", // your website email address here
      subject: `${req.body.subject}`,
      html: `<div>You've got a mail</div>`,
    });
  } catch (error) {
    // console.log(error);
    return res.status(error.statusCode || 500).json({ error: error.message });
  }

  return res.status(200).json({ error: "" });
}

export default sendEmail;

SendGrid要求我们通过setApiKey() 方法用API密钥初始化一个sendgrid 对象。用你的API密钥初始化该对象,你就可以用send() 方法发送电子邮件。

send() 方法的主体中,基本上有四个字是必须的。

  • to - 你希望你的邮件被送达的电子邮件地址
  • from - 你用于发送者身份验证的SendGrid电子邮件。你的邮件将从这个邮箱发送。
  • subject - 电子邮件的主题行
  • message - 电子邮件的信息正文

我们将自己构建这四个参数,以便我们能够更好地理解我们的电子邮件。下面是上面同一个片段的更新代码。

import sendgrid from "@sendgrid/mail";

sendgrid.setApiKey(process.env.SENDGRID_API_KEY);

async function sendEmail(req, res) {
  try {
    await sendgrid.send({
      to: "youremail@gmail.com", // Your email where you'll receive emails
      from: "youremail@gmail.com", // your website email address here
      subject: `[Lead from website] : ${req.body.subject}`,
      html: `<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      <html lang="en">
      <head>
        <meta charset="utf-8">
      
        <title>The HTML5 Herald</title>
        <meta name="description" content="The HTML5 Herald">
        <meta name="author" content="SitePoint">
      <meta http-equiv="Content-Type" content="text/html charset=UTF-8" />
      
        <link rel="stylesheet" href="css/styles.css?v=1.0">
      
      </head>
      
      <body>
        <div class="img-container" style="display: flex;justify-content: center;align-items: center;border-radius: 5px;overflow: hidden; font-family: 'helvetica', 'ui-sans';">              
              </div>
              <div class="container" style="margin-left: 20px;margin-right: 20px;">
              <h3>You've got a new mail from ${req.body.fullname}, their email is: ✉️${req.body.email} </h3>
              <div style="font-size: 16px;">
              <p>Message:</p>
              <p>${req.body.message}</p>
              <br>
              </div>
              <img src="https://manuarora.in/logo.png" class="logo-image" style="height: 50px;width: 50px;border-radius: 5px;overflow: hidden;">
              <p class="footer" style="font-size: 16px;padding-bottom: 20px;border-bottom: 1px solid #D1D5DB;">Regards<br>Manu Arora<br>Software Developer<br>+91 9587738861</p>
              <div class="footer-links" style="display: flex;justify-content: center;align-items: center;">
                <a href="https://manuarora.in/" style="text-decoration: none;margin: 8px;color: #9CA3AF;">Website</a>
                <a href="https://manuarora.in/blog/" style="text-decoration: none;margin: 8px;color: #9CA3AF;">Blog</a>
                <a href="https://github.com/manuarora700/" style="text-decoration: none;margin: 8px;color: #9CA3AF;">GitHub</a>
                <a href="https://instagram.com/maninthere/" style="text-decoration: none;margin: 8px;color: #9CA3AF;">Instagram</a>
                <a href="https://linkedin.com/in/manuarora28/" style="text-decoration: none;margin: 8px;color: #9CA3AF;">LinkedIn</a>
                <a href="https://twitter.com/mannupaaji/" style="text-decoration: none;margin: 8px;color: #9CA3AF;">Twitter</a>
                
              </div>
              </div>
      </body>
      </html>`,
    });
  } catch (error) {
    // console.log(error);
    return res.status(error.statusCode || 500).json({ error: error.message });
  }

  return res.status(200).json({ error: "" });
}

export default sendEmail;

如果你想在邮件正文中发送html ,你将不得不使用内联样式,在例子中也有。

在这里,我们基本上是使用SendGrid API提供的SendGrid的send() 方法来发送邮件。我们使用send() 方法和我们用API密钥初始化的sendgrid 对象。这确保了我们的邮件是安全的,并且只通过我们的许可来传递。

此外,我们将代码包裹在一个try - catch 块中。这确保我们的应用程序可以正确地处理异常和错误。如果邮件发送失败,那么代码会立即落入catch() 块中,我们会返回一个error 对象。这表明后端出现了一些问题。

看一下后端的API响应,前端就会做出相应的反应,用户界面就会改变。

风格设计进入send() 方法主体内的html 属性。你想如何设计你的电子邮件,完全取决于你。在这里,我包含了一个简单的模板,其中有通往我的Twitter、Instagram、GitHub和网站的页脚,以及终端用户发送的原始信息体。

现在我们的API路由已经设置好了,所以让我们转到前端,学习如何正确处理响应。

如何调用API和处理响应

由于我们的API路由已经设置好了,我们现在要调用我们的无服务器API并获取响应。

import React, { useState } from "react";

export default function ContactUs() {
  const [fullname, setFullname] = useState("");
  const [email, setEmail] = useState("");
  const [subject, setSubject] = useState("");
  const [message, setMessage] = useState("");



  const handleSubmit = async (e) => {
    e.preventDefault();

    let isValidForm = handleValidation();

     
      const res = await fetch("/api/sendgrid", {
        body: JSON.stringify({
          email: email,
          fullname: fullname,
          subject: subject,
          message: message,
        }),
        headers: {
          "Content-Type": "application/json",
        },
        method: "POST",
      });

      const { error } = await res.json();
      if (error) {
        console.log(error);
        return;
      }
    console.log(fullname, email, subject, message);
  };
  return (
    <main>
        <form class="rounded-lg shadow-xl flex flex-col px-8 py-8 bg-white dark:bg-blue-500">
      <h1 class="text-2xl font-bold dark:text-gray-50">Send a message</h1>

      <label for="fullname" class="text-gray-500 font-light mt-8 dark:text-gray-50">Full name<span class="text-red-500 dark:text-gray-50">*</span></label>
      <input type="text" name="fullname" class="bg-transparent border-b py-2 pl-4 focus:outline-none focus:rounded-md focus:ring-1 ring-green-500 font-light text-gray-500" />

      <label for="email" class="text-gray-500 font-light mt-4 dark:text-gray-50">E-mail<span class="text-red-500">*</span></label>
      <input type="email" name="email" class="bg-transparent border-b py-2 pl-4 focus:outline-none focus:rounded-md focus:ring-1 ring-green-500 font-light text-gray-500" />

      <label for="subject" class="text-gray-500 font-light mt-4 dark:text-gray-50">Subject<span class="text-red-500">*</span></label>
      <input type="text" name="subject" class="bg-transparent border-b py-2 pl-4 focus:outline-none focus:rounded-md focus:ring-1 ring-green-500 font-light text-gray-500" />

      <label for="message" class="text-gray-500 font-light mt-4 dark:text-gray-50">Message<span class="text-red-500">*</span></label>
      <textarea name="message" class="bg-transparent border-b py-2 pl-4 focus:outline-none focus:rounded-md focus:ring-1 ring-green-500 font-light text-gray-500"></textarea>
      <div class="flex flex-row items-center justify-start">
        <button class="px-10 mt-8 py-2 bg-[#130F49] text-gray-50 font-light rounded-md text-lg flex flex-row items-center">
          Send
          <svg width="24" height="24" viewBox="0 0 24 24" class="text-cyan-500 ml-2" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
            <path d="M9.00967 5.12761H11.0097C12.1142 5.12761 13.468 5.89682 14.0335 6.8457L16.5089 11H21.0097C21.562 11 22.0097 11.4477 22.0097 12C22.0097 12.5523 21.562 13 21.0097 13H16.4138L13.9383 17.1543C13.3729 18.1032 12.0191 18.8724 10.9145 18.8724H8.91454L12.4138 13H5.42485L3.99036 15.4529H1.99036L4.00967 12L4.00967 11.967L2.00967 8.54712H4.00967L5.44417 11H12.5089L9.00967 5.12761Z" fill="currentColor" />
          </svg>
        </button>
      </div>
    </form>
    </main>
  );
}

这里我们用fetch 来调用我们刚刚创建的API,它是由React提供的。

Fetch调用无服务器API,其主体是这样的。

body: JSON.stringify({
          email: email,
          fullname: fullname,
          subject: subject,
          message: message,
        })

这些是我们的表单字段,已经填写了表单数据(还记得useState() 吗?),现在可以供我们使用。

API的回应是成功或失败。如果是成功,邮件就会被送达,否则,邮件就不会被送达。

为了让终端用户知道表单的状态,我们需要显示一些UI元素。但在这之前,我们需要处理如果有空字段会发生什么。

如何处理表单验证并使UI响应API的响应

在这里我们需要确保3件事情。

  1. 所有的字段都应该被填写--也就是说,如果任何字段是空的,我们就不能提交表单。另外,用户必须知道为什么表格没有提交。为此,我们要显示错误信息。
  2. 当表单被提交时,用户必须知道一些处理正在进行中。为此,我们将在表单提交的过程中改变按钮的文本。
  3. 当表单成功提交或失败时,我们将在表单的底部显示最终状态。

让我们创建一个方法handleValidation() 来检查验证。


  const handleValidation = () => {
    let tempErrors = {};
    let isValid = true;

    if (fullname.length <= 0) {
      tempErrors["fullname"] = true;
      isValid = false;
    }
    if (email.length <= 0) {
      tempErrors["email"] = true;
      isValid = false;
    }
    if (subject.length <= 0) {
      tempErrors["subject"] = true;
      isValid = false;
    }
    if (message.length <= 0) {
      tempErrors["message"] = true;
      isValid = false;
    }

    setErrors({ ...tempErrors });
    console.log("errors", errors);
    return isValid;
  };

这个函数非常简单明了:它检查所有的字段,如果表单有效,则返回一个布尔值isValid

另外,我们为所有字段保持状态,以便在最后显示错误信息--基本上,我们要保存包含错误的字段。

最后的代码看起来像这样,有按钮文本、错误信息和表单验证。

import React, { useState } from "react";

export default function ContactUs() {
   // States for contact form fields
  const [fullname, setFullname] = useState("");
  const [email, setEmail] = useState("");
  const [subject, setSubject] = useState("");
  const [message, setMessage] = useState("");

  //   Form validation state
  const [errors, setErrors] = useState({});

  //   Setting button text on form submission
  const [buttonText, setButtonText] = useState("Send");

  // Setting success or failure messages states
  const [showSuccessMessage, setShowSuccessMessage] = useState(false);
  const [showFailureMessage, setShowFailureMessage] = useState(false);

  // Validation check method
  const handleValidation = () => {
    let tempErrors = {};
    let isValid = true;

    if (fullname.length <= 0) {
      tempErrors["fullname"] = true;
      isValid = false;
    }
    if (email.length <= 0) {
      tempErrors["email"] = true;
      isValid = false;
    }
    if (subject.length <= 0) {
      tempErrors["subject"] = true;
      isValid = false;
    }
    if (message.length <= 0) {
      tempErrors["message"] = true;
      isValid = false;
    }

    setErrors({ ...tempErrors });
    console.log("errors", errors);
    return isValid;
  };

  //   Handling form submit

  const handleSubmit = async (e) => {
    e.preventDefault();

    let isValidForm = handleValidation();

    if (isValidForm) {
      setButtonText("Sending");
      const res = await fetch("/api/sendgrid", {
        body: JSON.stringify({
          email: email,
          fullname: fullname,
          subject: subject,
          message: message,
        }),
        headers: {
          "Content-Type": "application/json",
        },
        method: "POST",
      });

      const { error } = await res.json();
      if (error) {
        console.log(error);
        setShowSuccessMessage(false);
        setShowFailureMessage(true);
        setButtonText("Send");
        return;
      }
      setShowSuccessMessage(true);
      setShowFailureMessage(false);
      setButtonText("Send");
    }
    console.log(fullname, email, subject, message);
  };
  return (
    <main>
      // Rest of the JSX code goes here. (With form fields)
    </main>
  );
}

当表单成功交付时,我们在用户界面上得到一个漂亮的响应。为了传递这个响应,我们有showSuccessMessageshowFailureMessage 状态。如果来自后端API路由的响应不包含属性error ,这意味着表单提交成功,电子邮件已经被发送。

在这种情况下,showSuccessMessage 被设置为True,这就在表单框的下面显示了相应的标记。如果响应体包含error 的属性,showFailureMessage 被设置为True,屏幕上就会显示相应的信息。

在成功和失败的情况下,我们必须将按钮文本重置为send ,而不是sending... 。为此,我们使用状态setButtonText('send') ,在失败或成功的情况下设置按钮文本。当发送按钮被点击时,我们将按钮文本设置为sending...

如何接收电子邮件和UI响应

当邮件成功送达时,我们会在联系表格本身得到一个成功信息。

而你将成功地收到一封带有我们刚刚创建的模板的电子邮件,由SendGrid 💯安全地传递。

环境变量

请注意,我们使用的是API密钥,而这些密钥是敏感的。这意味着我们应该总是在环境变量中存储秘密或API密钥。

由于我们已经为我们的本地环境设置了.env.local ,托管提供商也需要知道API密钥。

Vercel提供了一个简单的方法,在主机面板上存储API密钥。

要在你的Vercel账户中安全地存储API密钥,请执行以下操作。

  • 转到你的项目页面
  • 转到设置
  • 转到环境变量
  • 添加环境变量的名称,在我们的例子中,它是SENDGRID_API_KEY ,并在值域中添加相应的API密钥。
  • 重新部署你的应用程序,你的项目将在生产环境中工作。

现场演示和源代码

下面是该应用程序的源代码和实时演示。

现场演示
源代码

总结

SendGrid是一个很好的选择,可以用来从网站上发送电子邮件。当你把它与Next.js和他们的无服务器API路由整合在一起时,在你网站的任何部分整合表单就变得非常容易。

SendGrid还为你提供了一个整合模板的选项,你可以为你的电子邮件提供自定义主题。

也有其他选项用于发送电子邮件,如Nodemailer,我过去曾使用过,现在仍用于我的一些项目中。

我花了大约一个小时从头开始构建这个应用程序--这都要感谢Next.js、TailwindCSS和SendGrid极其直观的工作流程和API语义。此外,还要感谢Tailwind Master Kit提供的漂亮的联系页面用户界面。

如果你喜欢这个博客,请尝试在你自己的网站上实现它,这样你就可以接触到你的终端用户。

如果你想提供任何反馈,请通过我的微博联系我,或访问我的网站

编码愉快。)


Manu Arora

马努-阿罗拉

我是一名全栈开发人员,负责构建影响数百万人生活的产品和网络应用。我在推特上发表随机想法 @mannupaaji 并在 manuarora.in 开发项目。


如果你读到这里,请发推特给作者,向他们表示你的关心。鸣谢

免费学习代码。freeCodeCamp的开源课程已经帮助超过40,000人获得了作为开发者的工作。开始吧