Search code examples
c#azure-active-directorymicrosoft-graph-apioffice365console-application

How to send email with AAD Graph API with personal outlook account


Im trying to have a console application that will read my personal outlook account set as scheduled task, I have setup an AAD account with personal outlook account.

Here is the code that I have tried.

try
        {

            string tenantId = "xxxxxx";
            string clientId = "xxxxxxxx";
            string clientSecret = "xxxxxxxxx";
            string userId = "xxxxxxxxx";
            //The following scope is required to acquire the token
            string[] scopes = new string[] { "https://graph.microsoft.com/.default" };

            var options = new TokenCredentialOptions
            {
                AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
            };

            var clientSecretCredential = new ClientSecretCredential(
            tenantId, clientId, clientSecret, options);

            GraphServiceClient graphServiceClient = new GraphServiceClient(clientSecretCredential, scopes);


            var message = new Message
            {
                Subject = "Your subject here",
                Body = new ItemBody
                {
                    ContentType = BodyType.Html,
                    Content = "Email Content"
                },
                ToRecipients = new List<Recipient>()
            {
                new Recipient
                {
                    EmailAddress = new EmailAddress
                    {
                        Address = "[email protected]"
                    }
                }
            },
                CcRecipients = new List<Recipient>()
            {
                new Recipient
                {
                    EmailAddress = new EmailAddress
                    {
                        Address = "[email protected]"
                    }
                }
            }
            };

          
            Microsoft.Graph.Users.Item.SendMail
            .SendMailPostRequestBody requestbody = new()
            {
                Message = message,
                SaveToSentItems = false // or true, as you want
            };

            var user = await graphServiceClient.Users[userId].GetAsync();

                Console.WriteLine(user.Id + ": " + user.DisplayName + " <" + user.Mail + ">" + user.MailboxSettings);

            await graphServiceClient.Users[userId]
                .SendMail
                .PostAsync(requestbody);

            //await graphServiceClient.Users[userId]
            //      .SendMail(message, false)
            //      .Request()
            //      .PostAsync();

        }
        catch (ODataError odataError)
        {

            Console.WriteLine(odataError.Error.Code);
            Console.WriteLine(odataError.Error.Message);

        }

The call to API was successful as I have manage to retrieve the user.Id which is my userobjectId, and my user name, but the mail is null, the error was no ResourcesNotFound, Resource could not be discovered.

I have did some research, it seems I need to assign license of 356 office in AAD to this outlook account in order to have the mailbox and the sendMail will work. But I'm a little but overwhelming by the information that I found online and not sure which is the correct approach.

Any advice or guidance will be appreciated. Thanks.


Solution

  • I assigned O365 license to the user invited with personal Outlook account like below:

    enter image description here

    When I ran your code in my environment, I got same error even after assigning O365 license to the user:

    try
            {
    
                string tenantId = "xxxxxx";
                string clientId = "xxxxxxxx";
                string clientSecret = "xxxxxxxxx";
                string userId = "xxxxxxxxx";
                //The following scope is required to acquire the token
                string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
    
                var options = new TokenCredentialOptions
                {
                    AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
                };
    
                var clientSecretCredential = new ClientSecretCredential(
                tenantId, clientId, clientSecret, options);
    
                GraphServiceClient graphServiceClient = new GraphServiceClient(clientSecretCredential, scopes);
    
    
                var message = new Message
                {
                    Subject = "Your subject here",
                    Body = new ItemBody
                    {
                        ContentType = BodyType.Html,
                        Content = "Email Content"
                    },
                    ToRecipients = new List<Recipient>()
                {
                    new Recipient
                    {
                        EmailAddress = new EmailAddress
                        {
                            Address = "[email protected]"
                        }
                    }
                },
                    CcRecipients = new List<Recipient>()
                {
                    new Recipient
                    {
                        EmailAddress = new EmailAddress
                        {
                            Address = "[email protected]"
                        }
                    }
                }
                };
    
              
                Microsoft.Graph.Users.Item.SendMail
                .SendMailPostRequestBody requestbody = new()
                {
                    Message = message,
                    SaveToSentItems = false // or true, as you want
                };
    
                var user = await graphServiceClient.Users[userId].GetAsync();
    
                    Console.WriteLine(user.Id + ": " + user.DisplayName + " <" + user.Mail + ">" + user.MailboxSettings);
    
                await graphServiceClient.Users[userId]
                    .SendMail
                    .PostAsync(requestbody);
    
                //await graphServiceClient.Users[userId]
                //      .SendMail(message, false)
                //      .Request()
                //      .PostAsync();
    
            }
            catch (ODataError odataError)
            {
    
                Console.WriteLine(odataError.Error.Code);
                Console.WriteLine(odataError.Error.Message);
    
            }
    

    Response

    enter image description here

    As mentioned in this MS Document, personal Microsoft account requires Mail.Send Delegated permission that won't work with client credentials flow.

    Without user interaction, you cannot send mail with personal Outlook account using client credentials flow by adding Application permission.

    To resolve the issue, you must use delegated flow that involves user interaction like authorization code flow, interactive flow, etc....

    Alternatively, you can also sign into Graph Explorer with Outlook account that works with Delegated permissions and run below query to send mail:

    POST https://graph.microsoft.com/v1.0/me/sendMail
    Content-type: application/json
    
    {
      "message": {
        "subject": "Meet for lunch?",
        "body": {
          "contentType": "Text",
          "content": "The new cafeteria is open."
        },
        "toRecipients": [
          {
            "emailAddress": {
              "address": "[email protected]"
            }
          }
        ],
        "ccRecipients": [
          {
            "emailAddress": {
              "address": "[email protected]"
            }
          }
        ]
      },
      "saveToSentItems": "true"
    }
    

    Response:

    enter image description here

    When I checked the same in Outlook Sent Items, email sent successfully like below:

    enter image description here