4

I have created a small Console App to send email using Microsoft Graph API.

Tutorial Used

https://learn.microsoft.com/en-us/graph/api/user-sendmail?view=graph-rest-1.0&tabs=csharp

Error

ServiceException: Code: NoPermissionsInAccessToken Message: The token contains no permissions, or permissions can not be understood.

Code

using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using Microsoft.Graph;
using Microsoft.Graph.Auth;
using Microsoft.Graph.Extensions;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Identity.Client;

namespace GraphAPI
 {
    class Program
    {

    static void Main(string[] args)
    {
        // Azure AD APP
        string clientId = "<client Key Here>";
        string tenantID = "<tenant key here>";
        string clientSecret = "<client secret here>";

        Task<GraphServiceClient> callTask = Task.Run(() => SendEmail(clientId, tenantID, clientSecret));
        // Wait for it to finish
        callTask.Wait();
        // Get the result
        var astr = callTask;
    }

    public static async Task<GraphServiceClient> SendEmail(string clientId, string tenantID, string clientSecret)
    {

        IConfidentialClientApplication confidentialClientApplication = ConfidentialClientApplicationBuilder
            .Create(clientId)
            .WithTenantId(tenantID)
            .WithClientSecret(clientSecret)
            .Build();

        ClientCredentialProvider authProvider = new ClientCredentialProvider(confidentialClientApplication);       

        GraphServiceClient graphClient = new GraphServiceClient(authProvider);

        var message = new Message
        {
            Subject = "Meet for lunch?",
            Body = new ItemBody
            {
                ContentType = BodyType.Text,
                Content = "The new cafeteria is open."
            },
            ToRecipients = new List<Recipient>()
            {
                new Recipient
                {
                    EmailAddress = new EmailAddress
                    {
                        Address = "myToEmail@gmail.com"
                    }
                }
            },
            CcRecipients = new List<Recipient>()
            {
                new Recipient
                {
                    EmailAddress = new EmailAddress
                    {
                        Address = "myCCEmail@gmail.com"
                    }
                }
            }
        };

        var saveToSentItems = true;

          await graphClient.Me
            .SendMail(message, saveToSentItems)
            .Request()
            .PostAsync();

        return graphClient;

    }

}

}

Here is the Screenshot of permissions I gave to the AD APP

enter image description here

So, Can anybody guide me where I am going wrong

Tushar Narang
  • 1,997
  • 3
  • 21
  • 49
  • 1
    Did you explicitly grant the permissions? "Click the Grant permissions button to actually grant the permissions to the application. An admin has to grant these permissions, you can do so by clicking the button. Any changes you make in the permissions you enable for the application require you to explicitly grant the permissions by clicking the button." – rickvdbosch Aug 08 '19 at 11:41
  • 1
    No, that is disabled for me, I fail to understand, Why I cant use the delegated one, to send mail as my own user. Why do I need to use application level permission. – Tushar Narang Aug 09 '19 at 03:27
  • Because, you are using the ClientCredentialsProvider, which doesn't allow for user delegation flow. – Adam Hardy Jul 06 '21 at 05:44

1 Answers1

2

Based on your screenshot, you haven't grant admin consent to Mail.Send application permission.

Click the grant admin consent button under api permissions.

enter image description here

Update:

Interactive provider:

            string[] scopes = { "Mail.Send" };
            string clientId = "";
            IPublicClientApplication publicClientApplication = PublicClientApplicationBuilder
            .Create(clientId)
            .WithRedirectUri("https://localhost")
            .Build();

            InteractiveAuthenticationProvider authProvider = new InteractiveAuthenticationProvider(publicClientApplication, scopes);

            GraphServiceClient graphClient = new GraphServiceClient(authProvider);
Tony Ju
  • 14,891
  • 3
  • 17
  • 31
  • Thanks Tony, That Button is disabled for me and getting permission on application level wont be easy. Can I not simply use the delegated permission. Coz according to documentation provided by Microsoft I need only one of the permission. – Tushar Narang Aug 09 '19 at 03:29
  • @TusharNarang Yes, you can. But the way you got the access token is client credentials flow which need application permission. To use delegated permission, you need to access the graph with user authentication. Refer to https://learn.microsoft.com/en-us/graph/sdks/choose-authentication-providers?tabs=CS – Tony Ju Aug 09 '19 at 03:32
  • I used the interactive provider and got following error ServiceException: Code: ErrorAccessDenied Message: Access to OData is disabled. Inner error – Tushar Narang Aug 09 '19 at 04:14
  • @TusharNarang Check the updated answer, is your code the same as mine? – Tony Ju Aug 09 '19 at 08:18
  • Hi Tony, Mine is a console so I dont understand why i need to redirect it to localhost. However u did try with interactive but i got an exception Is there a way to authenticate with admin consent sen mail permission. – Tushar Narang Aug 09 '19 at 09:08
  • @TusharNarang Yes, you can refer to the steps here. https://learn.microsoft.com/en-us/azure/active-directory/manage-apps/configure-user-consent#grant-admin-consent-when-registering-an-app-in-the-azure-portal – Tony Ju Aug 09 '19 at 09:26
  • @TusharNarang To use delegated Mail.Send permission, you will not be asked for admin consent. When you login with your account, you will only be asked for user consent. – Tony Ju Aug 09 '19 at 09:37
  • @TusharNarang The value of redirect url does't matter, just keep it is the same as the value in azure portal. You can also use the default one if you don't specify it in the code. But you need to specify it in azure portal with `urn:ietf:wg:oauth:2.0:oob` – Tony Ju Aug 09 '19 at 09:57
  • Ok I Defined the same and used interactive one as well. I got this error ServiceException: Code: ErrorAccessDenied Message: Access to OData is disabled. – Tushar Narang Aug 09 '19 at 10:49
  • Also I used ur code and got this messafe after signing in AADSTS50011: The reply url specified in the request does not match the reply urls configured for the application: 'fae539bd-f8be-4948-8d0e-eebdaf773111'. – Tushar Narang Aug 09 '19 at 10:52
  • @TusharNarang I didn't encounter such issue. See if this helps. https://blogs.msdn.microsoft.com/wushuai/2017/04/01/how-to-fix-access-to-odata-is-disabled-when-calling-graph-api/ – Tony Ju Aug 12 '19 at 06:37
  • Nope, it seems more of an AD auth issue, will confirm once done – Tushar Narang Aug 23 '19 at 10:45