You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Nodemailer本地运行正常但生产环境无法发送邮件问题排查

问题分析与解决方案

核心问题1:异步回调错误未被捕获且响应提前返回

你的代码里transporter.sendMail采用回调模式,但外层try/catch无法捕获回调内部的错误,而且不管邮件是否发送成功,直接返回了200响应。生产环境若未配置日志收集,你根本看不到回调里打印的错误,导致出现“无报错但邮件未发送”的假象。

解决方法:改用Nodemailer的Promise形式(支持await),让代码等待邮件发送完成后再返回响应,确保错误能被try/catch捕获。

核心问题2:敏感环境变量使用前端暴露前缀

NEXT_PUBLIC_开头的环境变量会被打包到前端代码中,邮箱密码用这个前缀会导致敏感信息泄露,且生产环境可能因变量暴露限制,后端无法正确读取认证信息(或你未配置非NEXT_PUBLIC_的变量)。

解决方法:将邮箱和密码的环境变量改为不带NEXT_PUBLIC_的前缀,比如GMAIL_EMAIL和GMAIL_PASSWORD,确保仅后端可读取。

核心问题3:Gmail SMTP生产环境认证限制

本地能发但生产环境失败,大概率是Gmail的生产环境限制:

  • 若账号开启两步验证,必须使用应用专用密码替代普通密码
  • 未开启两步验证的账号,需开启“不太安全的应用访问”(Google逐步淘汰该选项,更推荐应用专用密码)
  • 生产服务器IP可能被Google标记为可疑,需在Google账号安全中心检查登录记录,允许该IP访问

修改后的代码示例

try {
  const { name, email, message } = req.body;

  const transporter = nodemailer.createTransport({
    port: 465,
    host: "smtp.gmail.com",
    auth: {
      user: process.env.GMAIL_EMAIL, // 移除NEXT_PUBLIC_前缀
      pass: process.env.GMAIL_PASSWORD, // 移除NEXT_PUBLIC_前缀
    },
    secure: true,
  });

  const mailData = {
    from: process.env.GMAIL_EMAIL,
    to: process.env.RECEIVE_CONTACT_EMAIL, // 同样移除NEXT_PUBLIC_前缀
    subject: `Message From ${email}`,
    text: message,
  };

  // 用await等待邮件发送完成
  const info = await transporter.sendMail(mailData);
  console.log(info);
  res.status(200).json({ message: "Email sent successfully" });
} catch (error) {
  console.error("Email send error:", error);
  res.status(500).json({ message: "Failed to send email", error: error.message });
}

额外检查项

  • 确认生产环境环境变量已正确配置,且变量名与代码一致
  • 查看生产环境服务器日志,现在错误会被try/catch捕获并打印,可定位具体问题
  • 若使用Vercel、Netlify等平台,检查是否在环境变量设置中添加了非NEXT_PUBLIC_的变量,且部署时重新构建了应用

内容的提问来源于stack exchange,提问作者Mace

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 21:09:21