Microsoft.Graph SDK作为用户的SendMail-400-不支持意外的异常或打开导航属性

时间:2018-09-19 12:02:59

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

我正在开发一个应用程序,当用户需要完成操作时,该应用程序需要向用户发送电子邮件通知和提醒。用户提交数据,然后应用程序通知其他用户以特定顺序执行操作(例如,用户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'."

更详细的信息:

  • 应用程序具有Microsoft Graph-> Send mail as any userRead all groupsRead all users' full profiles权限。
  • 调用GraphServiceClient.Client.Users["MyUPN"].SendMail(email, true).Request().PostAsync()会产生400个带有Unexpected exception returned from the service.的一般异常(下面的完整代码)
  • 看着请求,我发现它正在呼叫https://graph.windows.net:443/{{tenantId}}/users/{{MyUPN}}/microsoft.graph.sendMail?api-version=1.6,并尝试通过邮递员(使用有效令牌)进行相同的呼叫,这产生了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调用(例如获得用户的组或管理员)也可以正常工作-该错误仅出现在与电子邮件相关的调用中。


更新9/19/2018 AM

如果我使用证书而不是密钥->密码来生成令牌,则看起来可以正常使用电子邮件;然后调用Outlook API。不幸的是,这不能通过GraphServiceClient和Graph API起作用-它可以使用证书,也可以使用Outlook API基本URL,但是microsoft.graph.sendMail操作在Outlook API中只是sendMail

为了可维护性,我仍然希望所有这些都在Graph API下运行,因此我仍在寻找原始问题的答案。

2 个答案:

答案 0 :(得分:1)

在某个时候,我已经将客户端的BaseUrl设置为https://graph.windows.net:443/{{tenantId}},这可能是由于过去几年中品牌的变化(Microsoft Graph vs 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();

答案 1 :(得分:0)

根据您的描述,您想发送电子邮件,但收到400错误。

根据我的测试,我们可以按照以下步骤发送电子邮件。

第一步,我们应该得到一个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

步骤2,我们可以使用以下代码发送邮件:

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;
        }