Nodemailer发件报错No recipients defined及收件地址无效问题求助
问题原因
- 初始版本
No recipients defined报错原因:
你封装的getAdminEmail函数采用回调式写法,没有对外层返回任何值,同时你没有处理异步逻辑,调用时直接同步取值拿到的是undefined,导致管理员邮件的收件人为空。 - 修改后RFC-5321规范报错原因:
SuperAdminListModel.find({})返回的是符合条件的文档数组,你没有取数组的第一个元素,直接把整个数组当邮箱地址传入,类型不匹配。- 你拿到的管理员邮箱字符串前后被意外添加了单引号,RFC 5321标准规定纯邮箱地址不允许包裹多余的引号符号,因此被 Gmail 接口拒绝。
- 隐藏问题:你在
dispatch_emails函数内两次调用res.send(),同一个HTTP请求只能返回一次响应,后续会触发请求已发送的报错。 - 配置错误:你写的
secureConnection: 'false'是无效配置,Nodemailer对应配置字段为secure,且接受布尔值而非字符串。
修复方案
- 修正管理员邮箱获取逻辑:
// 把RegisterAdminUser内获取邮箱的代码替换为如下 const superAdminRes = await SuperAdminListModel.findOne({}); if (!superAdminRes?.superadmin_email) { return res.status(500).json({ error: '系统未配置管理员邮箱' }); } // 清除邮箱前后多余的引号和空白字符 const adminEmail = superAdminRes.superadmin_email.replace(/['"\s]+/g, '');
- 重写
dispatch_emails函数,修复配置错误和重复返回的问题:
const dispatch_emails = async (admin_email, user_email, fullname, company_name) =>{ const transporter = nodemailer.createTransport({ service: 'gmail', host: 'smtp.gmail.com', port: 587, auth: { user: '你的发件Gmail地址', pass: '你的Gmail应用密码' }, secure: false, tls: { rejectUnauthorized: false } }); const userMailOptions = { from: '你的发件Gmail地址', to: user_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 adminMailOptions = { from: '你的发件Gmail地址', to: admin_email, subject: `Account Registration for ${user_email}, Fullname : ${fullname} (${company_name})`, html: `<h3>Attention Admin</h3> <p>A new User has registered with the following Information: </br> <strong>Username : ${user_email}</strong></br> <strong>Company Name : ${company_name}</strong></br> <strong>Registration Date: ${(new Date()).toLocaleString()}</strong></br> Regards</br>Online Services.</p>` }; // 并行发送两封邮件统一返回结果 return Promise.all([ transporter.sendMail(userMailOptions), transporter.sendMail(adminMailOptions) ]) }
- 修正注册逻辑中的响应返回位置,添加邮件发送错误处理:
// 把bcrypt.hash的回调替换为如下 bcrypt.hash(req.body.password, salt, async (err, hash) => { if (err) { return res.status(500).json({ error: err }); } newUser.password = hash; await newUser.save(); try { // 传入清理后的管理员邮箱 await dispatch_emails(adminEmail, newUser.email, newUser.fullname, newUser.company_name); const payload = { _id: newUser._id, email: req.body.email, }; const token = jwt.sign(payload, services.JWT_KEY, { expiresIn: 31556926, }); return res.status(200).json({ message: "User registered Successfully", token: token, user: newUser, }); } catch (mailError) { console.error('邮件发送失败:', mailError); // 可根据业务调整,也可返回注册成功提示邮件发送异常 return res.status(500).json({ error: '邮件发送失败' }); } }) // 删掉原来bcrypt.genSalt回调外层的res.return,避免提前返回
内容的提问来源于stack exchange,提问作者Keros
相关产品推荐
相关产品推荐

