Microsoft.Graph SDK SendMail As User - 400 - 不支持意外异常或打开导航属性

Microsoft.Graph SDK SendMail As User - 400 - Unexpected Exception or Open navigation properties are not supported

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

我正在使用 Microsoft Graph Client Library v1.10.0。 运行 我的代码产生了一个聚合异常,最终归结为代码 400,代码 "generalException",消息 "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 base URL,但 microsoft.graph.sendMail 操作只是sendMail 在 Outlook API.

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

在某些时候,我将客户端的 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();

根据你的描述,你想发邮件但是收到400错误。

根据我的测试,我们可以使用以下步骤发送邮件。

第 1 步,我们应该得到一个 graphClient,这是一个经过身份验证的 HttpClient。

代码如下:

GraphServiceClient graphServiceClient = new GraphServiceClient(
            new DelegateAuthenticationProvider(
                async (requestMessage) =>
                {
                    string accessToken = await MsalAuthProvider.Instance.GetUserAccesstokenAsync();
                    requestMessage.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("bearer", accessToken);
                }));
        return graphServiceClient;

可以参考官方文档the simple code

step2,我们可以使用如下代码发送邮件:

public async Task<bool> SendAsync(EmailAddress toaddress)
    {
        var email = new Message
        {
            Body = new ItemBody
            {
                Content = "Test for sending eamil ",
                ContentType = BodyType.Text,
            },
            Subject = "Test for sending eamil",
            ToRecipients = new List<Recipient>
            {
                new Recipient
                {
                   EmailAddress = toaddress 
                }
            },
        };
        try
        {
            await _serviceClient.Me.SendMail(email).Request().PostAsync(); // the _serviceClient is the result in the step1.
            return true;
        }
        catch (Exception ex)
        {
            return false;
        }