”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 构建专业的电子邮件服务:Gmail OAuth Express + Webhooks

构建专业的电子邮件服务:Gmail OAuth Express + Webhooks

发布于2024-11-03
浏览:688

电子邮件通知对于现代 Web 应用程序至关重要。在本指南中,我们将使用 Express.js 和 Gmail 的 OAuth2 身份验证构建安全的电子邮件通知服务。我们的服务将接受 webhook 请求并根据传入数据自动发送电子邮件。

我们正在建设什么

我们将创建一个 Express 服务器:

  • 通过 POST 请求接收 webhook 数据
  • 使用 OAuth2 通过 Gmail 进行身份验证
  • 根据 webhook 负载发送自定义电子邮件
  • 优雅地处理错误

先决条件

  • Node.js 安装在您的计算机上
  • 启用 Gmail API 的 Google Cloud Console 项目
  • OAuth2 凭据(客户端 ID、客户端密钥、刷新令牌)
  • Express.js 和 async/await 的基本了解

项目设置

首先,安装所需的软件包:

npm install express body-parser nodemailer googleapis dotenv

使用您的凭据创建 .env 文件:

CLIENT_ID=your_client_id
CLIENT_SECRET=your_client_secret
REDIRECT_URI=your_redirect_uri
REFRESH_TOKEN=your_refresh_token
[email protected]

如果您在设置这些凭据时遇到任何困难,就像我一样,您可以按照以下步骤操作...

第 1 步:创建新的 Google Cloud 项目:

一个。转到 https://console.cloud.google.com/
b.单击页面顶部的项目下拉列表
c.点击“新建项目”
d.输入项目名称,点击“创建”

Build a Professional Email Service: Gmail OAuth Express   Webhooks

第 2 步:启用 Gmail API:
一个。在左侧边栏中,转到“API 和服务”>“库”
b.搜索“Gmail API”
c.点击“Gmail API”,然后点击“启用”

Build a Professional Email Service: Gmail OAuth Express   Webhooks


第 3 步:配置 OAuth 同意屏幕:
一个。转到“API 和服务”>“OAuth 同意屏幕”
b.选择“外部”作为用户类型,然后单击“创建”
c.填写必填字段:
- 应用程序名称:[您的应用程序名称]
- 用户支持电子邮件:[您的电子邮件]
- 开发者联系信息:[您的电子邮件]
d.点击“保存并继续”
e.在“范围”页面上,单击“添加或删除范围”
f.查找并选择“https://mail.google.com/”范围
g。单击“更新”,然后单击“保存并继续”
h.在“测试用户”页面,点击“添加用户”
我。添加您的 Gmail 地址并点击“保存并继续”
j。查看摘要并单击“返回仪表板”


第 4 步:创建 OAuth2 凭据:
一个。转到“API 和服务”>“凭据”
b.单击“创建凭据”>“OAuth 客户端 ID”
c.选择“Web应用程序”作为应用程序类型
d.名称:[您的应用名称]
e.授权的 JavaScript 来源:添加服务器的域(例如,用于本地开发的 http://localhost:3000)
Build a Professional Email Service: Gmail OAuth Express   Webhooks
f.授权重定向 URI:
- 添加:https://developers.google.com/oauthplayground
- 添加服务器的回调 URL(如果有的话)(例如,http://localhost:3000/auth/google/callback)
g。点击“创建”
h.弹出窗口将显示您的客户端 ID 和客户端密钥。安全地保存这些。


第五步:获取新的刷新令牌:
一个。转到 https://developers.google.com/oauthplayground/

Build a Professional Email Service: Gmail OAuth Express   Webhooks

b.单击右上角的齿轮图标(如设置)
c.单击复选框“使用您自己的 OAuth 凭据”
d.输入您的新客户端 ID 和客户端密钥
e.关闭设置
f.在左侧边栏中,找到“Gmail API v1”
g。选择 https://mail.google.com/
h.点击“授权API”
我。选择您的 Google 帐户并授予请求的权限
j。在下一个屏幕上,单击“将授权码兑换为令牌”
k.从响应中复制“刷新令牌”

如果您在此过程中或测试电子邮件功能时遇到任何问题,请提供您在评论中看到的具体错误消息或行为。


代码解释

我们来一步步分解实现:

1. 初始设置和依赖关系

const express = require("express");
const bodyParser = require("body-parser");
const nodemailer = require("nodemailer");
const { google } = require("googleapis");
require("dotenv").config();

const app = express();
app.use(bodyParser.json());

这部分设置我们的 Express 服务器并导入必要的依赖项。我们使用 body-parser 来解析 JSON 请求,并使用 dotenv 来管理环境变量。

2.OAuth2配置

const oAuth2Client = new google.auth.OAuth2(
  CLIENT_ID,
  CLIENT_SECRET,
  REDIRECT_URI
);
oAuth2Client.setCredentials({ refresh_token: REFRESH_TOKEN });

我们使用 Google 的身份验证库创建 OAuth2 客户端。这可以使用 Gmail 的 API 处理令牌刷新和身份验证。

3. 邮件发送功能

async function sendEmail(webhookData) {
  const {
    receiver_email, //change data based on your needs
  } = webhookData;

  try {
    const accessToken = await oAuth2Client.getAccessToken();
    const transport = nodemailer.createTransport({
      service: "gmail",
      auth: {
        type: "OAuth2",
        user: process.env.EMAIL_USER,
        clientId: CLIENT_ID,
        clientSecret: CLIENT_SECRET,
        refreshToken: REFRESH_TOKEN,
        accessToken: accessToken,
      },
    });

    const mailOptions = {
      from: `Your Name `,
      to: receiver_email,
      subject: ``, //Add Subject of Email
      html: ``, // Add your HTML template here
    };

    return await transport.sendMail(mailOptions);
  } catch (error) {
    console.error("Error in sendMail function:", error);
    throw error;
  }
}

该函数:

  • 从webhook负载中提取数据,您可以根据需要修改负载
  • 获取新的访问令牌
  • 使用 OAuth2 身份验证创建传输
  • 发送包含自定义内容的电子邮件

4.Webhook端点

app.post("/webhook", async (req, res) => {
  try {
    const webhookData = req.body;
    await sendEmail(webhookData);
    res.status(200).send("Email sent successfully");
  } catch (error) {
    console.error("Error processing webhook:", error);
    res.status(500).send("Error processing webhook");
  }
});

我们的 webhook 端点:

  • 接收POST请求
  • 处理 webhook 数据
  • 发送电子邮件
  • 返回适当的响应

测试

使用curl或Postman测试您的webhook:

curl -X POST http://localhost:4000/webhook \
-H "Content-Type: application/json" \
-d '{
  "receiver_email": "[email protected]",
}'

故障排除

常见问题及解决方案:

  1. 身份验证错误:检查您的 OAuth2 凭据
  2. 令牌过期:确保刷新令牌有效
  3. 缺少数据:验证 webhook 有效负载

结论

您现在拥有一个安全的、OAuth2验证的电子邮件通知系统!此实现为构建更复杂的通知系统提供了坚实的基础,同时保持安全性和可靠性。

希望这篇文章对您设置电子邮件服务有用。

编码愉快! ?

版本声明 本文转载于:https://dev.to/yashrajxdev/build-a-professional-email-service-gmail-oauth2-express-webhooks-2gp8?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • Bootstrap 4 Beta 中的列偏移发生了什么?
    Bootstrap 4 Beta 中的列偏移发生了什么?
    Bootstrap 4 Beta:列偏移的删除和恢复Bootstrap 4 在其 Beta 1 版本中引入了重大更改柱子偏移了。然而,随着 Beta 2 的后续发布,这些变化已经逆转。从 offset-md-* 到 ml-auto在 Bootstrap 4 Beta 1 中, offset-md-*...
    编程 发布于2024-11-15
  • 在 Go 中使用 WebSocket 进行实时通信
    在 Go 中使用 WebSocket 进行实时通信
    构建需要实时更新的应用程序(例如聊天应用程序、实时通知或协作工具)需要一种比传统 HTTP 更快、更具交互性的通信方法。这就是 WebSockets 发挥作用的地方!今天,我们将探讨如何在 Go 中使用 WebSocket,以便您可以向应用程序添加实时功能。 在这篇文章中,我们将介绍: WebSoc...
    编程 发布于2024-11-15
  • 如何使用 GCC 捕获 Linux 中的分段错误?
    如何使用 GCC 捕获 Linux 中的分段错误?
    捕获 Linux 中的分段错误问:我在第三方库中遇到分段错误,但我无法解决根本问题。是否有跨平台或特定于平台的解决方案来使用 gcc 捕获 Linux 中的这些错误?A:Linux 允许将分段错误作为异常处理。当程序遇到此类故障时,它会收到 SIGSEGV 信号。通过设置信号处理程序,您可以拦截此信...
    编程 发布于2024-11-15
  • 如何使用 MySQL 查找今天生日的用户?
    如何使用 MySQL 查找今天生日的用户?
    如何使用 MySQL 识别今天生日的用户使用 MySQL 确定今天是否是用户的生日涉及查找生日匹配的所有行今天的日期。这可以通过一个简单的 MySQL 查询来实现,该查询将存储为 UNIX 时间戳的生日与今天的日期进行比较。以下 SQL 查询将获取今天有生日的所有用户: FROM USERS ...
    编程 发布于2024-11-15
  • 如何在不创建实例的情况下访问Go结构体的类型?
    如何在不创建实例的情况下访问Go结构体的类型?
    在不创建物理结构的情况下访问 Reflect.Type在 Go 中,动态加载问题的解决方案需要访问结构的类型,而无需物理创建它们。虽然现有的解决方案要求在类型注册之前创建结构体并清零,但存在一种更有效的方法。人们可以利用 reflect.TypeOf((*Struct)(nil)).Elem()手术...
    编程 发布于2024-11-15
  • Java中如何高效地将整数转换为字节数组?
    Java中如何高效地将整数转换为字节数组?
    Java 中整数到字节数组的高效转换将整数转换为字节数组可用于多种目的,例如网络传输或数据存储。有多种方法可以实现此转换。ByteBuffer 类:一种有效的方法是使用 ByteBuffer 类。 ByteBuffer 是一个存储二进制数据并提供各种操作来操纵它的缓冲区。使用 ByteBuffer ...
    编程 发布于2024-11-15
  • 如何在 Go 中按多个字段对结构体切片进行排序?
    如何在 Go 中按多个字段对结构体切片进行排序?
    按多个字段对切片对象进行排序按多个条件排序考虑以下 Parent 和 Child 结构:type Parent struct { id string children []Child } type Child struct { id string }假设我们有一个...
    编程 发布于2024-11-15
  • Qt 线程与 Python 线程:我应该在 PyQt 应用程序中使用哪个?
    Qt 线程与 Python 线程:我应该在 PyQt 应用程序中使用哪个?
    PyQt 应用程序中的线程:Qt 线程与 Python 线程寻求使用 PyQt 创建响应式 GUI 应用程序的开发人员经常遇到执行的挑战长时间运行的任务而不影响 UI 的功能。一种解决方案是使用单独的线程来完成这些任务。这就提出了是使用 Qt 线程还是原生 Python 线程模块的问题。Qt 线程提...
    编程 发布于2024-11-15
  • 为什么我的PHP提交按钮没有触发回显和表格显示?
    为什么我的PHP提交按钮没有触发回显和表格显示?
    PHP 提交按钮困境:不可用的回显和表格您的代码打算在单击“提交”按钮时显示回显和表格在 PHP 表单上。但是,您遇到了这些元素仍然隐藏的问题。这是因为您使用 if(isset($_POST['submit'])) 来控制这些元素的显示,但提交按钮缺少 name 属性。解决方案:提供...
    编程 发布于2024-11-15
  • 大批
    大批
    方法是可以在对象上调用的 fns 数组是对象,因此它们在 JS 中也有方法。 slice(begin):将数组的一部分提取到新数组中,而不改变原始数组。 let arr = ['a','b','c','d','e']; // Usecase: Extract till index p...
    编程 发布于2024-11-15
  • 为什么我的 @font-face EOT 字体无法在 Internet Explorer 中通过 HTTPS 加载?
    为什么我的 @font-face EOT 字体无法在 Internet Explorer 中通过 HTTPS 加载?
    @font-face EOT 无法通过 HTTPS 加载:解决方案遇到 @font-face EOT 文件在 Internet 中无法通过 HTTPS 加载的问题在 Explorer 版本 7、8 和 9 中,用户发现无论 HTTPS 上包含的 HTML 页面的托管状态如何,问题仍然存在。经过实验,...
    编程 发布于2024-11-15
  • 为什么通过 Makefile 运行 Go 程序时出现“权限被拒绝”错误?
    为什么通过 Makefile 运行 Go 程序时出现“权限被拒绝”错误?
    权限被拒绝:调查“go run”和 Makefile 调用之间的差异通过 Makefile 运行 Go 程序时遇到权限被拒绝错误可能会令人困惑。此问题源于 GNU make 或其 gnulib 组件中的错误。根本原因在于系统 PATH 中存在一个名为“go”的目录,该目录位于实际 Go 可执行文件所...
    编程 发布于2024-11-15
  • 可以使用 CSS 设计 SVG 背景图像吗?
    可以使用 CSS 设计 SVG 背景图像吗?
    您可以使用 CSS 设计 SVG 背景图像吗?作为 SVG 爱好者,您精通将 SVG 用作背景图像。然而,仍然存在一个持续存在的问题:您是否也可以在同一个文件中使用 CSS 设计 SVG 样式?遗憾的是,答案是不。用作背景图像的 SVG 被视为与 CSS 样式表隔离的单个实体。 CSS 文件中的样式...
    编程 发布于2024-11-15
  • 能否结合使用 LIKE 和 IN 来实现更强大的 SQL 查询?
    能否结合使用 LIKE 和 IN 来实现更强大的 SQL 查询?
    结合LIKE和IN进行高级SQL查询在SQL中,LIKE运算符经常用于模式匹配,而IN运算符允许我们将一个值与一系列特定值进行匹配。虽然这些运算符有不同的用途,但可以将它们组合起来创建更强大的查询。让我们考虑以下场景:您有一个表,其中有一列名为“company_id”,并且您想要选择其中包含该列的所...
    编程 发布于2024-11-15
  • 为什么PHP中逗号可以用于回显但不能用于返回?
    为什么PHP中逗号可以用于回显但不能用于返回?
    为什么用逗号回显有效,而用逗号返回却不起作用?在 PHP 中使用 echo 和 return 连接值时,有使用句号和逗号之间的细微差别。具体来说:Echo:允许以逗号分隔的多个表达式回显到输出。返回:只能返回一个单个表达式。使用句点句点 (.) 运算符将字符串或其他数据类型连接成单个字符串。例如:e...
    编程 发布于2024-11-15

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3