如何使用SendGrid发送认证邮件?代码运行返回Forbidden错误如何解决?

问题核心原因与解决方案
SendGrid返回403 Forbidden属于权限/配置类错误,按以下优先级排查即可解决:
- API密钥配置错误
首先确认process.env.MAIL_KEY是否正确读取到了SendGrid后台生成的完整权限API密钥,注意密钥生成后只会显示一次,丢失后需要重新生成,且密钥必须开通Mail Send权限,权限受限的密钥会直接返回403。 - 发件人身份未验证
SendGrid要求发件人邮箱(即你代码中process.env.EMAIL_FROM对应的地址)必须先在SendGrid后台完成单 sender 验证,或者完成整个发件域名的验证,未验证的发件人发信会直接被拦截返回403。 - 账户状态异常
检查你的SendGrid账户状态,新账户未完成身份验证、发信额度用完、被平台判定违规冻结发信权限,都会触发403错误。 - 环境变量加载异常
临时增加一行打印代码console.log(process.env.MAIL_KEY, process.env.EMAIL_FROM),确认运行环境的环境变量被正确读取,避免配置项为空或者读取错误。
你代码存在的额外逻辑问题
你当前的User.findOne是异步查询,查询回调还没返回时,下方的发信逻辑就已经执行,哪怕用户邮箱已经被注册,邮件还是会被发送,需要调整逻辑把发信流程放到查询回调内部,确认无重复用户后再执行发信,调整后的参考代码如下:
const sgMail = require('@sendgrid/mail') sgMail.setApiKey(process.env.MAIL_KEY) const { name, email, password } = req.body; console.log(name, email, password) const errors = validationResult(req); if (!errors.isEmpty()) { const firstError = errors.array().map(error => error.msg)[0]; return res.status(422).json({ errors: firstError }); } User.findOne({ email }).exec(async (err, user) => { if (err) { return res.status(500).json({errors: '用户查询失败'}) } if (user) { return res.status(400).json({ errors: 'Email is taken' }); } // 确认无重复用户后再执行发信逻辑 const token = jwt.sign( { name, email, password }, process.env.JWT_ACCOUNT_ACTIVATION, { expiresIn: '5m' } ); const emailData = { from: process.env.EMAIL_FROM, to: email, subject: 'Account activation link', html: ` <h1>Please use the following to activate your account</h1> <p>${process.env.CLIENT_URL}/users/activate/${token}</p> <hr /> <p>This email may contain sensitive information</p> <p>${process.env.CLIENT_URL}</p> ` }; try { await sgMail.send(emailData) return res.json({ message: `Email has been sent to ${email}` }); } catch(err) { console.log(err) return res.status(400).json({ success: false, errors: errorHandler(err) }); } });
内容的提问来源于stack exchange,提问作者Afolabi Opeyemi
相关产品推荐
相关产品推荐

