Express.js + Nodemailer在Vercel生产环境无法发送邮件求助
开发环境正常、Vercel生产环境失效的Nodemailer问题排查与解决
以下针对你遇到的问题,结合给出的代码逐一分析可能的原因及解决方案:
1. 环境变量与配置文件未同步
你的代码混合了process.env环境变量和本地gmail.js配置文件,Vercel生产环境无法读取本地配置文件,且环境变量可能未正确部署:
- 把
gmail.js中的clientId、clientSecret、refreshToken全部迁移到Vercel项目的「环境变量」中(项目设置→Environment Variables),代码中直接通过process.env读取:auth: { type: "OAuth2", user: process.env.MAIL_USERNAME, pass: process.env.APP_PASSWORD, clientId: process.env.GMAIL_CLIENT_ID, clientSecret: process.env.GMAIL_CLIENT_SECRET, refreshToken: process.env.GMAIL_REFRESH_TOKEN, // 建议移除accessToken,让Nodemailer自动通过refreshToken刷新,避免令牌过期 }, - 修改环境变量后重新部署Vercel项目,确保变量生效。
2. 邮件模板文件路径错误
本地开发的目录结构和Vercel部署后的结构不一致,path.join(__dirname, '../../src/templates/email/${data.template}')可能找不到模板文件,导致fs.readFileSync抛出错误:
- 改用异步读取并添加错误捕获,避免同步读取阻塞流程且无错误提示:
// 替换原同步读取代码 fs.readFile(filePath, "utf8", (err, fileTemplate) => { if (err) { return reject(new Error(`读取邮件模板失败: ${err.message}`)); } const mailOptions = { from: '"Event Organizing" <arkawebdev1@gmail.com>', to: data.to, subject: data.subject, html: mustache.render(fileTemplate, { ...data }), }; transporter.sendMail(mailOptions, (error, result) => { error ? reject(error) : resolve(result); }); }); - 同时检查Vercel部署后的文件结构,确保模板文件被正确打包到生产环境(可在Vercel部署日志中查看文件目录)。
3. Nodemailer配置参数错误
代码中secure字段设置为字符串"true",但Nodemailer要求该字段为布尔值,这会导致SMTP连接异常:
- 修改为布尔值:
secure: true, // 去掉引号
4. Promise未返回导致异步流程中断
sendMail方法创建了Promise但未返回,调用该方法时无法正确处理异步逻辑,在Vercel Serverless函数环境中会导致函数提前结束:
- 添加
return返回Promise:sendMail: (data) => { // 加上return return new Promise((resolve, reject) => { // 原代码逻辑 }); },
5. Gmail OAuth2权限限制
Gmail的OAuth2授权可能限制了生产环境的访问:
- 登录Google Cloud Console,检查OAuth2客户端的「重定向URI」是否包含Vercel生产域名(若涉及授权流程)。
- 若使用Gmail App Password,确保账号已开启2FA,且App Password是正确生成的(仅开启2FA后才能创建App Password)。
- 确认refreshToken有效,可尝试重新生成refreshToken。
内容的提问来源于stack exchange,提问作者danny kerr
相关产品推荐
相关产品推荐

