Node.js调用SendGrid/Mail API发送邮件时出现Bad Request错误——原始请求缺少Header信息
先帮你梳理下几个核心问题,以及对应的修复步骤:
1. 先拿到SendGrid的具体错误信息(最关键)
你的错误日志只打印了error.message,但SendGrid的400错误会在error.response.body.errors里给出精准原因(比如发件人未验证、API key权限不足、邮件格式错误等)。先把catch里的日志改成:
.catch((error) => { console.error('SendGrid Error Details:', error.response.body.errors); console.log('RECEIVED ERROR') })
这一步能直接帮你定位到底是哪出问题,比如常见的The from address does not match a verified Sender Identity(发件人未验证),或者Permission denied, wrong API key(API key权限不对)。
2. 修复Promise的错误处理逻辑
你的sendMail函数里的Promise完全没做resolve和reject,导致外部的.then()和.catch()根本无法正确捕获结果。而且没必要自己封装Promise,因为sgMail.send()本身就返回Promise,直接用就行:
async function sendMail(mailData) { try { const msg = { to: mailData.to, from: mailData.from, subject: mailData.subject, text: mailData.text, html: `<div>${mailData.message}</div>` // 修复转义问题 } console.log("API KEY: " + SENDGRID_API_KEY); console.log(JSON.stringify(msg)); await sgMail.send(msg); // 直接await原生Promise console.log('Email sent'); return 'success'; } catch (error) { console.error('SendGrid Error:', error.response?.body?.errors || error.message); throw error; // 把错误抛出去,让外部的catch捕获 } }
3. 优化SendGrid的初始化逻辑
sgMail.setApiKey()只需要初始化一次,不用每次调用sendMail都设置。把它移到文件顶部,全局初始化:
const sgMail = require('@sendgrid/mail') const SENDGRID_API_KEY = process.env.SENDGRID_API_KEY; sgMail.setApiKey(SENDGRID_API_KEY); // 放在这里,只执行一次
4. 修复HTML内容的转义问题
你原来的html: '<div>'+req.body.message+'</div>'会把<和>转成实体字符,导致SendGrid发送的邮件里显示的是<div>你的消息</div>而不是真正的HTML。改成模板字符串直接写标签:
html: `<div>${req.body.message}</div>`
如果req.body.message里有用户输入的HTML,建议用sanitize-html这类库过滤避免XSS,纯文本的话直接用就行。
5. 排查SendGrid平台的配置问题
如果上面的代码改完还是报错,结合第一步拿到的错误信息,检查:
- 发件人邮箱是否验证:在SendGrid后台的Sender Identity里,必须验证你用的
dhook@fullonconsulting.com这个邮箱,否则会被拒绝。 - API Key的权限:创建API Key的时候,要勾选
Mail Send权限,不能只给只读权限。 - Vercel环境变量是否正确:确认Vercel的环境变量
SENDGRID_API_KEY已经正确设置,且部署时生效(可以打印前几位验证:console.log('API Key prefix:', SENDGRID_API_KEY?.slice(0, 5)))。
最后,把主函数改成async函数,await调用sendMail:
export default async function (req, res) { // 加async const mailData = { from: 'dhook@fullonconsulting.com', to: req.body.email, subject: 'Message to Full On Consulting', text: req.body.message, html: `<div>${req.body.message}</div>` } // 可以删掉原来的Mail.create相关代码,因为你没用到这个生成的body try { await sendMail(mailData); console.log('Email sent...'); res.status(200).json({ status: 'SUCCESS' }) } catch (error) { console.log('Error ... ', error); res.status(400).json({ status: 'FAILED', error: error.response?.body?.errors || error.message }); } }
内容的提问来源于stack exchange,提问作者Don

