如何使用 Node.js、React.js、Nodemailer 和 OAuth2 实现电子邮件功能

2025-05-25

如何使用 Node.js、React.js、Nodemailer 和 OAuth2 实现电子邮件功能

Nodemailer 是一个 Node.js 模块,允许用户直接向你的邮箱发送邮件。本文将指导你如何使用 OAuth2 将 Node.js 服务器连接到你的 GMail 帐户,以及如何创建 React.js 表单来发送电子邮件。

步骤:
  • 设置 Node.js 服务器
  • 设置 Nodemailer 第一部分
  • 配置 OAuth2
  • 设置 Nodemailer 第 2 部分
  • 设置 Nodemailer 第 3 部分
  • 设置 React.js
  • 设置 Nodemailer 第 4 部分
  • 完成反应

要顺利阅读本文,您需要在设备上安装 Node 和 npm,拥有代码编辑器,并且对 Node.js 和 React.js 有基本的了解。本指南会涉及后端、OAuth2 和前端,所以请耐心等待!

要检查系统上的节点和 npm 版本,请运行以下命令来检索版本号:



node -v
v15.9.0
npm -v
7.5.3


Enter fullscreen mode Exit fullscreen mode

设置 Node.js 服务器

如果您已经安装了 node 和 npm,那就开始吧。

为你的项目创建一个目录。我们将使用 nodemailerAPI。
mkdir nodemailerAPI

进入新nodemailerAPI目录并创建一个server.js文件,它将作为我们的主要文件。



cd nodemailerAPI
touch server.js


Enter fullscreen mode Exit fullscreen mode

在终端中,运行以下命令来初始化 package.json 文件:



npm init -y


Enter fullscreen mode Exit fullscreen mode

现在让我们安装所需的软件包。
在本项目中,我们将使用Express.js, Nodemailer, and Dotenv



npm i express nodemailer dotenv


Enter fullscreen mode Exit fullscreen mode

是时候进行一些 node.js 编码了!

我们将使用 来引入我们的软件包并运行我们的服务器Express.js。在代码编辑器中打开目录并输入以下代码:



const express = require("express");
const nodemailer = require("nodemailer");
const app = express();
require("dotenv").config();

const port = 3001;
app.listen(port, () => {
 console.log(`Server is running on port: ${port}`);
});


Enter fullscreen mode Exit fullscreen mode

输入上述代码后,您将能够使用以下命令运行服务器并查看 console.log:



node server.js
Server is running on port: 3001


Enter fullscreen mode Exit fullscreen mode

我们的服务器现在正在运行,这真是个好消息!让我们暂时停止服务器control-c,然后继续下一步,设置 NodeMailer。

设置 NodeMailer

Nodemailer 需要 3 件事才能开始运行:

  1. 运输者对象
  2. mailOptions 对象
  3. sendMail 方法

步骤 1:让我们设置传输器对象:



let transporter = nodemailer.createTransport({
 service: "gmail",
 auth: {
   type: "OAuth2",
   user: process.env.EMAIL,
   pass: process.env.WORD,
   clientId: process.env.OAUTH_CLIENTID,
   clientSecret: process.env.OAUTH_CLIENT_SECRET,
   refreshToken: process.env.OAUTH_REFRESH_TOKEN,
 },
});


Enter fullscreen mode Exit fullscreen mode

重要提示:用户名和密码分别是你的邮箱地址和邮箱密码。设置好 OAuth2 后,我们将获取 clientId、clientSecret 和 refreshToken。

如您所见,将这些变量存储在.env文件中对于您的隐私非常重要,因此让我们创建一个.env文件来存储我们的身份验证值:



touch .env


Enter fullscreen mode Exit fullscreen mode

在文件中.env输入以下内容:



EMAIL=youremail@gmail.com
WORD=youremailpassword
OAUTH_CLIENTID=
OAUTH_CLIENT_SECRET=
OAUTH_REFRESH_TOKEN=


Enter fullscreen mode Exit fullscreen mode

在继续 NodeMailer 流程​​的第二步之前,让我们设置 OAuth2 并获取其他值!

配置 OAuth2

点击以下链接前往您的Google Cloud Platform信息中心。在左上角附近,您会看到一个下拉箭头。点击后,会弹出一个项目信息窗口。

在弹出模式下,选择新项目选项。

点击“新建项目”按钮后,您将看到一个新屏幕,其中包含一个用于命名新项目的表单。对于此项目,我们将使用“新建项目” nodemailerAPI,您可以跳过位置输入框。点击“创建”。

单击创建后,它将生成您的新项目,并且您将被重定向回您的仪表板。

在创建新项目的同一下拉菜单(左上角)上,您将能够看到您的新项目,现在可以选择它。

选择后,打开左上角的导航菜单并选择以下内容:

单击 OAuth 同意屏幕后,您将进入以下页面,在该页面中单击外部:

单击创建后,您将进入一个新页面,您需要在该页面填写有关新创建项目的信息:

填写完以上信息并点击“保存并继续”后,您将看到 OAuth 配置的“范围”阶段。此页面可以跳过,因此请点击此处的“保存并继续”。

在下一页中,您将自己添加为测试用户:

使用您的 Gmail 将自己添加为测试用户,然后点击“保存并继续”。下一页将汇总所有已输入的信息,此阶段到此结束。

接下来,单击左侧的凭据,然后单击创建凭据并选择 OAuth 客户端 ID:

您将被重定向到以下页面,您可以在其中创建 OAuth 客户端 ID:
将应用程序类型更改为 Web 应用程序。我们将使用 OAuth2 Playground https://developers.google.com/oauthplayground作为授权重定向 URI:

输入这些字段后,您可以单击“创建”。

接下来,您将看到您的 OAuth 客户端 ID 和客户端密钥:

复制这两个值并返回到您的.env文件以填写这些空键。

现在您应该只缺少一个键值:OAUTH_REFRESH_TOKEN,所以让我们去获取它。

前往OAuth Playground。到达那里后,点击屏幕右上角的齿轮图标以调出配置。点击Use your own OAuth credentials并输入刚刚在文件中输入的客户端 ID 和密钥.env

在屏幕左侧,您将看到大量的 API 列表。选择 Gmail API v1,然后选择下拉菜单下的第一个选项:

点击右下角的“授权 API”。这会弹出一个窗口,让你选择你的 Gmail 帐户。选择你的帐户,然后在下一页选择“继续”。

然后,会弹出一个新的窗口,要求您授予该应用从 Gmail 发送电子邮件的权限。点击此处允许。

点击“允许”后,您将被重定向回 OAuth 游乐场仪表板。点击exchange authorization code for tokens即可接收.env文件的刷新令牌:

我们的 OAuth2 配置已经完成,所以让我们回到节点。

NodeMailer 步骤 2:

现在,你应该已经在文件中填写了所有键值对.env。让我们验证一下 Nodemailer 步骤 1 中创建的传输器下面的传输器。



transporter.verify((err, success) => {
 err
   ? console.log(err)
   : console.log(`=== Server is ready to take messages: ${success} ===`);
});


Enter fullscreen mode Exit fullscreen mode

在终端内,再次运行服务器并检查 console.log:



node server.js 
Server is running on port: 3001
=== Server is ready to take messages: true ===


Enter fullscreen mode Exit fullscreen mode

我们成功了!太激动了!

在验证之下,让我们创建一个测试mailOptions对象:



let mailOptions = {
 from: "test@gmail.com",
 to: process.env.EMAIL,
 subject: "Nodemailer API",
 text: "Hi from your nodemailer API",
};


Enter fullscreen mode Exit fullscreen mode

Nodemailer 步骤 3:

mailOptions接下来,让我们通过一种方法发送transporter sendMail



transporter.sendMail(mailOptions, function (err, data) {
 if (err) {
   console.log("Error " + err);
 } else {
   console.log("Email sent successfully");
 }
});


Enter fullscreen mode Exit fullscreen mode

现在,让我们再次运行服务器,在终端内,您将看到:



node server.js 
Server is running on port: 3001
=== Server is ready to take messages: true ===
Email sent successfully


Enter fullscreen mode Exit fullscreen mode

请检查您的电子邮件,因为它就在那里!

此时检查完整的 server.js 代码:



const express = require("express");
const nodemailer = require("nodemailer");
const app = express();
require("dotenv").config();

let transporter = nodemailer.createTransport({
 service: "gmail",
 auth: {
   type: "OAuth2",
   user: process.env.EMAIL,
   pass: process.env.WORD,
   clientId: process.env.OAUTH_CLIENTID,
   clientSecret: process.env.OAUTH_CLIENT_SECRET,
   refreshToken: process.env.OAUTH_REFRESH_TOKEN,
 },
});

transporter.verify((err, success) => {
 err
   ? console.log(err)
   : console.log(`=== Server is ready to take messages: ${success} ===`);
});

let mailOptions = {
 from: "test@gmail.com",
 to: process.env.EMAIL,
 subject: "Nodemailer API",
 text: "Hi from your nodemailer API",
};

transporter.sendMail(mailOptions, function (err, data) {
 if (err) {
   console.log("Error " + err);
 } else {
   console.log("Email sent successfully");
 }
});

const port = 3001;
app.listen(port, () => {
 console.log(`Server is running on port: ${port}`);
});


Enter fullscreen mode Exit fullscreen mode

目前,由于我们尚未建立路由,因此无法从前端访问 Nodemailer。因此,让我们创建路由。

我们transporter.sendMail已经设置好了,所以会很快!我们只需要获取transporter.sendMail并将其放入一个附加到路由的函数中。我们还附加了一个响应操作来返回状态,这将有助于在稍后的 cURL 测试中判断测试是否成功。



app.post("/send", function (req, res) {
 let mailOptions = {
   from: "test@gmail.com",
   to: process.env.EMAIL,
   subject: "Nodemailer API",
   text: "Hi from your nodemailer API",
 };

 transporter.sendMail(mailOptions, function (err, data) {
   if (err) {
     console.log("Error " + err);
   } else {
     console.log("Email sent successfully");
     res.json({ status: "Email sent" });
   }
 });
});


Enter fullscreen mode Exit fullscreen mode

让我们使用 cURL 测试这个新路线。

nodemailerAPI服务器运行时,打开终端,并在新终端选项卡中运行以下命令:



curl -d -url http://localhost:3001/send


Enter fullscreen mode Exit fullscreen mode

运行 cURL 命令后,您将在终端中看到我们的响应:



{"status":"Email sent"}


Enter fullscreen mode Exit fullscreen mode

您应该会在收件箱中看到一封电子邮件;我们的路线现在可以在前端使用了!

======================================================

设置 React.js

React 设置步骤 1:

让我们回到您的终端来创建新的 React 项目,我们将nodemailer-form通过运行以下命令来调用它:



npx create-react-app nodemailer-form


Enter fullscreen mode Exit fullscreen mode

在代码编辑器中打开这个新的 React 目录src/App.js,你将看到 create-react-app 附带的默认 React 代码。让我们删除除顶层之外的所有内容div

为了本指南的目的,我们将仅在 内进行编码App.js,该代码现在是空白的,可供我们开始工作。

导入并设置 useState Hook

在最上面一行App.js,导入 useState 如下:



import { useState } from "react";


Enter fullscreen mode Exit fullscreen mode

发送电子邮件时,我们nodemailerAPI需要输入姓名、邮箱地址和消息内容。因此,我们需要进行useState以下设置:



const [mailerState, setMailerState] = useState({
   name: "",
   email: "",
   message: "",
 });


Enter fullscreen mode Exit fullscreen mode

现在让我们设置一个函数来处理我们在未来的输入框中输入时的变化。



function handleStateChange(e) {
   setMailerState((prevState) => ({
     ...prevState,
     [e.target.name]: e.target.value,
   }));
 }


Enter fullscreen mode Exit fullscreen mode

接下来,让我们创建一个表单并将其附加handleStateChange到每个输入框以及名称和值。



return (
   <div className="App">
     <form>
       <fieldset>
         <legend>React NodeMailer Contact Form</legend>
         <input
           placeholder="Name"
           onChange={handleStateChange}
           name="name"
           value={mailerState.name}
         />
         <input
           placeholder="Email"
           onChange={handleStateChange}
           name="email"
           value={mailerState.email}
         />
         <textarea
           placeholder="Message"
           onChange={handleStateChange}
           name="message"
           value={mailerState.message}
         />
  <button>Send Message</button>
       </fieldset>
     </form>
   </div>
 );


Enter fullscreen mode Exit fullscreen mode

如果你用 运行你的 React 项目,npm start并在 上查看它localhost:3000,你会发现它可能是你所见过的最丑陋的表单之一。让我们快速修复一下,添加一些内联样式,让它看起来像一个联系表单:



<div className="App">
     <form
       style={{
         display: "flex",
         height: "100vh",
         justifyContent: "center",
         alignItems: "center",
       }}
     >
       <fieldset
         style={{
           display: "flex",
           flexDirection: "column",
           justifyContent: "center",
           width: "50%",
         }}
       >
         <legend>React NodeMailer Contact Form</legend>
         <input
           placeholder="Name"
           onChange={handleStateChange}
           name="name"
           value={mailerState.name}
         />
         <input
           placeholder="Email"
           onChange={handleStateChange}
           name="email"
           value={mailerState.email}
         />
         <textarea
           style={{ minHeight: "200px" }}
           placeholder="Message"
           onChange={handleStateChange}
           name="message"
           value={mailerState.message}
         />
         <button>Send Message</button>
       </fieldset>
     </form>
   </div>


Enter fullscreen mode Exit fullscreen mode

此时,您的表单应如下所示:

它仍然不会赢得任何风格比赛(也许在 90 年代),但至少它看起来像那么回事!

它还不能正常工作,所以我们需要让它也发挥作用!
我们需要创建一个函数,用于将数据发送到nodemailerAPI路由,并将其附加到表单上:



const submitEmail = async (e) => {
   e.preventDefault();
   console.log({ mailerState });
   const response = await fetch("http://localhost:3001/send", {
     method: "POST",
     headers: {
       "Content-type": "application/json",
     },
     body: JSON.stringify({ mailerState }),
   })
     .then((res) => res.json())
     .then(() => {
       setMailerState({
         email: "",
         name: "",
         message: "",
       });
     });
 };


Enter fullscreen mode Exit fullscreen mode


<form
   style={{
     display: "flex",
     height: "100vh",
     justifyContent: "center",
     alignItems: "center",
   }}
    onSubmit={submitEmail}
 >


Enter fullscreen mode Exit fullscreen mode

现在,我们的表单应该可以正常使用了,是吗?如果你尝试提交表单,什么也不会发生。如果你使用 Google Chrome 浏览器并打开控制台,你会看到以下内容:

我们的mailerState记录与预期一致,但是我们得到了一个CORs error

还记得之前我提到过我们的后端 API 路由已经差不多准备好了吗?现在到了需要返回 API 并修复一些问题的阶段。

Nodemailer 第 4 部分

让我们回到我们的节点服务器并安装我们的最后一个依赖项:CORs。在 nodemailer API 目录中,运行以下命令:



npm i cors


Enter fullscreen mode Exit fullscreen mode

现在,require cors在文件顶部server.js,告诉应用使用 cors 作为中间件。文件顶部server.js file应该如下所示:



const express = require("express");
const nodemailer = require("nodemailer");
const app = express();
const cors = require("cors");
require("dotenv").config();

// middleware
app.use(express.json());
app.use(cors());


Enter fullscreen mode Exit fullscreen mode

当我们在后端时,我们需要进行更改mail options以反映来自 React 端的请求。

我们当前的邮件选项如下所示:



let mailOptions = {
   from: "test@gmail.com",
   to: process.env.EMAIL,
   subject: "Nodemailer API",
   text: "Hi from your nodemailer API",
 };


Enter fullscreen mode Exit fullscreen mode

但这对我们没有好处,因为这是每次命中此路线时发送的内容,所以我们需要将其更改为如下所示:



let mailOptions = {
   from: `${req.body.mailerState.email}`,
   to: process.env.EMAIL,
   subject: `Message from: ${req.body.mailerState.email}`,
   text: `${req.body.mailerState.message}`,
 };


Enter fullscreen mode Exit fullscreen mode

让我们也更新transporter.sendMail将 json 发送回 react,以便我们可以提醒用户电子邮件已发送:



transporter.sendMail(mailOptions, function (err, data) {
   if (err) {
     res.json({
       status: "fail",
     });
   } else {
     console.log("== Message Sent ==");
     res.json({
       status: "success",
     });
   }
 });


Enter fullscreen mode Exit fullscreen mode

因此,我们的最终server.js文件应该是这样的:



const express = require("express");
const nodemailer = require("nodemailer");
const app = express();
const cors = require("cors");
require("dotenv").config();

// middleware
app.use(express.json());
app.use(cors());

let transporter = nodemailer.createTransport({
 service: "gmail",
 auth: {
   type: "OAuth2",
   user: process.env.EMAIL,
   pass: process.env.WORD,
   clientId: process.env.OAUTH_CLIENTID,
   clientSecret: process.env.OAUTH_CLIENT_SECRET,
   refreshToken: process.env.OAUTH_REFRESH_TOKEN,
 },
});
transporter.verify((err, success) => {
 err
   ? console.log(err)
   : console.log(`=== Server is ready to take messages: ${success} ===`);
});

app.post("/send", function (req, res) {
 let mailOptions = {
   from: `${req.body.mailerState.email}`,
   to: process.env.EMAIL,
   subject: `Message from: ${req.body.mailerState.email}`,
   text: `${req.body.mailerState.message}`,
 };

 transporter.sendMail(mailOptions, function (err, data) {
   if (err) {
     res.json({
       status: "fail",
     });
   } else {
     console.log("== Message Sent ==");
     res.json({
       status: "success",
     });
   }
 });
});

const port = 3001;
app.listen(port, () => {
 console.log(`Server is running on port: ${port}`);
});


Enter fullscreen mode Exit fullscreen mode

我们的指南部分已经完成了。让我们来解决React 中nodemailerAPI的最后一点。nodemailer-form

回到 React 中的表单

我们只需要更新submitEmail函数来等待响应。它等待后端告知它状态是失败还是成功,并相应地发出警报。



const submitEmail = async (e) => {
   e.preventDefault();
   console.log({ mailerState });
   const response = await fetch("http://localhost:3001/send", {
     method: "POST",
     headers: {
       "Content-type": "application/json",
     },
     body: JSON.stringify({ mailerState }),
   })
     .then((res) => res.json())
     .then(async (res) => {
       const resData = await res;
       console.log(resData);
       if (resData.status === "success") {
         alert("Message Sent");
       } else if (resData.status === "fail") {
         alert("Message failed to send");
       }
     })
     .then(() => {
       setMailerState({
         email: "",
         name: "",
         message: "",
       });
     });
 };


Enter fullscreen mode Exit fullscreen mode

因此,当您尝试发送电子邮件时,您将收到以下警报,并且您将在控制台中看到从后端发送的状态:

至此,您已成功使用 OAuth2、React.js、Node.js 和 Express.js 实现了 Nodemailer。现在,您可以将其添加到未来的项目中!

文章来源:https://dev.to/jlong​​4223/how-to-implement-email-functionality-with-node-js-react-js-nodemailer-and-oauth2-2h7m
PREV
四年 DEV 写作经验总结:20+
NEXT
重构初级 React 代码 - 代码量减少 43%,数据结构更优