Sending emails from daemon app using Graph API on behalf of me

Jan Tošovský 6 Reputation points
2020-07-07T15:11:54.18+00:00

I'd like to send some internal alerts or notifications from my daemon scripts directly to specific email addresses.

I am investigating simple REST API client using Microsoft Graph API, but I am failing to find any example covering this simple scenario.

For daemon apps AFAIK only Client Credentials authentication provider is available.
https://learn.microsoft.com/en-us/graph/sdks/choose-authentication-providers

In this case:

  • application-wide Email.Send scope needs to be allowed
  • this scope allows to send emails on behalf of anybody !
  • because of this broad permission the consent of tenant Admin is required

This broad permission is not acceptable in our company so no way.

I hope I am missing something and there is some way.

Microsoft Entra ID
Microsoft Entra ID
A Microsoft Entra identity service that provides identity management and access control capabilities. Replaces Azure Active Directory.
19,389 questions
0 comments No comments
{count} vote

2 answers

Sort by: Most helpful
  1. soumi-MSFT 11,716 Reputation points Microsoft Employee
    2020-07-09T12:25:46.307+00:00

    @jan-tosovsky, Thank you for reaching out and I apologize for the delay in my response. based on this query you shared, I believe the best way to go about is using the on-behalf-of flow. When you go through the details of this flow you would find that initially a user has to first authentication and fetch a token for an API registered in AAD (lets say API-A) and then this API-A would be making the call to the Graph API on behalf of the user.

    Initially, when the user has to authenticate to get a token for API-A, since you are using a Daemon app, you can use the ROPC flow where you can specify the username and password in the app code itself using which the token can be requested from AAD.

    Now, when using the on-behalf-of flow, you would need to provide delegated permission "Send mail as a user", for graph api on API-A so that it can fetch a token for Graph API on your behalf.

    Another approach you could use here to avoid having to grant these rights to all users (which would allow them to send via Outlook, etc.) would be to have your backend app use the client credentials flow to get an app-only token. In that case, the app itself would have the permission to send as any user.

    Hope this helps.

    Do let us know if this helps and if there are any more queries around this, please do let us know so that we can help you further. Also, please do not forget to accept the response as Answer; if the above response helped in answering your query.


  2. 2020-10-21T07:20:46.127+00:00

    @soumi-MSFT I have a same issue and here is my case

    I have a service account using which i need to send Email

    I created a appId and got Send.Mail delegation consented by AAD Admin

    33929-image.png

    This is the error I am getting when sending the Email. I spent lot of time trying to know what is the issue. Can you please help me what is the problem.

    Federated service at https://msft.sts.microsoft.com/adfs/services/trust/2005/usernamemixed returned error: ID3242: The security token could not be authenticated or authorized.

    This is the code I am using to get the token.

    -----------------------------------------------------------------------------------------------------------------------------

    string[] scopes = new string[] { "Mail.Send" };

                IPublicClientApplication publicClientApplication = PublicClientApplicationBuilder  
                            .Create(clientId)  
                            .WithTenantId(tenantId)  
                            .Build();  
    
                UsernamePasswordProvider authProvider = new UsernamePasswordProvider(publicClientApplication, scopes);  
                 
                GraphServiceClient graphClient = new GraphServiceClient(authProvider);  
    

    -----------------------------------------------------------------------------------------------------------------------------

    And below is the code to send Email.

    ----------------------------------------------------------------------------------------------------------------------------

    SecureString password = new SecureString();
    foreach (char c in emailpassword)
    {
    password.AppendChar(c);
    }

                // construct http request  
                var message = new Message  
                {  
                    Subject = subject,  
                    Body = new ItemBody  
                    {  
                        ContentType = BodyType.Html,  
                        Content = body  
                    },  
                    ToRecipients = new List<Recipient>()  
                    {  
                        new Recipient  
                        {  
                            EmailAddress = new EmailAddress  
                            {  
                                Address = toEmailId  
                            }  
                        }  
                    }  
                };  
    
                if (ccMailId != null)  
                {  
                    message.CcRecipients = new List<Recipient>()  
                    {  
                        new Recipient  
                        {  
                            EmailAddress = new EmailAddress  
                            {  
                                Address = ccMailId  
                            }  
                        }  
                    };  
                }  
    
                var saveToSentItems = false;  
    
                await graphClient.Me.SendMail(message, saveToSentItems).Request().WithUsernamePassword(email, password).PostAsync();  
    
    0 comments No comments