Next.js API路由实现邮件发送时重复发信该如何解决?
问题根因
你遇到的发两封邮件的问题和是否抽离发信函数没有关系,核心原因是代码中存在多余的全局调用:你在定义完contactUsEmail函数后,直接写了一行contactUsEmail().catch(console.error);,这行代码会在Next.js加载该API路由文件时直接执行,没有传入任何参数,所以第一封参数全为undefined的邮件就是这行代码触发的。第二封参数正确的邮件才是用户请求接口时,控制器逻辑正常调用生成的。
修复方案
- 第一步:直接删除文件中
contactUsEmail().catch(console.error);这行多余的调用代码,即可解决重复发信的问题。 - 第二步:优化异步调用逻辑,你当前在控制器中调用
contactUsEmail时没有加await,会导致邮件还没发送完成就提前给前端返回响应,若发信过程出现报错前端也无法感知,建议补充await,同时增加异常捕获逻辑,避免服务端报错无处理。 - 第三步:关于发信函数是否抽离:如果后续其他业务逻辑也需要用到发信能力,建议将
contactUsEmail这类通用工具函数抽离到/lib或者/utils目录下统一维护,减少重复代码;如果只有当前这一个API路由用到发信功能,保留在当前文件中也完全没问题。
修复后的完整代码示例
const nodemailer = require("nodemailer"); import { validEmail } from '../../services'; const contactUsEmail = async (from, subject, tel, text, email) => { // 使用默认SMTP传输创建可复用的传输器对象 const transporter = nodemailer.createTransport({ host: 'smtp.ethereal.email', port: 587, auth: { user: 'myuser@example.com', pass: 'xxxxxxxxxxxx' } }); // 使用已定义的传输器对象发送邮件 let info = await transporter.sendMail({ from: `${email}`, // 发件人邮箱地址 to: "deven.medhurst@ethereal.email", // 收件人列表 subject: `${subject}`, // 邮件主题 text: `From: ${from}\nEmail: ${email}\nTel: ${tel}\n\n${text}`, // 纯文本正文 }); console.log("Message sent: %s", info.messageId); // 仅通过Ethereal账号发送邮件时可查看预览 console.log("Preview URL: %s", nodemailer.getTestMessageUrl(info)); return info; }; export default async function sendEmailToUs (req, res) { if(req.method !== 'POST'){ res.status(400).send('Bad request'); return } const email = req.body.email; if(!validEmail(email)){ res.status(400).send('Errors'); return } try { const from = req.body.from; const tel = req.body.tel === '' ? '0' : req.body.tel; const subject = req.body.subject; const text = req.body.text; await contactUsEmail(from, subject, tel, text, email); res.status(200).send('Sended'); } catch (err) { console.error('发信失败:', err); res.status(500).send('邮件发送失败'); } }
注:Next.js原生API路由不需要传入next参数,上述代码已移除该无用参数,同时删除了else块内重复声明的email变量。
内容的提问来源于stack exchange,提问作者Antonio De Luca
相关产品推荐
相关产品推荐

