如何用JS发送邮件?购物网站邮箱注册验证码功能求助
购物网站邮箱注册+验证码功能实现方案
核心流程拆解
- 用户输入邮箱,前端完成格式校验
- 后端生成6位随机验证码,将验证码与邮箱绑定并设置过期时间(建议5分钟)
- 后端调用邮件服务商API发送验证码邮件
- 用户输入验证码后,前端提交至后端校验有效性
- 校验通过后完成用户注册,同时清理已使用的验证码
后端实现示例(Node.js)
以Node.js + Express + Redis + Nodemailer为例,先安装依赖:
npm install express nodemailer redis bcrypt
核心代码
const express = require('express'); const nodemailer = require('nodemailer'); const redis = require('redis'); const bcrypt = require('bcrypt'); const app = express(); app.use(express.json()); // 初始化Redis客户端(本地服务示例,生产环境需配置对应参数) const redisClient = redis.createClient(); redisClient.connect().catch(console.error); // 配置邮件传输器(以QQ邮箱为例,其他邮箱替换对应配置) const mailTransporter = nodemailer.createTransport({ service: 'qq', auth: { user: 'your-business-email@qq.com', pass: 'your-email-authorization-code' // 邮箱授权码,非登录密码 } }); // 生成6位随机验证码 const generateVerificationCode = () => { return Math.floor(100000 + Math.random() * 900000).toString(); }; // 发送验证码接口 app.post('/api/send-code', async (req, res) => { const { email } = req.body; const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; // 邮箱格式校验 if (!emailRegex.test(email)) { return res.status(400).json({ msg: '邮箱格式不正确' }); } // 限制发送频率(1分钟内只能发一次) const lastSendTime = await redisClient.get(`send_time:${email}`); if (lastSendTime && Date.now() - parseInt(lastSendTime) < 60000) { return res.status(400).json({ msg: '请1分钟后再尝试发送' }); } const code = generateVerificationCode(); // 存储验证码,5分钟过期 await redisClient.setEx(`code:${email}`, 300, code); // 记录发送时间 await redisClient.setEx(`send_time:${email}`, 60, Date.now().toString()); // 发送邮件 const mailOptions = { from: '你的购物网站 <your-business-email@qq.com>', to: email, subject: '你的购物网站注册验证码', html: `<p>您好!您的注册验证码是:<strong>${code}</strong></p><p>验证码5分钟内有效,请及时完成注册。</p>` }; mailTransporter.sendMail(mailOptions, (err, info) => { if (err) { console.error(`发送邮件失败:${err}`); return res.status(500).json({ msg: '验证码发送失败,请稍后重试' }); } res.status(200).json({ msg: '验证码已发送至您的邮箱' }); }); }); // 用户注册接口 app.post('/api/register', async (req, res) => { const { email, code, password } = req.body; // 校验验证码 const storedCode = await redisClient.get(`code:${email}`); if (!storedCode || storedCode !== code) { return res.status(400).json({ msg: '验证码无效或已过期' }); } // 密码加密(10为哈希加盐轮数,越高越安全但耗时更长) const hashedPassword = await bcrypt.hash(password, 10); // 此处添加将用户信息(email、hashedPassword)存入数据库的逻辑 // 示例(MongoDB + Mongoose): // const newUser = new User({ email, password: hashedPassword }); // await newUser.save(); // 清理验证码和发送时间记录 await redisClient.del(`code:${email}`); await redisClient.del(`send_time:${email}`); res.status(200).json({ msg: '注册成功' }); }); app.listen(3000, () => console.log('服务启动在3000端口'));
前端交互实现
HTML表单
<div class="register-container"> <form id="registerForm"> <div class="form-group"> <label>邮箱</label> <input type="email" id="emailInput" placeholder="请输入您的邮箱" required> </div> <div class="form-group"> <label>验证码</label> <div class="code-input-group"> <input type="text" id="codeInput" placeholder="请输入验证码" maxlength="6" required> <button type="button" id="sendCodeBtn">发送验证码</button> </div> </div> <div class="form-group"> <label>密码</label> <input type="password" id="passwordInput" placeholder="请设置密码(不少于6位)" minlength="6" required> </div> <button type="submit" class="submit-btn">完成注册</button> </form> </div>
JavaScript逻辑
const sendCodeBtn = document.getElementById('sendCodeBtn'); const registerForm = document.getElementById('registerForm'); let countdownTimer = null; // 发送验证码按钮点击事件 sendCodeBtn.addEventListener('click', async () => { const email = document.getElementById('emailInput').value; if (!email) { alert('请先输入邮箱'); return; } // 按钮倒计时逻辑 sendCodeBtn.disabled = true; let countdown = 60; sendCodeBtn.textContent = `${countdown}秒后重发`; countdownTimer = setInterval(() => { countdown--; sendCodeBtn.textContent = `${countdown}秒后重发`; if (countdown <= 0) { clearInterval(countdownTimer); sendCodeBtn.disabled = false; sendCodeBtn.textContent = '发送验证码'; } }, 1000); // 调用后端接口 try { const response = await fetch('/api/send-code', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email }) }); const data = await response.json(); if (!response.ok) throw new Error(data.msg); alert(data.msg); } catch (err) { alert(err.message); // 出错后恢复按钮状态 clearInterval(countdownTimer); sendCodeBtn.disabled = false; sendCodeBtn.textContent = '发送验证码'; } }); // 表单提交事件 registerForm.addEventListener('submit', async (e) => { e.preventDefault(); const email = document.getElementById('emailInput').value; const code = document.getElementById('codeInput').value; const password = document.getElementById('passwordInput').value; try { const response = await fetch('/api/register', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, code, password }) }); const data = await response.json(); if (!response.ok) throw new Error(data.msg); alert('注册成功!即将跳转至首页'); // 跳转逻辑 setTimeout(() => window.location.href = '/', 1500); } catch (err) { alert(err.message); } });
关键注意事项
- 邮箱授权码获取:登录邮箱后台开启POP3/SMTP服务,获取授权码替代登录密码,避免账号泄露风险。
- 验证码安全:禁止将验证码明文存储在数据库,用Redis的过期键自动清理无效验证码。
- 接口防护:添加频率限制(如1分钟内同一邮箱只能发一次验证码),防止恶意刷接口消耗邮件资源。
- 密码安全:必须使用bcrypt等哈希算法加密用户密码,绝对禁止明文存储。
- 邮件内容优化:避免使用敏感词汇,添加网站品牌标识,降低被判定为垃圾邮件的概率。
- 异常处理:前后端都要添加异常捕获逻辑,给用户明确的错误提示,提升体验。
内容的提问来源于stack exchange,提问作者levan tulashvili
相关产品推荐
相关产品推荐

