如何使用 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
设置 Node.js 服务器
如果您已经安装了 node 和 npm,那就开始吧。
为你的项目创建一个目录。我们将使用 nodemailerAPI。mkdir nodemailerAPI
进入新nodemailerAPI
目录并创建一个server.js
文件,它将作为我们的主要文件。
cd nodemailerAPI
touch server.js
在终端中,运行以下命令来初始化 package.json 文件:
npm init -y
现在让我们安装所需的软件包。
在本项目中,我们将使用Express.js, Nodemailer, and Dotenv
。
npm i express nodemailer dotenv
是时候进行一些 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}`);
});
输入上述代码后,您将能够使用以下命令运行服务器并查看 console.log:
node server.js
Server is running on port: 3001
我们的服务器现在正在运行,这真是个好消息!让我们暂时停止服务器control-c
,然后继续下一步,设置 NodeMailer。
设置 NodeMailer
Nodemailer 需要 3 件事才能开始运行:
- 运输者对象
- mailOptions 对象
- 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,
},
});
重要提示:用户名和密码分别是你的邮箱地址和邮箱密码。设置好 OAuth2 后,我们将获取 clientId、clientSecret 和 refreshToken。
如您所见,将这些变量存储在.env
文件中对于您的隐私非常重要,因此让我们创建一个.env
文件来存储我们的身份验证值:
touch .env
在文件中.env
输入以下内容:
EMAIL=youremail@gmail.com
WORD=youremailpassword
OAUTH_CLIENTID=
OAUTH_CLIENT_SECRET=
OAUTH_REFRESH_TOKEN=
在继续 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} ===`);
});
在终端内,再次运行服务器并检查 console.log:
node server.js
Server is running on port: 3001
=== Server is ready to take messages: true ===
我们成功了!太激动了!
在验证之下,让我们创建一个测试mailOptions
对象:
let mailOptions = {
from: "test@gmail.com",
to: process.env.EMAIL,
subject: "Nodemailer API",
text: "Hi from your nodemailer API",
};
Nodemailer 步骤 3:
mailOptions
接下来,让我们通过一种方法发送transporter sendMail
:
transporter.sendMail(mailOptions, function (err, data) {
if (err) {
console.log("Error " + err);
} else {
console.log("Email sent successfully");
}
});
现在,让我们再次运行服务器,在终端内,您将看到:
node server.js
Server is running on port: 3001
=== Server is ready to take messages: true ===
Email sent successfully
请检查您的电子邮件,因为它就在那里!
此时检查完整的 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}`);
});
目前,由于我们尚未建立路由,因此无法从前端访问 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" });
}
});
});
让我们使用 cURL 测试这个新路线。
在nodemailerAPI
服务器运行时,打开终端,并在新终端选项卡中运行以下命令:
curl -d -url http://localhost:3001/send
运行 cURL 命令后,您将在终端中看到我们的响应:
{"status":"Email sent"}
您应该会在收件箱中看到一封电子邮件;我们的路线现在可以在前端使用了!
======================================================
设置 React.js
React 设置步骤 1:
让我们回到您的终端来创建新的 React 项目,我们将nodemailer-form
通过运行以下命令来调用它:
npx create-react-app nodemailer-form
在代码编辑器中打开这个新的 React 目录src/App.js
,你将看到 create-react-app 附带的默认 React 代码。让我们删除除顶层之外的所有内容div
:
为了本指南的目的,我们将仅在 内进行编码App.js
,该代码现在是空白的,可供我们开始工作。
导入并设置 useState Hook
在最上面一行App.js
,导入 useState 如下:
import { useState } from "react";
发送电子邮件时,我们nodemailerAPI
需要输入姓名、邮箱地址和消息内容。因此,我们需要进行useState
以下设置:
const [mailerState, setMailerState] = useState({
name: "",
email: "",
message: "",
});
现在让我们设置一个函数来处理我们在未来的输入框中输入时的变化。
function handleStateChange(e) {
setMailerState((prevState) => ({
...prevState,
[e.target.name]: e.target.value,
}));
}
接下来,让我们创建一个表单并将其附加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>
);
如果你用 运行你的 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>
它仍然不会赢得任何风格比赛(也许在 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: "",
});
});
};
<form
style={{
display: "flex",
height: "100vh",
justifyContent: "center",
alignItems: "center",
}}
onSubmit={submitEmail}
>
现在,我们的表单应该可以正常使用了,是吗?如果你尝试提交表单,什么也不会发生。如果你使用 Google Chrome 浏览器并打开控制台,你会看到以下内容:
我们的mailerState
记录与预期一致,但是我们得到了一个CORs error
。
还记得之前我提到过我们的后端 API 路由已经差不多准备好了吗?现在到了需要返回 API 并修复一些问题的阶段。
Nodemailer 第 4 部分
让我们回到我们的节点服务器并安装我们的最后一个依赖项:CORs
。在 nodemailer API 目录中,运行以下命令:
npm i cors
现在,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());
当我们在后端时,我们需要进行更改mail options
以反映来自 React 端的请求。
我们当前的邮件选项如下所示:
let mailOptions = {
from: "test@gmail.com",
to: process.env.EMAIL,
subject: "Nodemailer API",
text: "Hi from your nodemailer API",
};
但这对我们没有好处,因为这是每次命中此路线时发送的内容,所以我们需要将其更改为如下所示:
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
将 json 发送回 react,以便我们可以提醒用户电子邮件已发送:
transporter.sendMail(mailOptions, function (err, data) {
if (err) {
res.json({
status: "fail",
});
} else {
console.log("== Message Sent ==");
res.json({
status: "success",
});
}
});
因此,我们的最终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}`);
});
我们的指南部分已经完成了。让我们来解决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: "",
});
});
};
因此,当您尝试发送电子邮件时,您将收到以下警报,并且您将在控制台中看到从后端发送的状态:
至此,您已成功使用 OAuth2、React.js、Node.js 和 Express.js 实现了 Nodemailer。现在,您可以将其添加到未来的项目中!
文章来源:https://dev.to/jlong4223/how-to-implement-email-functionality-with-node-js-react-js-nodemailer-and-oauth2-2h7m