Mongoose ValidationError报错:admin_email类型转换失败 无法调用Nodemailer发信
报错原因
核心错误触发点来自Mongoose字段类型校验失败:
SuperAdminListModel.find({})返回的是符合查询条件的文档数组,你直接将整个数组赋值给了admin_email字段,而AdminUserListSchema中admin_email定义的是String类型,类型不匹配直接触发校验失败- 额外存在两处代码逻辑问题:
- 你将超管查询结果赋值给了
superadmin_email变量,但调用dispatch_emails方法时传的是未定义的admin_email变量,会触发引用错误 - 新建用户时先执行了一次save,修改密码后又执行了一次save,逻辑冗余;且
dispatch_emails方法中使用了res.send,和外层接口的响应逻辑冲突,会触发重复返回响应报错;邮件发送回调中直接抛错没有捕获,会触发未处理的Promise rejection警告。
- 你将超管查询结果赋值给了
解决方法
1. 修正超管邮箱查询和取值逻辑
如果只需要取第一个超管的邮箱,改用findOne查询直接拿到单个文档,再取出邮箱字段:
// 替换原有的超管查询逻辑 const superAdmin = await SuperAdminListModel.findOne({}); if (!superAdmin) { return res.status(500).json({ errors: { system: "未查询到超管账号,无法发送通知邮件" } }); } const admin_email = superAdmin.superadmin_email;
2. 优化注册逻辑,避免冗余操作和错误引用
提前完成密码哈希,仅做一次用户保存,修正变量引用:
export const RegisterAdminUser = async (req, res) => { try { // 超管查询逻辑 const superAdmin = await SuperAdminListModel.findOne({}); if (!superAdmin) { return res.status(500).json({ errors: { system: "未查询到超管账号" } }); } const admin_email = superAdmin.superadmin_email; // 校验用户是否存在 const existingUser = await AdminListModel.findOne({ email: req.body.email }); if (existingUser) { return res.status(409).json({ errors: { email: "用户已存在" } }); } // 提前做密码哈希,仅做一次用户保存 const hashPassword = await bcrypt.hash(req.body.password, 10); const newUser = new AdminListModel({ admin_email : admin_email, company_name: req.body.company_name, fullname: req.body.fullname, email: req.body.email, phone_number: req.body.phone_number, timezone: req.body.timezone, password: hashPassword }); await newUser.save(); const token = jwt.sign({ _id: newUser._id, email: newUser.email }, services.JWT_KEY, { expiresIn: 31556926, }); // 触发邮件发送 dispatch_emails(admin_email, newUser.email, newUser.fullname, newUser.company_name); return res.status(200).json({ message: "用户注册成功", token: token, user: newUser, }); } catch (err) { return res.status(500).json({ error: err.message }); } };
3. 修正邮件发送逻辑,避免冲突和未捕获错误
去掉dispatch_emails中的响应返回,添加错误捕获:
const dispatch_emails =(admin_email, email, fullname, company_name) =>{ const transporter = nodemailer.createTransport({ service: 'gmail', host: 'smtp.gmail.com', port: 587, auth: { user: '*************@gmail.com', pass: '************' }, secure: false, tls: { ciphers: 'SSLv3', rejectUnauthorized: false } }); const mailOptions = { from: '*********@gmail.com', to: email, subject: 'Account Registration Successful!', html: `<h3>Attention,${fullname} , </h3><p><h3>Your Account has been successfully setup.</h3></p><p> Please allow a maximum of 24 - 48 Hours for Review and succesful setup and approval of your online account.</p></br>Regards,</br> Online Services.` }; const AdminNotifyEmail = { from: '************@gmail.com', to: admin_email, subject: `Account Registration for ${email}, with Fullname : ${fullname} (${company_name})`, html: `<h3>Attention Admin , </h3><p>A new User has registered his Access with the following Information: </br> <strong>Username : ${email}</strong></br><strong>Company Name : ${company_name}</strong></br><strong>Date of Registration: ${(new Date()).toLocaleString()}</strong></br>Regards</br>Online Services.</p>` }; // 添加错误日志,不要直接抛错 transporter.sendMail(mailOptions, function (error, info) { if (error) console.error('用户注册邮件发送失败:', error); }) transporter.sendMail(AdminNotifyEmail, function (error, info) { if (error) console.error('管理员通知邮件发送失败:', error); }) }
内容的提问来源于stack exchange,提问作者Keros
相关产品推荐
相关产品推荐

