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

使用Aspose Email DLL与Microsoft Graph Client API获取邮件时遇资源未找到错误

问题描述

在使用Aspose Email DLL结合Microsoft Graph Client API获取邮件时,出现以下错误:

Aspose.Email.AsposeBadServerResponceException: 'Server error Status: ResourceNotFound
Description: Resource could not be discovered.

请求详情:

  • 请求地址:GET https://graph.microsoft.com/v1.0/users/1234outlook.onmicrosoft.com/mailFolders
  • 请求头:Authorization: Bearer xxxxxx,Accept: application/json

相关代码实现如下:

代码1(Graph_API类)

using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Aspose.Email.Clients;
using Aspose.Email.Clients.Graph;
using Aspose.Email.Mapi;
using Azure.Identity;
using EASendMail;
using Microsoft.Graph;

namespace Code
{
    internal class Graph_API
    {
        private static string _clientId = ConfigurationManager.AppSettings["ClientId"];
        private static string _tenantId = ConfigurationManager.AppSettings["TenantId"];
        private static string _secretValue = ConfigurationManager.AppSettings["SecretValue"];

        static string _postString(string uri, string requestData)
        {
            HttpWebRequest httpRequest = WebRequest.Create(uri) as HttpWebRequest;
            httpRequest.Method = "POST";
            httpRequest.ContentType = "application/x-www-form-urlencoded";
            using (Stream requestStream = httpRequest.GetRequestStream())
            {
                byte[] requestBuffer = Encoding.UTF8.GetBytes(requestData);
                requestStream.Write(requestBuffer, 0, requestBuffer.Length);
                requestStream.Close();
            }
            try
            {
                HttpWebResponse httpResponse = httpRequest.GetResponse() as HttpWebResponse;
                var responseText = new StreamReader(httpResponse.GetResponseStream()).ReadToEnd();
                Console.WriteLine(responseText);
                return responseText;
            }
            catch (WebException ep)
            {
                if (ep.Status == WebExceptionStatus.ProtocolError)
                {
                    var responseText = new StreamReader(ep.Response.GetResponseStream()).ReadToEnd();
                    Console.WriteLine(responseText);
                }
                throw ep;
            }
        }

        public string GenerateToken()
        {
            string client_id = _clientId;
            string client_secret = _secretValue;
            string tenant = _tenantId;
            string requestData =
                string.Format("client_id={0}&client_secret={1}" +
                "&scope=https://graph.microsoft.com/.default&grant_type=client_credentials",
                client_id, client_secret);
            string tokenUri = string.Format("https://login.microsoftonline.com/{0}/oauth2/v2.0/token", tenant);
            string responseText = _postString(tokenUri, requestData);
            OAuthResponseParser parser = new OAuthResponseParser();
            parser.Load(responseText);
            var vv = parser.AccessToken;
            return vv;
        }

        public void Generatemail()
        {
            interface_class bb = new interface_class();
            IGraphClient client = GraphClient.GetClient(bb, _tenantId);
            client.Resource = (ResourceType)1;
            client.ResourceId = "1234outlook.onmicrosoft.com";
            MapiMessage mm = new MapiMessage();
            mm.Subject = "EMAILNET-39318 " + Guid.NewGuid().ToString();
            mm.Body = "EMAILNET-39318 REST API v1.0 - Create Message";
            mm.SetProperty(KnownPropertyList.DisplayTo, "1234outlook.onmicrosoft.com");
            mm.SetProperty(KnownPropertyList.SenderName, "1234outlook.onmicrosoft.com");
            mm.SetProperty(KnownPropertyList.SentRepresentingEmailAddress, "1234outlook.onmicrosoft.com");
            MapiMessage createdMessage = client.CreateMessage(Aspose.Email.Clients.Graph.KnownFolders.Inbox, mm);
        }

        public void FetchMail()
        {
            try
            {
                interface_class bb = new interface_class();
                using (IGraphClient client = GraphClient.GetClient(bb, _tenantId))
                {
                    client.Resource = (ResourceType)1;
                    client.ResourceId = "1234outlook.onmicrosoft.com";
                    FolderInfoCollection folderInfoCol1 = client.ListFolders();
                    FolderInfo inbox = null;
                    foreach (FolderInfo folderInfo in folderInfoCol1)
                    {
                        if (folderInfo.DisplayName.Equals("Inbox", StringComparison.InvariantCultureIgnoreCase))
                        {
                            inbox = folderInfo;
                            break;
                        }
                    }
                    MessageInfoCollection messageInfoCol = client.ListMessages(inbox.ItemId);
                    MessageInfo messageInfo = messageInfoCol[0];
                    MapiMessage message = client.FetchMessage(messageInfo.ItemId);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
}

代码2(interface_class类)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Aspose.Email.Clients;
using Aspose.Email.Clients.Graph;

namespace Code
{
    internal class interface_class : ITokenProvider
    {
        Graph_API obj = new Graph_API();
        DateTime expirationDate = DateTime.Today.AddDays(1);

        public void Dispose()
        {
            throw new NotImplementedException();
        }

        public OAuthToken GetAccessToken()
        {
            string token = obj.GenerateToken();
            return new OAuthToken(token, expirationDate);
        }

        public OAuthToken GetAccessToken(bool ignoreExistingToken)
        {
            throw new NotImplementedException();
        }
    }
}

错误原因排查

  • ResourceId格式无效:请求中的用户标识符1234outlook.onmicrosoft.com是不完整的邮箱地址,Graph API要求用户主体名称(UPN)必须是完整格式(如user@1234outlook.onmicrosoft.com),不完整的标识符会导致API无法定位资源。
  • ResourceType硬编码风险:代码中client.Resource = (ResourceType)1;使用数字硬编码,虽然ResourceType.User对应值为1,但硬编码易出错,且枚举值变更会引发问题。
  • 权限配置缺失:客户端凭据模式下,Azure AD应用需授予Mail.Read等应用权限并完成管理员同意,权限不足或未同意可能导致资源访问失败。
  • 循环依赖问题:interface_class实例化Graph_API,而Graph_API又创建interface_class,循环依赖可能导致token生成异常,间接引发资源访问错误。

解决方法

1. 修正ResourceId为完整邮箱地址

将代码中所有client.ResourceId = "1234outlook.onmicrosoft.com";修改为租户内存在的完整用户邮箱:

client.ResourceId = "valid-user@1234outlook.onmicrosoft.com";

2. 使用枚举常量替代硬编码

将client.Resource = (ResourceType)1;替换为明确的枚举值:

client.Resource = ResourceType.User;

3. 配置并确认Azure AD应用权限

  1. 登录Azure门户,找到目标应用注册。
  2. 进入API权限页面,添加Microsoft Graph的应用权限(如Mail.Read、Mail.Send)。
  3. 点击授予管理员同意,确保权限生效。

4. 解决循环依赖问题

修改interface_class,通过静态方法调用token生成逻辑,避免实例化Graph_API:

internal class interface_class : ITokenProvider
{
    DateTime expirationDate = DateTime.Today.AddDays(1);

    public void Dispose()
    {
        // 若无需释放资源,可留空或实现空逻辑
    }

    public OAuthToken GetAccessToken()
    {
        string token = Graph_API.GenerateTokenStatic();
        return new OAuthToken(token, expirationDate);
    }

    public OAuthToken GetAccessToken(bool ignoreExistingToken)
    {
        return GetAccessToken();
    }
}

同时将Graph_API中的GenerateToken改为静态方法:

public static string GenerateTokenStatic()
{
    string client_id = _clientId;
    string client_secret = _secretValue;
    string tenant = _tenantId;
    string requestData =
        string.Format("client_id={0}&client_secret={1}" +
        "&scope=https://graph.microsoft.com/.default&grant_type=client_credentials",
        client_id, client_secret);
    string tokenUri = string.Format("https://login.microsoftonline.com/{0}/oauth2/v2.0/token", tenant);
    string responseText = _postString(tokenUri, requestData);
    OAuthResponseParser parser = new OAuthResponseParser();
    parser.Load(responseText);
    var vv = parser.AccessToken;
    return vv;
}

5. 验证Token有效性

解析获取到的token,检查aud(受众)是否为https://graph.microsoft.com,roles字段是否包含所需权限(如Mail.Read),确保token有效且权限符合要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 19:51:53