使用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应用权限
- 登录Azure门户,找到目标应用注册。
- 进入API权限页面,添加Microsoft Graph的应用权限(如
Mail.Read、Mail.Send)。 - 点击授予管理员同意,确保权限生效。
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
相关产品推荐
相关产品推荐

