Nodemailer实现的联系表单为何会随机发送全为undefined的内容邮件?
问题触发原因
- 前端表单字段仅设置了
id属性,未设置name属性:原生表单提交或者未适配id取值的前端提交逻辑,无法正确携带字段值到服务端。 - 前端
required校验仅在用户通过浏览器正常访问页面提交时生效,爬虫、自动化脚本可以直接绕过前端页面,调用服务端POST /接口提交空参数,直接触发undefined问题。 - 服务端未做任何参数合法性校验,直接读取
req.body下的字段拼接邮件内容,字段不存在时返回的undefined会直接带入邮件。
修复方案
1. 补充前端表单的name属性
给所有输入字段补充和服务端读取逻辑对应的name属性,修改后HTML代码如下:
<form action="#" class="row contact-form"> <div class="col-lg-6 col-md-6 mb-3"><input type="text" placeholder="First Name" id="inputFirstName" name="nameFirst" class="shadow form-control form-control-lg" required></div> <div class="col-lg-6 col-md-6 mb-3"><input type="text" placeholder="Last Name" id="inputLastName" name="nameLast" class="shadow form-control form-control-lg" required></div> <div class="col-lg-12 mb-3"><input type="email" placeholder="Email Address" id="inputEmail" name="email" class="shadow form-control form-control-lg" required></div> <div class="col-lg-12 mb-3"> <textarea name="message" id="message" rows="8" class="shadow form-control form-control-lg" required></textarea> </div> <div class="text-center d-grid mt-1"> <button type="submit" class="btn btn-primary rounded-pill pt-3 pb-3"> Send Message <i class="fas fa-paper-plane"></i> </button> </div> </form>
同时建议将邮箱输入框的type从text改为email,增加前端原生格式校验。
2. 增加服务端参数校验
在调用Nodemailer发邮件前先校验所有必填参数是否存在,示例代码如下:
//Contact Form app.post("/", (req, res) => { // 新增参数校验逻辑 const { nameFirst, nameLast, email, message } = req.body; if (!nameFirst?.trim() || !nameLast?.trim() || !email?.trim() || !message?.trim()) { return res.status(400).send('参数不完整'); } // 邮箱格式校验可选补充 const emailReg = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailReg.test(email)) { return res.status(400).send('邮箱格式非法'); } //Nodemailer Transporter const smtpTransport = nodemailer.createTransport({ service: "gmail", auth: { type: "OAuth2", user: process.env.EMAIL, accessToken: accessToken, clientId: process.env.CLIENT_ID, clientSecret: process.env.CLIENT_SECRET, refreshToken: process.env.REFRESH_TOKEN, }, }); // Nodemailer options let mailOptions = { from: email, to: process.env.EMAIL, subject: `Message from ${email}`, text: `${nameFirst} ${nameLast} \n ${message}`, }; //Nodemailer Transporter/Sendmail smtpTransport.sendMail(mailOptions, (error, info) => { if (error) { res.send("error"); } else { res.send("success"); } }); });
3. 可选优化项
- 前端增加表单提交前的JS校验,双重拦截非法提交
- 接口增加CSRF校验,阻止跨站恶意请求
- 可添加简单的人机校验进一步拦截爬虫请求
内容的提问来源于stack exchange,提问作者MikeAye
相关产品推荐
相关产品推荐

