当前位置: 首页 > news >正文

通过 Node.js 搭配 Nodemailer 实现邮箱验证码发送

目录

一、整体思路

二、环境准备

三、代码详细步骤

1. 引入模块并初始化

2. 配置 Nodemailer 邮件服务

3. 定义发送验证码接口

4. 定义校验验证码接口

5. 启动服务器

四、补充说明

一、整体思路

  1. 接收邮箱地址请求
    用户在前端填写邮箱,发送到后端接口(如 /send-code)。

  2. 后端生成验证码并缓存
    后端生成随机验证码,存入 Redis 或内存(带过期时间)。

  3. 使用 Nodemailer 发邮件
    配置邮箱服务器,用 Nodemailer 发送邮件,将验证码发到用户邮箱。

  4. 用户提交验证码校验
    后端验证用户提交的验证码是否正确并且未过期。

二、环境准备

首先,需要安装必要的 Node.js 包:

npm install express nodemailer redis
  • express:搭建 HTTP 服务器。

  • nodemailer:发送邮件。

  • redis:存验证码,设置过期时间。

三、代码详细步骤

1. 引入模块并初始化

const express = require('express');
const nodemailer = require('nodemailer');
const redis = require('redis');
const { promisify } = require('util');const app = express();
app.use(express.json());// 连接 Redis
const redisClient = redis.createClient();
const setAsync = promisify(redisClient.set).bind(redisClient);
const getAsync = promisify(redisClient.get).bind(redisClient);

2. 配置 Nodemailer 邮件服务

可以选择 SMTP 邮件服务器,比如:

  • Gmail

  • QQ邮箱

  • 阿里云邮件推送

  • SendGrid

示例(以 QQ 邮箱为例):

const transporter = nodemailer.createTransport({host: 'smtp.qq.com',port: 465,secure: true, // true for 465, false for other portsauth: {user: '你的QQ邮箱@qq.com', // 发送方邮箱pass: '授权码'              // 不是密码!是SMTP授权码!}
});

注意:QQ邮箱需要开启 SMTP 服务,并拿到一个授权码,不能用普通密码。

3. 定义发送验证码接口

app.post('/send-code', async (req, res) => {const { email } = req.body;if (!email) {return res.status(400).send({ error: 'Email is required' });}// 生成6位随机验证码const code = Math.floor(100000 + Math.random() * 900000).toString();// 保存到 Redis,设置过期时间5分钟await setAsync(`verify:${email}`, code, 'EX', 300);// 发送邮件const mailOptions = {from: '你的QQ邮箱@qq.com',to: email,subject: '您的验证码',text: `您的验证码是 ${code},有效期5分钟,请勿泄露。`};try {await transporter.sendMail(mailOptions);res.send({ message: '验证码发送成功' });} catch (err) {console.error('发送失败', err);res.status(500).send({ error: '验证码发送失败' });}
});

4. 定义校验验证码接口

app.post('/verify-code', async (req, res) => {const { email, code } = req.body;if (!email || !code) {return res.status(400).send({ error: 'Email and code are required' });}const savedCode = await getAsync(`verify:${email}`);if (!savedCode) {return res.status(400).send({ error: '验证码已过期或不存在' });}if (savedCode === code) {return res.send({ message: '验证成功' });} else {return res.status(400).send({ error: '验证码错误' });}
});

5. 启动服务器

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {console.log(`服务器运行在 http://localhost:${PORT}`);
});

四、补充说明

  1. 限流控制(防止恶意刷验证码)

    • 比如一个邮箱1分钟内只能发送一次。

    • 可以在 Redis 里加一层锁或者计数器。

  2. 验证码加密

    • 验证码可以使用简单加密(例如哈希存储),提高安全性。

  3. 防止暴力破解

    • 连续错误输验证码次数超过3次,锁定一段时间。

  4. 生产环境发送 HTML 格式邮件

    • 邮件正文可以用 HTML 格式美化,比如加品牌 Logo、验证码提示等。

  5. 异步处理发送邮件

    • 邮件发送可以做成异步,或者通过消息队列(如 RabbitMQ)解耦,提高响应速度。

相关文章:

通过 Node.js 搭配 Nodemailer 实现邮箱验证码发送

目录 一、整体思路 二、环境准备 三、代码详细步骤 1. 引入模块并初始化 2. 配置 Nodemailer 邮件服务 3. 定义发送验证码接口 4. 定义校验验证码接口 5. 启动服务器 四、补充说明 一、整体思路 接收邮箱地址请求 → 用户在前端填写邮箱,发送到后端接口&…...

Java后端程序员学习前端之html

什么是html Hyper Text Markup Language(超文本标记语言) 超文本包括:文字、图片、音频、视频、动画等 组织:W3C World Wide Web Consortium(万维网联盟)。 成立子1994年,Web技术领域最权威和具影响力的国际中立性技术标准机构 http://www.w3.org! …...

[密码学实战]SDF之非对称运算类函数(三)

[密码学实战]SDF之非对称运算类函数(三) 一、标准解读:GM/T 0018-2023核心要求 1.1 SDF接口定位 安全边界:硬件密码设备与应用系统间的标准交互层 功能范畴: #mermaid-svg-4fs0ed6OYQs5fXlc {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:…...

MCP 架构全解析:Host、Client 与 Server 的协同机制

目录 🏗️ MCP 架构全解析:Host、Client 与 Server 的协同机制 📌 引言 🧩 核心架构组件 1. Host(主机) 2. Client(客户端) 3. Server(服务器) &#…...

第三部分:赋予网页灵魂 —— JavaScript(下)

目录 7 DOM 操作:控制网页的"智能面板7.1 小例子:点击按钮时改变段落文字,根据用户输入改变图片7.2 练习:实现一个简单的 Tab 切换效果 8 事件处理:响应用户的"指令"8.1 小例子:实现点击按钮…...

(02)Redis 的订阅发布Pub/Sub

我们为了自己实现一个MQ功能,就要深入底层挖掘现有开源产品的实现过程。 Redis 发布订阅底层结构解析 Redis 不存储消息,仅作为“实时中转”;只有订阅者在线时才能收到消息;消息是广播给所有订阅此频道的客户端。 1. 核心数据结…...

JavaScript性能优化实战:从基础到高级的全面指南

作为前端开发者,掌握JavaScript性能优化是提升用户体验和职业竞争力的关键。本文将系统性地介绍JavaScript性能优化的各个方面,从基础概念到高级技巧,帮助你编写更高效的代码。 一、JavaScript性能优化基础概念 1.1 什么是JavaScript性能优…...

CertiK创始人顾荣辉出席Unchained Summit,探讨Web3.0安全与合规路径

4月28日,CertiK联合创始人、哥伦比亚大学教授顾荣辉出席迪拜Unchained Summit峰会并发表主题演讲,探讨Web3.0在创新与安全间的平衡,引发网易科技、中国财经时报、腾讯网、新浪财经等多家知名媒体的关注和报道。 作为迪拜最重要的峰会之一&am…...

企业出海降本:如何将应用从 AWS EC2 快速无缝迁移至DigitalOcean Droplet

企业出海已经成为目前最热门的趋势。然而不论你是做跨境电商,还是短剧出海,或处于最热门的AI 赛道,你都需要使用海外的云主机或GPU云服务。海外一线的云服务平台尽管覆盖区域广泛,但是往往费用成本较高。所以降本始终是企业出海关…...

java练习2

package a01_第一次练习.a02_计算输入天数;import java.text.ParseException; import java.time.Duration; import java.time.LocalDateTime; import java.util.Scanner;public class Test {public static void main(String[] args) throws ParseException {//当前时间LocalDat…...

PDM是什么?PDM有什么用?怎么选PDM?2025制造PDM/PLM系统盘点(4000字)

(文章来自CRDE PDM研究中心) 摘要 PDM是制造企业产品数据管理的核心工具,并逐渐发展出了PLM、云PLM等新形态,在功能增加的同时成本也有大幅降低,已经成为企业研发管理的最优选择,并逐渐被有产品创新需求的…...

TiDB 可观测性最佳实践

TiDB 介绍 TiDB,由 PingCAP 公司自主研发的开源分布式关系型数据库,是一款创新的 HTAP 数据库产品,它融合了在线事务处理(OLTP)和在线分析处理(OLAP)的能力,支持水平扩容和缩容&…...

8.idea创建maven项目(使用Log4j日志记录框架+Log4j 介绍)

8.idea创建maven项目(使用Log4j日志记录框架Log4j 介绍) 在 IntelliJ IDEA 的 Maven 项目中引入了 Log4j,并配置了日志同时输出到控制台和文件。 Log4j 提供了灵活的日志配置选项,可以根据项目需求调整日志级别、输出目标和格式。 1. 创建 Maven 项目 …...

Linux 命名管道+日志

一、命名管道 1.1 进程通信的前提:先让不同进程看到同一份资源; 1.2 如何确保两个进程打开的是同一个文件:同路径下同一文件名; 1.3 命名管道:通过路径文件名确保这个份资源的唯一性; 1.4 接口&#xf…...

c/c++之信号处理<signal.h>

该库提供了一组用于处理信号的函数和宏。信号是由操作系统或程序本身生成的一种异步事件,用于通知某些事件的发生,例如非法操作、用户中断等。 信号 信号是进程之间通信的重要方式。信号是一种异步通知机制,由操作系统或其他进程发送给当前进…...

基于PyTorch的图像分类特征提取与模型训练文档

概述 本代码实现了一个基于PyTorch的图像特征提取与分类模型训练流程。核心功能包括: 使用预训练ResNet18模型进行图像特征提取 将提取的特征保存为标准化格式 基于提取的特征训练分类模型 代码结构详解 1. 库导入 import torch import torch.nn as nn import…...

DDoS vs CC攻击:哪种对服务器威胁更大?

引言 DDoS(分布式拒绝服务)与CC(Challenge Collapsar)攻击是两种常见的网络攻击手段,均会导致服务器资源耗尽、服务中断。但它们的攻击原理、防御难度及危害程度存在显著差异。本文将从技术原理、攻击效果、防御成本等…...

Weiss Robotics的WPG与WSG系列紧凑型机器人夹爪,精准、灵活、高效

在自动化和智能制造领域,Weiss Robotics 以其创新的智能抓取系统而受到广泛认可。本文将重点介绍 Weiss Robotics 的两大产品系列:WPG 系列和 WSG 系列。这些产品系列凭借其先进的技术特性,为各行各业的自动化需求提供了高效、灵活的解决方案…...

引力透镜效应添加光线弯曲程度可视化层的MATLAB代码

物理实现要点: ‌雅可比矩阵计算‌ 通过数值梯度计算偏转场的空间导数: 放大率μ反映像的亮度增强倍数 ‌动态范围处理‌ 使用对数压缩μ值范围:μ_vis log10(1μ),避免高放大率区域饱和 ‌多物理量联合显示‌ 红圈标注爱因…...

OpenCV 图形API(71)图像与通道拼接函数-----从图像(GMat)中裁剪出一个矩形区域的操作函数 crop()

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 裁剪一个2D矩阵。 该函数根据给定的 cv::Rect 裁剪矩阵。 输出矩阵必须与输入矩阵具有相同的深度,大小由给定的矩形大小指定。 注意…...

tarjan缩点+强联通分量

【模板】缩点https://www.luogu.com.cn/problem/P3387 首先我们要理解这道题为什么要用缩点 题目说的是有向图,如果无环的话就可以用DP来解决了 由于可以走重复的点,所以一个环上的点可以看成是一个点,它的点权就等于该环上所有点的点权之…...

tornado_登录页面(案例)

目录 1.基础知识​编辑 2.脚手架(模版) 3.登录流程图(processon) 4.登录表单 4.1后(返回值)任何值:username/password (4.1.1)app.py (4.1.2&#xff…...

Educational Codeforces Round 178 (Rated for Div. 2)

ABC 略 D n个数互质&#xff0c;即n个数都是质数&#xff0c;预处理前4e5个质数&#xff0c;原排列从大到小排序求前缀和&#xff0c;质数求前缀和&#xff0c;从后往前循环第一个前者前缀和能大于等于后者就是留下的i个数。 #include<bits/stdc.h> #define int long …...

从Transformer原理角度来看,prompt设置输出字数限制会生效的原因

从Transformer原理角度来看,prompt设置输出字数限制会生效的原因 1. 生成过程的控制 Transformer在生成文本时是一个自回归的过程,它从起始标记开始,逐个生成下一个单词或标记。在这个过程中,模型会根据已经生成的文本和自身的参数来预测下一个可能的标记的概率分布。当设…...

WEB漏洞--CSRF及SSRF案例

CSRF案例 原理 检测是否存在CSRF&#xff08;跨站请求伪造&#xff09;漏洞 1. 手动测试 构造恶意请求&#xff1a;创建一个恶意网页或电子邮件&#xff0c;包含指向目标网站的恶意请求&#xff08;如更改密码或发送消息的URL&#xff09;。诱使用户访问该恶意请求&#xff0c;…...

Android开发——实现一个计算器

目录 代码讲解 activity_calculator.xmld代码讲解 1. 根布局&#xff08;LinearLayout&#xff09; 2. 显示区域&#xff08;TextView&#xff09; 3. 按钮区域&#xff08;GridLayout&#xff09; 4. 清除和删除按钮 5. 数字和操作符按钮 6. 其他行的按钮 7. 最后一行…...

23G显存可以跑多大尺寸的Qwen3?

随着阿里Qwen3系列大模型的发布,开发者们对如何在有限显存下部署不同尺寸的模型尤为关注。本文基于Qwen3的技术特性和实际测试数据,探讨在23G显存环境下可运行的模型选择及优化策略。 不过由于咱财力有限,只有一张A100,还不是空的,目前只有23G的显存。 那么这23G显存能跑…...

网络通讯【QTcpServer、QTcpSocket、QAbstractSocket】

目录 QTcpServer class简单描述成员函数和信号 QTcpSocket Class详细描述成员函数和信号 QAbstractSocket Class详细描述成员函数和信号成员函数说明文档 QT实现服务器和客户端通讯服务器端&#xff1a;通讯流程原代码 客户端通信流程原代码 QTcpServer class header: #includ…...

std::functional 类是干什么用的?

author: hjjdebug date: 2025年 04月 29日 星期二 15:54:53 CST description: std::functional 类是干什么用的&#xff1f; 文章目录 1.functional 对象的概念2.functional 对象存在的意义2.1 为什么要把接口再封一层&#xff1f;2.2 c中函数参数可以不用回调函数, 而改用func…...

人事管理系统6

模糊查询 DepartmentMapper.xml &#xff1a; <select id"findDepartmentListByName" resultMap"BaseResultMap"> select <include refid"Base_Column_List"/> from department where dname like %${dname}% /*where dname like con…...

链表的中间节点

这题需要用到快慢指针的思想&#xff0c;快指针叫fast&#xff0c;慢指针是slow&#xff0c;快指针每次往后移两个节点&#xff0c;slow只移动一个节点&#xff0c;这样子fast的速度是slow的两遍&#xff0c;当fast遍历完链表&#xff0c;slow才遍历一半&#xff0c;正好就在中…...

【学习学学】城市群与都市圈是什么?怎么

城市群与都市圈是什么&#xff1f;怎么发展 这些年城市群&#xff0c;都市圈的概念被逐渐提了出来&#xff0c;也是未来我国即将重点发展的对象之一。 因此&#xff0c;身边有一些朋友在问&#xff0c;城市群与都市圈有什么区别&#xff1f;哪个对城市发展影响更大&#xff1f…...

【深度学习与大模型基础】第14章-分类任务与经典分类算法

Part 1&#xff1a;什么是分类任务&#xff1f; 1.1 分类就是“贴标签” 想象你有一堆水果&#xff0c;有苹果&#x1f34e;、橘子&#x1f34a;、香蕉&#x1f34c;&#xff0c;你的任务是让机器学会自动判断一个新水果属于哪一类——这就是分类&#xff08;Classification&…...

第十五章:预训练大语言模型

目录 15.1 数据准备 15.1.1 数据预处理 15.1.2 数据调度 15.2 模型架构 15.2.1 主流架构 一、编码器架构&#xff08;Encoder-only&#xff0c;以 BERT 为代表&#xff09; 核心特点&#xff1a; 代表模型&#xff1a;BERT、RoBERTa、ALBERT 典型应用&#xff1a; 二…...

万象生鲜配送系统代码2025年4月29日更新日志

亲爱的用户&#xff1a;万象生鲜配送系统始终致力于为您提供更优质、高效的服务体验。经过我们技术团队的不懈努力&#xff0c;万象生鲜配送系统在 2025 年 4 月迎来了一次重大更新。本次更新涵盖了多个方面&#xff0c;包括功能新增、性能优化以及问题修复&#xff0c;旨在进一…...

Mac 创建QT按钮以及一些操作

在创建QT项目好 后我们打开mainwindow.cpp&#xff0c;下面所示的代码都是在这个cpp文件里面因为它是窗口的入口函数 #include "mainwindow.h" #include "ui_mainwindow.h" #include<QPushButton>//按钮的头文件MainWindow::MainWindow(QWidget *pa…...

C++学习之shell高级和正则表达式

目录 1.正则表达式 2.C中使用正则 3.复习 4.sort命令 5.uniq命令 6.wc命令 7.grep命令 8.find命令 9.xargs命令 10.sed命令 11.awk命令 12.crontab 1.正则表达式 1 管道 使用| 将多个命令拼接在一起 原理&#xff0c;就是将前一个命令的标准输出作为后一个…...

SpringBoot获取用户信息常见问题(密码屏蔽、驼峰命名和下划线命名的自动转换)

文章目录 一、不返回password字段二、返回的createTime和updateTime为空原因解决&#xff1a;开启驼峰命名和下划线命名的自动转换 一、不返回password字段 在字段上面添加JsonIgnore注解即可 JsonIgnore // 在把对象序列化成json字符串时&#xff0c;忽略该字段 private Str…...

优化PCB Via Stub系列(2) – 运用U-Turn Via设计破解阻抗匹配困境,改善信号完整性

在PCB设计中&#xff0c;往往透过制程改善如背钻、盲孔或埋孔&#xff0c;来消除不必要的Via stub&#xff0c;可是多出来的制造成本会压低产品的毛利&#xff0c;可是又有什么办法可以不透过制程改善以缩小Via stub带来的SI困扰呢&#xff1f; 本周我们来讲从Layout布局的角度…...

飞鸟游戏模拟器 1.0.3 | 完全免费无广告,内置大量经典童年游戏,重温美好回忆

飞鸟游戏模拟器是一款专为安卓用户设计的免费游戏模拟器&#xff0c;内置了大量经典的童年游戏。该模拟器拥有丰富的游戏资源&#xff0c;目前已有约20,000款游戏&#xff0c;包括多种类型如冒险、动作、角色扮演等。用户可以直接搜索查找想要玩的游戏进行下载并启动。游戏库中…...

​钓鱼网页散播银狐木马,远控后门威胁终端安全

在当今网络环境下&#xff0c;许多人都有通过搜索引擎下载应用程序的习惯&#xff0c;虽然这种方式简单又迅速&#xff0c;但这也可能被不法分子所利用&#xff0c;通过设置钓鱼网站来欺骗用户。这些钓鱼网站可能会通过各种方式吸引用户点击&#xff0c;从而进行病毒的传播&…...

一文读懂 JavaScript 中的深浅拷贝

在 JavaScript 编程里&#xff0c;深浅拷贝是处理数据时极为关键的概念。理解它们的差异&#xff0c;能帮我们规避许多数据操作上的 “陷阱”。今天&#xff0c;咱们就借助简单的 “abc” 相关示例&#xff0c;深入探索深浅拷贝的奥秘&#xff0c;并且通过在浏览器控制台输出结…...

5G技术在工业4.0中的应用:连接未来,驱动智能制造

5G技术在工业4.0中的应用&#xff1a;连接未来&#xff0c;驱动智能制造 引言 工业4.0&#xff0c;作为第四次工业革命的核心&#xff0c;已经在全球范围内掀起了智能制造的浪潮。它不仅包括了自动化生产、智能物流、云计算和大数据的应用&#xff0c;更是融合了互联网、物联网…...

驱动开发硬核特训 · Day 25 (附加篇):从设备树到驱动——深入理解Linux时钟子系统的实战链路

一、前言 在嵌入式Linux开发中&#xff0c;无论是CPU、外设控制器&#xff0c;还是简单的GPIO扩展器&#xff0c;大多数硬件模块都离不开时钟信号的支撑。 时钟子系统&#xff08;Clock Subsystem&#xff09;&#xff0c;作为Linux内核中基础设施的一部分&#xff0c;为设备…...

数据结构---单链表的增删查改

前言&#xff1a; 经过了几个月的漫长岁月&#xff0c;回头时年迈的小编发现&#xff0c;数据结构的内容还没有写博客&#xff0c;于是小编赶紧停下手头的活动&#xff0c;补上博客以洗清身上的罪孽 目录 前言 概念&#xff1a; 单链表的结构 我们设定一个哨兵位头节点给链…...

【codeforces 2104D,E】欧拉筛,字符串上dp

【codeforces 2104D&#xff0c;E】欧拉筛&#xff0c;字符串上dp Problem - D - Codeforces 题意&#xff1a; 给定一个长度为 n n n的数组 a 1 , a 2 , . . . , a n a_1, a_2, ... , a_n a1​,a2​,...,an​&#xff0c;其中 2 ≤ a i ≤ 1 0 9 2 \leq a_i \leq 10^9 2≤…...

UEC++第15天|番茄插件、实现跳跃、实现背景运动

这是flyBird的第二天&#xff0c;做了一些简单的功能&#xff0c;明天继续更新 vs的番茄插件 在visual stdudio里使用可以帮助代码补全&#xff0c;这一篇博客写的不错&#xff0c;大家可以参考一下。VS2019 安装番茄助手&#xff08;Visual Assist x 插件&#xff09;攻略_vs…...

论文笔记-基于多层感知器(MLP)的多变量桥式起重机自适应安全制动与距离预测

《IET Cyber-Systems and Robotics》出版山东大学 Tenglong Zhang 和 Guoliang Liu 团队的研究成果&#xff0c;文章题为“Adaptive Safe Braking and Distance Prediction for Overhead Cranes With Multivariation Using MLP”。 摘要 桥式起重机的紧急制动及其制动距离预测是…...

[论文阅读]Adversarial Semantic Collisions

Adversarial Semantic Collisions Adversarial Semantic Collisions - ACL Anthology Proceedings of the 2020 Conference on Empirical Methods in Natural Language Processing (EMNLP) 对抗样本是相似的输入但是产生不同的模型输出&#xff0c;而语义冲突是对抗样本的逆…...

Redis Sentinel 和 Redis Cluster 各自的原理、优缺点及适用场景是什么?

我们来详细分析下 Redis Sentinel (哨兵) 和 Redis Cluster (集群) 这两种方案的原理和使用场景。 Redis Sentinel (哨兵) 原理: Sentinel 本身是一个或一组独立于 Redis 数据节点的进程。它的核心职责是监控一个 Redis 主从复制 (Master-Slave) 架构。多个 Sentinel 进程协同…...