React+Express+Nodemailer配置OAuth2遇invalid_grant错误求助
解决Nodemailer OAuth2配置中的
invalid_grant错误 嘿,我刚帮不少踩过这个坑的新手解决过问题,invalid_grant是OAuth2认证里超常见的错误,咱们一步步拆解排查:
先揪出代码里的基础错误
SMTP主机填错了:你用的
host: 'mail.google.com'不对,Gmail的官方SMTP主机是smtp.gmail.com,这是最容易忽略的基础问题,先改这个!OAuth2参数的核心问题:
- Refresh Token失效或权限不足:
- 先确认你的refresh token是有效的——Gmail的refresh token如果长时间闲置、账号权限变更,或者你在Google Cloud Console里重置了客户端密钥,都会直接失效。
- 一定要确保你在获取refresh token时,申请的是
https://mail.google.com/这个全邮箱权限的scope,普通的发送权限不够用。 - 如果是测试应用,别忘了在Google Cloud Console的「OAuth同意屏幕」里把你的邮箱添加为测试用户,未发布的应用默认只允许测试用户授权。
- 别手动硬编码Access Token:你代码里手动填了
accessToken和expires,但access token有效期很短(一般1小时),过期后就会触发invalid_grant。其实Nodemailer可以自动用refresh token刷新获取新的access token,直接删掉这两个参数就好!
- Refresh Token失效或权限不足:
代码里的冗余配置:
sendMail里的auth字段完全多余,transporter已经配置了全局认证信息,删掉它。- 别忘了在transporter的
auth里加上user: 'mymail@gmail.com',这个字段是OAuth2认证必需的。
修正后的完整代码示例
async function main2() { const output = `Some output text...`; // 修正后的transporter配置 let transporter = nodemailer.createTransport({ host: 'smtp.gmail.com', // 正确的Gmail SMTP主机 port: 465, secure: true, auth: { type: 'OAuth2', user: 'mymail@gmail.com', // 必须添加你的邮箱地址 clientId: '你的clientID', clientSecret: '你的clientSecret', refreshToken: '你的有效refreshToken' // 移除手动设置的accessToken和expires,让Nodemailer自动处理 }, tls: { rejectUnauthorized: false } }); let info = await transporter.sendMail({ from: '"发送者名称" <mymail@gmail.com>', // 建议添加from字段,符合邮件规范 to: `${req.body.email}`, // 直接传邮箱字符串即可 subject: 'Hello', html: output }); console.log('Message sent: %s', info.messageId); console.log(`Message sent to: ${req.body.email}`); console.log('Preview URL: %s', nodemailer.getTestMessageUrl(info)); } main2().catch(console.error);
额外排查小贴士
- 如果你开启了账号2步验证,不用生成应用专用密码——OAuth2认证不需要这个,只要确保refresh token是正确获取的就行。
- 可以去Google Cloud Console的「API和服务」→「日志」里查看具体的授权错误细节,有时候会提示你权限不足或者token过期的具体原因。
内容的提问来源于stack exchange,提问作者Vladimir Bezdan
相关产品推荐
相关产品推荐

