You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

通过Azure函数获取Graph API令牌发送邮件遇问题求助

问题分析与解决方案

为什么你的令牌和Graph Explorer的不一样?

这是正常现象,两者用的是完全不同的认证流程:

  • Graph Explorer使用用户委托认证流:基于登录用户的身份获取令牌,令牌包含用户身份信息,对应用户委托权限。
  • 你的代码使用客户端凭据流:以应用自身身份获取令牌,令牌无用户上下文,对应应用权限。
    两种令牌的受众、权限范围、结构均不同,内容自然不匹配,这不是问题,但发邮件失败的根源就在这里。

发送邮件返回Bad Request的排查与解决

1. 检查应用权限配置

客户端凭据流发送邮件需要配置应用级别的Mail.Send权限,而非用户委托权限:

  • 登录Azure门户,找到你的应用注册
  • 进入「API权限」页面,点击「添加权限」→ 选择Microsoft Graph → 「应用权限」
  • 搜索并添加Mail.Send权限,点击「授予管理员同意」(必须完成此步骤,权限才会生效)

2. 修改Graph API调用端点

用应用权限发送邮件时,不能使用/me/sendMail(/me代表当前登录用户,而客户端凭据流无用户上下文),必须指定具体用户ID或邮箱:

POST https://graph.microsoft.com/v1.0/users/{userPrincipalName}/sendMail

示例:https://graph.microsoft.com/v1.0/users/alice@yourcompany.com/sendMail

3. 完善令牌获取的错误处理

你的代码未检查令牌请求是否成功,若权限配置错误或参数有误,会拿到无效令牌导致后续请求失败。建议添加错误检查:

private static async Task<string> GetGraphAccessToken(ILogger log)
{
    var clientId = Environment.GetEnvironmentVariable("ClientId");
    var clientSecret = Environment.GetEnvironmentVariable("ClientSecret");
    var tenantId = Environment.GetEnvironmentVariable("TenantId");

    var tokenEndpoint = $"https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token";
    var body = new FormUrlEncodedContent(new[]
    {
        new KeyValuePair<string, string>("client_id", clientId),
        new KeyValuePair<string, string>("scope", "https://graph.microsoft.com/.default"),
        new KeyValuePair<string, string>("client_secret", clientSecret),
        new KeyValuePair<string, string>("grant_type", "client_credentials"),
    });

    HttpResponseMessage response = await httpClient.PostAsync(tokenEndpoint, body);
    string responseContent = await response.Content.ReadAsStringAsync();

    // 添加错误检查
    if (!response.IsSuccessStatusCode)
    {
        log.LogError($"令牌获取失败,状态码: {response.StatusCode},响应内容: {responseContent}");
        throw new InvalidOperationException($"无法获取Graph API令牌: {responseContent}");
    }

    var tokenResult = JsonConvert.DeserializeObject<dynamic>(responseContent);
    return tokenResult.access_token;
}

4. 检查邮件请求体格式

确保发送邮件的请求体符合Graph API要求,示例:

{
  "message": {
    "subject": "测试邮件",
    "body": {
      "contentType": "Text",
      "content": "这是客户端凭据流发送的测试邮件"
    },
    "toRecipients": [
      {
        "emailAddress": {
          "address": "recipient@yourcompany.com"
        }
      }
    ]
  },
  "saveToSentItems": true
}

总结

令牌差异是认证流程不同导致的正常现象,无需在意;发送邮件失败的核心问题是应用权限未正确配置和API端点使用错误,按照上述步骤修正即可解决问题。

内容的提问来源于stack exchange,提问作者Felix Rouleau

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 11:52:43