0

I am trying to replace a windows service which sends emails for users via smtp with Microsoft accounts (within the business)

Microsoft are turning off the old auth method at the end of the month

I am using c# and mail kit and can get a token, however I can not currently send emails without user interaction to 'sign in via a webpage' each time to grant permission

Ofcourse a windows service on another box can not interact with the users

I have registered my app via azure, that part seems done

I have searched the web and find a lot of mixed results

Is anyone aware, Is it currently possible to have a windows service (without user interaction) send emails on a users behalf (I have their user/pass etc) but can not see a clear way to do this using mailkit

Thank You

Haggo
  • 19
  • 6

1 Answers1

0

it appears that user:sendmail has application permission. https://learn.microsoft.com/en-us/graph/api/user-sendmail?view=graph-rest-1.0&tabs=http

meaning you can register your application with a client secret and then use the client secret to make calls to graph without the need for user interaction.

you can most of this from the graph quick start https://developer.microsoft.com/en-us/graph/quick-start

I am working on something similar where I am making graph calls through a c# api but probably similiar.

I have my registration info in appsettings.

 "Settings": {
    "clientId": "7d202de8-ccd8-xxxxxxxx-a5e4-101df736dd6a",
    "clientSecret": "ctV8Q~U3qYHpd_xxxxxxOeHB08TXxxxxxxxxU_.ag9",
    "tenantId": "44fxxxxxx5-327a-4d5a-86d5-cxxxxxxxxx97d7e4"
  },

I have a helper class that makes the api calls (this one is getting some users)

namespace Application
{
    using Azure.Identity;
    using Microsoft.Graph;
    public class GraphHelper
    {
        private static Settings _settings;

        public static void InitializeGraph(Settings settings,
    Func<DeviceCodeInfo, CancellationToken, Task> deviceCodePrompt)
        {
            _settings = settings;
        }

        private static ClientSecretCredential _clientSecretCredential;
        private static GraphServiceClient _appClient;

        private static void EnsureGraphForAppOnlyAuth()
        {
            _ = _settings ??
                throw new System.NullReferenceException("Settings cannot be null");

            if (_clientSecretCredential == null)
            {
                _clientSecretCredential = new ClientSecretCredential(
                    _settings.TenantId, _settings.ClientId, _settings.ClientSecret);
            }

            if (_appClient == null)
            {
                _appClient = new GraphServiceClient(_clientSecretCredential,
                    new[] { "https://graph.microsoft.com/.default" });
            }
        }

        public static Task<IGraphServiceUsersCollectionPage> GetUsersAsync()
        {
            EnsureGraphForAppOnlyAuth();
            _ = _appClient ??
                throw new System.NullReferenceException("Graph has not been initialized for app-only auth");

            return _appClient.Users
                .Request()
                .Select(u => new
                {
                    // Only request specific properties
                    u.DisplayName,
                    u.Id,
                    u.Mail
                })
                // Get at most 25 results
                .Top(25)
                // Sort by display name
                .OrderBy("DisplayName")
                .GetAsync();
        }
}
}
 

then I can make calls to it like this

public async Task<IGraphServiceUsersCollectionPage> Handle(Query request, CancellationToken cancellationToken)
            {
                Settings s = new Settings();
                var settings = s.LoadSettings(_config);
                GraphHelper.InitializeGraph(settings, (info, cancel) => Task.FromResult(0));
                var result = await GraphHelper.GetUsersAsync();
                return result;
            }
Bryan Dellinger
  • 4,724
  • 7
  • 33
  • 79
  • This looks great thank you, I have followed your link to graph quick start I am just awaiting to have a MPN account verified then hopefully i can continue the help doc steps, looks good so far – Haggo Sep 13 '22 at 14:00
  • if you want a pure development environment you can sign up here https://developer.microsoft.com/en-us/microsoft-365/dev-program it will give you a free tenant and a bunch of E3 licenses you can use. that is what I am currently using for development so I don't have to keep bugging admins for stuff till I'm ready to deploy – Bryan Dellinger Sep 13 '22 at 15:25
  • Thank You, while I await, I have signed up for a dev account and have access to azure for it, I am unable to grant the following permission for Application Mail.Send It always says, not granted for x user I have given the user I am logged in to azure with, any role and even made a customer role with every right – Haggo Sep 14 '22 at 09:56
  • yeah it is a bit confusing even after you go to api permissions and add the permission it is still not granted. you have to go to the top next to add permission where it says grant admin consent for whatever and click that. then it will work – Bryan Dellinger Sep 14 '22 at 10:46
  • when you are adding mail.send in the api permissions portal you are picking application permissions and not delegated permissions correct? you should not need to give a specific user roles as your c# application will be signing in with the secret key not with a user. user roles should be irrelevant – Bryan Dellinger Sep 14 '22 at 10:57
  • It seems Grant admin is greyed out I am picking application permissions Ok, I shall try with the keys Thank You for your help so far :-) its very useful I have been able to use and send an email, with the MS sample from your link, using the keys etc, but it is making my give access with a webpage every time I was expecting that to happen once perhaps :-( – Haggo Sep 14 '22 at 11:06
  • if you signed up for a developer account, the user that you are using go to the office 365 admin portal and give them the role global administrator, then you can do anything. so the send email in that example is using delegated permission (which you don't want) in the example switch it to the application permission the one that says _appclient , the one that is used for get users async and see if you can get it working that way. because you don't want your users to have to log on in your actual c# application – Bryan Dellinger Sep 14 '22 at 11:18
  • I have done this now thank you, it seems unless you have a permission in the list which is granted already, the button is greyed, but not if you have a lesser permission granted already, then its not greyed and you can grant the others, odd lol so am i right in thinking, if i continue down this route that every domain / overall azure account (so every company/customer our ours) will need to do this same thing, and allow my app access to send email as a whole on their behalf – Haggo Sep 15 '22 at 08:03