首页 > 解决方案 > Microsoft.Graph SDK 以用户身份发送邮件 - 400 - 不支持意外异常或打开导航属性

问题描述

我正在开发一个应用程序,该应用程序需要在用户完成操作时向他们发送电子邮件通知和提醒。用户提交数据,然后应用程序通知其他用户按特定顺序执行操作(即用户 1:任务 1,任务 1 完成后,用户 2:任务 2,等等) - 如果用户花费的时间过长执行他们的操作,系统会提醒他们,然后服从他们的经理(通过 Windows 服务或类似服务)。因此,我无法代表当前登录的用户发送消息 - 它需要能够自行发送消息。最好代表提交数据的用户发送,以便后续用户可以直接回复他们。

我正在使用Microsoft Graph 客户端库v1.10.0。运行我的代码会产生一个聚合异常,最终归结为代码 400, code "generalException", message"Unexpected exception returned from the service." 我使用 LinqPad 来查看 Graph 对象,并尝试在 Postman 中重现调用,这会产生 400 和消息"Open navigation properties are not supported on OpenTypes. Property name: 'microsoft.graph.sendmail'."

更详尽的细节:

完整代码:

String MyEmailAddress = "";
String MyUpn = "";
String TenantId = "";
String AppGuid = "";
String AppKey = "";

var sender = new Microsoft.Graph.Recipient()

{
    EmailAddress = new Microsoft.Graph.EmailAddress() { Address = MyEmailAddress }
};
var email = new Microsoft.Graph.Message
{
    Sender = sender,
    From = sender,
    Subject = "Test",
    Body = new Microsoft.Graph.ItemBody()
    {
        Content = "Test Body",
        ContentType = Microsoft.Graph.BodyType.Text
    }
};

email.ToRecipients = new List<Microsoft.Graph.Recipient>(){ sender };

email.BodyPreview = "Test Summary";


GraphSdk _Sdk = new GraphSdk(TenantId, AppGuid, AppKey);

// Where the error throws
await _Sdk.Client.Users[MyUpn].SendMail(email, true).Request().PostAsync();

作为测试,我也尝试await _Sdk.Client.Users[MyUpn].Messages.Request().Top(20).GetAsync();了同样的错误。其他 Graph 调用,例如获取用户的组或经理,工作正常 - 此错误仅出现在与电子邮件相关的调用中。


2018 年 9 月 19 日上午更新

如果我使用证书而不是密钥->密码来生成令牌,看起来我可以让电子邮件正常工作;并改为调用 Outlook API。不幸的是,这不适用于 GraphServiceClient 和 Graph API - 它可以使用证书,并使用 Outlook API 基本 URL,但该microsoft.graph.sendMail操作仅sendMail在 Outlook API 中进行。

为了可维护性,我仍然想让它在 Graph API 下工作,所以我仍在寻找原始问题的答案。

标签: c#microsoft-graph-apimicrosoft-graph-sdks

解决方案


在某些时候,我已将客户端的 BaseUrl 设置为https://graph.windows.net:443/{{tenantId}},这可能是由于过去几年的不同品牌(Microsoft Graph 与 Azure Graph)。根据 Microsoft.Graph 的当前建议,它应该是https://graph.microsoft.com/v1.0/- 这似乎也是默认值。

此外,我不得不切换到使用证书而不是 Azure 生成的密钥 -> 应用程序密码。

总工作代码是:

String AADTenantId = "";
String AppGuid = "";
String SenderAddress = "";
String SenderId = "";
String ToAddress = "";
String SubjectText = "";
String BodyText = "";
Byte[] Certificate = ...GetCertBytes...
String CertPassword = "";

var client = new GraphServiceClient(new DelegateAuthenticationProvider(
    async requestMessage =>
    {
        var authContext = new AuthenticationContext($"https://login.microsoftonline.com/{AADTenantId}");
        var cert = new X509Certificate2(Certificate, CertPassword);
        var clientAssertion = new ClientAssertionCertificate(AppGuid, cert);
        AuthenticationResult authresult = await authContext.AcquireTokenAsync("https://graph.microsoft.com", clientAssertion);

        // Append the access token to the request
        requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authresult.AccessToken);
    }));

var sender = new Recipient()
{
    EmailAddress = new EmailAddress() { Address = SenderAddress }
};
var email = new Message
{
    Sender = sender,
    From = sender,
    Subject = SubjectText,
    Body = new ItemBody()
    {
        Content = BodyText,
        ContentType = BodyType.Text
    },
    ToRecipients = new List<Recipient>() {
        new Recipient() { EmailAddress = new EmailAddress { Address = ToAddress }}
    }
};

await client.Users[SenderId].SendMail(email, true).Request().PostAsync();

推荐阅读