React应用调用Microsoft Graph API发邮件遇401及租户GUID不存在错误
我正在开发一个React应用,尝试通过OAuth2认证使用Microsoft Graph API发送邮件,但调用时出现401 Unauthorized错误。操作流程如下:
- 用户使用MSAL(Microsoft Authentication Library)登录,并授予
Mail.Send和User.Read权限; - 通过
msalInstance.acquireTokenPopup()获取访问令牌; - 使用
axios.post()调用Microsoft Graph API,将访问令牌放入Authorization请求头发送邮件。
遇到的错误信息
POST https://graph.microsoft.com/v1.0/me/sendMail 401 (Unauthorized) Error message: Error during login or sending email: AxiosError {message: 'Request failed with status code 401', name: 'AxiosError', code: 'ERR_BAD_REQUEST', ...} Response error: {error: {code: "OrganizationFromTenantGuidNotFound", message: "The tenant for tenant guid 'd600ee99-eb85-4281-a0c5-18cc87425a9e' does not exist."}}
已尝试的操作
- 反复检查
Mail.Send和User.Read权限(附API权限截图); - 确认使用正确的Microsoft租户和订阅;
- 确保账户已登录且令牌获取正常;
- 查看邮件未收到相关问题截图。
代码实现
export const msalConfig = { auth: { clientId: "my-client-id", authority: "https://login.microsoftonline.com/<tenand-id>", redirectUri: "http://localhost:3000", // Adjust as per your app }, }; import React from "react"; import { PublicClientApplication } from "@azure/msal-browser"; import { msalConfig } from "./msalConfig"; import axios from "axios"; const GraphApiTest = () => { const loginAndSendEmail = async () => { const msalInstance = new PublicClientApplication(msalConfig); await msalInstance.initialize(); try { // Login and acquire access token const loginResponse = await msalInstance.loginPopup({ scopes: ["Mail.Send", "User.Read"], }); console.log("Login successful:", loginResponse); const account = msalInstance.getAllAccounts()[0]; const tokenResponse = await msalInstance.acquireTokenPopup({ account, scopes: ["Mail.Send", "User.Read"], }); const accessToken = tokenResponse.accessToken; console.log("Access Token acquired:", accessToken); const emailPayload = { message: { subject: "Test Email from React App", body: { contentType: "Text", content: "This is a test email sent from my React app via Microsoft Graph API.", }, toRecipients: [ { emailAddress: { address: "gulzarjavaria2@gmail.com", }, }, ], }, saveToSentItems: "true", }; const response = await axios.post( "https://graph.microsoft.com/v1.0/me/sendMail", emailPayload, { headers: { Authorization: `Bearer ${accessToken}`, "Content-Type": "application/json", }, } ); console.log("Email sent successfully:", response.data); } catch (error) { console.error("Error during login or sending email:", error); if (error.response) { console.error("Response error:", error.response.data); } } }; return ( <div> <button onClick={loginAndSendEmail}>Send Email via Outlook</button> </div> ); }; export default GraphApiTest;
疑问
能否解释为何会出现"OrganizationFromTenantGuidNotFound"和"401 Unauthorized"错误?错误提示租户ID存在问题,我该采取哪些步骤解决此问题并成功通过Microsoft Graph API发送邮件?
解答
错误原因分析
OrganizationFromTenantGuidNotFound:该错误直接指向配置的租户ID无效或不存在,可能的触发场景包括:
msalConfig中authority字段的<tenand-id>存在拼写错误(代码中写的是tenand-id而非正确的tenant-id,属于明显笔误);- 配置的租户ID与登录用户所属的租户不匹配;
- 该租户已被删除或未在Azure AD中完成注册。
401 Unauthorized:这是租户ID错误引发的连锁问题——基于无效租户生成的访问令牌无法被Graph API识别,因此请求被拒绝。
解决步骤
1. 修正租户ID的拼写与正确性
- 登录Azure Portal,进入Azure Active Directory,在概述页面复制正确的租户ID;
- 更新
msalConfig中的authority字段,替换为正确的租户ID,同时修正字段名笔误:authority: "https://login.microsoftonline.com/你的实际租户ID",
2. 验证用户与租户的关联关系
- 确认你使用的
.onmicrosoft.com结尾的用户确实属于上述Azure AD租户; - 可在Azure AD的用户列表中搜索该用户,检查其所属租户是否与配置的租户ID一致。
3. 确认应用注册的权限配置
- 登录Azure Portal,进入你的应用注册页面,确保:
- API权限中已添加
Mail.Send和User.Read的委托权限; - 权限状态为已授予管理员同意(租户内用户发送邮件需管理员提前同意权限,否则普通用户无法获取有效令牌)。
- API权限中已添加
4. 优化MSAL实例初始化逻辑
当前代码每次点击按钮都会创建新的PublicClientApplication实例,易导致状态不一致。建议全局初始化MSAL实例:
// 在组件外部全局初始化MSAL实例 const msalInstance = new PublicClientApplication(msalConfig); msalInstance.initialize(); const GraphApiTest = () => { const loginAndSendEmail = async () => { try { // 后续逻辑直接使用全局msalInstance,无需重复创建 // ... } catch (error) { // 错误处理 } }; // ... };
5. 验证访问令牌有效性
获取令牌后,使用JWT解析工具检查:
tid字段是否为正确的租户ID;scp字段是否包含Mail.Send和User.Read权限;- 令牌是否未过期(
exp字段为过期时间戳)。
6. 修正请求体格式
Graph API要求saveToSentItems为布尔类型,将代码中的字符串"true"改为布尔值true:
saveToSentItems: true,
验证测试
完成上述修正后重新运行应用:
- 点击登录按钮,确认登录流程正常,获取到包含正确租户ID和权限的访问令牌;
- 调用发送邮件接口,检查是否返回202 Accepted状态码,同时确认收件人收到邮件。
内容的提问来源于stack exchange,提问作者Javaria Gulzar
相关产品推荐
相关产品推荐

