Azure Function App通过Graph API发邮件本地正常云端失效
问题排查思路与解决方案
首先从你贴出的函数执行日志就能定位到最高概率的根因:整个函数从打印发送邮件日志到标记执行成功仅间隔1ms,根本没有等待Graph API请求返回就结束了进程,先从代码层排查修复:
- 你贴出的axios调用只展示了try块开头,既没有等待请求完成的后续逻辑,也没有异常捕获逻辑,大概率是Blob触发函数的主入口没有
await这个异步发信方法。非HTTP触发的Azure Function只要主函数执行完毕就会直接回收工作进程,挂起的异步请求会被直接掐断,不会等待响应返回,所以你会看到函数显示执行成功,但实际Graph请求根本没完成发送流程。
参考修正代码:// 函数入口必须标记为async,所有异步操作必须显式await module.exports = async function(context, myBlob) { context.log("BEGIN: Sending email for failed referral via Graph API."); context.log(`Blob Name: ${context.bindingData.blobTrigger}`); // 省略获取access_token、构造email参数的逻辑 try { const response = await axios({ url: `${GRAPH_ENDPOINT}/v1.0/users/${FROM_ADDRESS}/sendMail`, method: "POST", headers: { "Authorization": `Bearer ${access_token}`, "Content-Type": "application/json", }, // 注意:axios会自动将JS对象序列化为JSON,无需手动调用JSON.stringify,重复序列化反而会导致请求格式错误 data: email, }); // 必须打印响应状态做校验:sendMail接口成功的返回状态码是202 Accepted,不是200 context.log(`Graph API call success, status code: ${response.status}`); } catch (err) { // 必须添加catch块打印完整错误,禁止吞掉异常静默返回成功 const errMsg = err.response ? JSON.stringify(err.response.data) : err.message; context.log.error(`Send mail failed: ${errMsg}`); // 抛出错误让函数标记为执行失败,触发平台重试逻辑 throw err; } }; - 你代码中
data: JSON.stringify(email)属于冗余操作,axios传入对象类型的data参数时会自动做JSON序列化,手动重复序列化会导致请求体格式不符合Graph API要求,部分场景下会被服务端直接丢弃请求且不返回明确错误。
如果修复代码异步问题后仍然无法收到邮件,按以下优先级排查配置问题:
- 校验访问令牌有效性
你提到Application Insights中能看到令牌请求和Graph调用记录,但需要确认令牌本身是合法的:- 解码拿到的access_token,确认
aud声明值为https://graph.microsoft.com,不是其他服务的资源端点 - 确认
roles声明中包含Mail.Send应用权限,不要误拿到委派权限的令牌 - 确认令牌中的
appid和你授予Mail.Send权限、做过管理员同意的AAD应用ID完全一致
- 解码拿到的access_token,确认
- 排查VNET路由拦截问题
你开启了route-all将所有流量路由到内部网络,这里存在明显的配置误区:- 调用Microsoft Graph发信走的是443端口的HTTPS协议,根本不经过25、587的SMTP端口,你之前放通SMTP端口的操作对Graph调用完全无效
- 检查内部代理、防火墙、NSG规则是否放通了Function到Graph API端点的443出站流量,确认你放通的M365网段包含Graph服务的地址段,不要只放通Exchange SMTP相关网段
- 可以在函数中加一段测试逻辑,直接请求Graph的元数据端点,验证到Graph服务的网络连通性
- 校验Exchange Online侧配置
- 确认
FROM_ADDRESS对应的是真实存在、未被禁用的Exchange Online邮箱,没有配置传输规则静默删除应用身份发送的邮件 - 应用权限调用Graph发信不需要将邮箱加入特殊邮件组,只要AAD应用完成管理员授权即可调用,你配置的邮件组权限属于冗余操作,检查是否是该邮件组关联的传输规则反而拦截了邮件
- 到Exchange管理中心查询发件邮箱的完整邮件跟踪日志,不要只查收件侧日志,确认邮件是否被反垃圾邮件策略、传输规则拦截
- 确认
- 快速验证方法
临时关闭Function的VNET集成,让出站流量走Azure默认公网出口测试发信,如果关闭VNET后能正常发信,可100%确认问题出在VNET路由、防火墙或NSG的443端口拦截配置上。
内容的提问来源于stack exchange,提问作者tmarsh1
相关产品推荐
相关产品推荐

