如何用Nodemailer实现表单提交后先后发送管理员与用户邮件?
实现步骤
一、后端Node.js服务改造
将原有GET接口改为POST接口以接收React表单数据,通过async/await实现邮件顺序发送(先管理员通知,成功后再发用户确认邮件),避免回调嵌套的混乱。
改造后的后端代码
const express = require('express') const nodeMailer = require('nodemailer') const cors = require('cors') // 解决跨域问题,需先安装:npm install cors const app = express() // 配置跨域和JSON解析 app.use(cors()) app.use(express.json()) // 初始化邮件传输器(保持原配置) let mailTransport = nodeMailer.createTransport({ service: 'gmail', auth: { user: 'xuser@gmail.com', pass: 'dplcflaj21jcdtspsv22' // 生产环境建议用环境变量存储,比如process.env.EMAIL_PASS } }) // 发送管理员通知邮件 async function sendAdminAlert(userInfo) { const adminMailOpts = { from: 'xuser@gmail.com', to: 'testadmin@gmail.com', subject: `新用户提交:${userInfo.name}`, html: ` <h3>新增用户信息</h3> <p><strong>姓名:</strong>${userInfo.name}</p> <p><strong>邮箱:</strong>${userInfo.email}</p> <p><strong>地址:</strong>${userInfo.address}</p> ` } await mailTransport.sendMail(adminMailOpts) } // 发送用户确认邮件 async function sendUserConfirm(userInfo) { const userMailOpts = { from: 'xuser@gmail.com', to: userInfo.email, subject: `感谢您的提交,${userInfo.name}`, html: ` <h3>提交成功!</h3> <p>您好 ${userInfo.name},我们已收到您的信息:</p> <p><strong>地址:</strong>${userInfo.address}</p> <p>我们会尽快与您取得联系。</p> ` } await mailTransport.sendMail(userMailOpts) } // 表单提交处理接口 app.post('/submit-form', async (req, res) => { try { const userData = req.body // 1. 优先发送管理员通知邮件 await sendAdminAlert(userData) console.log('管理员邮件发送成功') // 2. 管理员邮件成功后,发送用户确认邮件 await sendUserConfirm(userData) console.log('用户确认邮件发送成功') res.status(200).json({ success: true, msg: '邮件发送完成' }) } catch (err) { console.error('邮件发送失败:', err) // 任意一步出错,返回错误信息给前端 res.status(500).json({ success: false, msg: '邮件发送失败,请稍后重试' }) } }) app.listen(3000, () => { console.log('服务运行在端口3000') })
关键说明
- 顺序执行保证:用
async/await确保只有管理员邮件成功后,才会触发用户确认邮件的发送,避免逻辑混乱。 - 代码可维护性:将两类邮件的发送逻辑拆分为独立函数,便于后续修改内容或扩展。
- 安全提示:生产环境务必将邮箱密码等敏感信息存入环境变量,禁止硬编码;Gmail用户若开启两步验证,需使用应用专用密码替代普通密码。
二、前端React表单实现
创建表单组件收集用户信息,提交到后端接口并处理提交状态反馈。
React表单组件示例
import { useState } from 'react' function UserInfoForm() { const [formData, setFormData] = useState({ name: '', email: '', address: '' }) const [submitMsg, setSubmitMsg] = useState('') const handleInputChange = (e) => { const { name, value } = e.target setFormData(prev => ({ ...prev, [name]: value })) } const handleSubmit = async (e) => { e.preventDefault() setSubmitMsg('提交中...') try { const res = await fetch('http://localhost:3000/submit-form', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(formData) }) const result = await res.json() if (result.success) { setSubmitMsg('提交成功!确认邮件已发送至您的邮箱') // 重置表单 setFormData({ name: '', email: '', address: '' }) } else { setSubmitMsg('提交失败,请稍后重试') } } catch (err) { setSubmitMsg('网络错误,请检查连接') console.error('提交异常:', err) } } return ( <form onSubmit={handleSubmit} style={{ maxWidth: '450px', margin: '2rem auto', padding: '1rem' }}> <div style={{ marginBottom: '1rem' }}> <label>姓名:</label> <input type="text" name="name" value={formData.name} onChange={handleInputChange} required style={{ width: '100%', padding: '0.5rem', marginTop: '0.25rem' }} /> </div> <div style={{ marginBottom: '1rem' }}> <label>邮箱:</label> <input type="email" name="email" value={formData.email} onChange={handleInputChange} required style={{ width: '100%', padding: '0.5rem', marginTop: '0.25rem' }} /> </div> <div style={{ marginBottom: '1rem' }}> <label>地址:</label> <textarea name="address" value={formData.address} onChange={handleInputChange} required rows="4" style={{ width: '100%', padding: '0.5rem', marginTop: '0.25rem' }} /> </div> <button type="submit" style={{ padding: '0.5rem 1.5rem', cursor: 'pointer' }}> 提交信息 </button> {submitMsg && ( <p style={{ marginTop: '1rem', color: submitMsg.includes('成功') ? 'green' : 'red' }}> {submitMsg} </p> )} </form> ) } export default UserInfoForm
关键说明
- 状态反馈:通过
submitMsg给用户展示提交中、成功、失败等状态,提升体验。 - 跨域处理:后端已配置
cors中间件,避免React应用与后端端口不同导致的跨域错误。
内容的提问来源于stack exchange,提问作者Nightcrawler
相关产品推荐
相关产品推荐

