Microsoft Graph API - отправка электронной почты от имени другого пользователя - PullRequest
0 голосов
/ 04 октября 2018

В нашем приложении нам нужно отправлять пользователям уведомления по электронной почте о различных событиях.

Я могу отправлять электронную почту, если отправляю как «Я» текущего пользователя, но пытаюсь отправить какдругая учетная запись пользователя возвращает сообщение об ошибке, и я бы предпочел, чтобы уведомления приходили не от самих пользователей и могли содержать информацию, которую мы не хотим перемещать в отправленных папках.

Что работает:

await graphClient.Me.SendMail(email, SaveToSentItems: false).Request().PostAsync();

Что не работает:

string FromUserEmail = "notifications@contoso.com";
await graphClient.Users[FromUserEmail].SendMail(email, SaveToSentItems: false).Request().PostAsync();

Также попытался напрямую использовать идентификатор объекта пользователя:

await graphClient.Users["cd8cc59c-0815-46ed-aa45-4d46c8a89d72"].SendMail(email, SaveToSentItems: false).Request().PostAsync();

Мое приложение имеет разрешения для API-интерфейса Graph для "Send mail as any user "включено и предоставлено владельцем / администратором.

Сообщение об ошибке, возвращаемое API:

Код: ErrorFolderNotFound Сообщение: указанная папка не найдена в хранилище.

Я думал, что эта ошибка могла быть из-за того, что в учетной записи уведомлений не было отправленной папки, поэтому я установил для SaveToSentItems значение false, но я все еще получаю ту же ошибку.

Есть ли сettings Мне нужно проверить саму учетную запись, чтобы приложение могло отправлять почту на эту учетную запись, или это должно сработать?

Я ознакомился с документацией здесь: https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/api/user_sendmail

.поддерживает то, что я пытаюсь сделать, но не ссылается ни на какую папку, кроме папки отправленных элементов, которую я советую API не сохранять в любом случае.

Мы не собираемся выдавать себя за любую реальнуюпользователь здесь, просто отправьте уведомления по электронной почте из приложения из этой конкретной учетной записи (я знаю, что это технически олицетворение, но не реальная сущность).

Ответы [ 3 ]

0 голосов
/ 04 октября 2018

Всякий раз, когда вы используете делегированные разрешения (т. Е. Когда пользователь вошел в систему), даже если ваш администратор дал согласие на Mail.Send.Shared, он НЕ предоставляет доступ ко всем почтовым ящикам в клиенте.Эти разрешения OAuth не переопределяют разрешения (и ограничения), действующие для пользователя.

Если пользователь еще не настроен с разрешениями для возможности «Отправить как» пользователю notifications@contoso.com, тоВы увидите эту ошибку.

Чтобы она работала, вам нужно предоставить права «Отправить как» всем пользователям, которые будут использовать ваше приложение.

Это неуловимовещь, и, конечно, это немного сбивает с толку.На портале Azure разрешения имеют несколько разные описания, в зависимости от того, смотрите ли вы приложение Application или Delegated Permissions .

  • : Send mail as any user
  • Делегированный: Send mail on behalf of others

Поскольку вы используете делегированный, разрешение не позволяет отправлять как любой пользователь,отправлять только от имени тех людей, у которых вошедший в систему пользователь имеет права на отправку как.

Другой подход, который можно использовать здесь, чтобы избежать необходимости предоставлять эти права всем пользователям (что позволит им отправлять через Outlook,и т. д.), чтобы ваше бэкэнд-приложение использовало поток учетных данных клиента для получения токена только для приложения.В этом случае само приложение будет иметь разрешение на отправку как любой пользователь.

0 голосов
/ 17 августа 2019

Так что, как и Schwarzie2478, мы использовали адрес noreply@ourcompany.com.Но наша AD является федеративной, что означает, что вы не можете использовать имя пользователя \ пароль для аутентификации, и мы не хотим использовать приложение Mail.Отправить разрешение, поскольку оно буквально может отправлять как кто-либо, и нет никакой возможности, чтобы IT Security позволила этому летать.Поэтому вместо этого мы использовали проверку подлинности Windows.

Для этого необходимо дать согласие приложению на использование разрешений делегатов mail.send и user.read, перейдя на https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/authorize?client_id={clientId}&response_type=code&scope=user.read%20mail.send и войдя в систему с пользователем Windows.что приложение будет работать как.

Подробнее об использовании Windows Auth здесь: https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/Integrated-Windows-Authentication

// method call
var t = SendEmailUsingGraphAPI();
t.Wait();

// method
static async Task<Boolean> SendEmailUsingGraphAPI() {

    // AUTHENTICATION
    var tenantID = "YOUR_TENANT_ID"; //azure ad tenant/directory id
    var clientID = "YOUR_APPS_CLIENT_ID"; // registered app clientID
    var scopes = "user.read mail.send";  // DELEGATE permissions that the request will need

    string authority = $"https://login.microsoftonline.com/{tenantID}";
    string[] scopesArr = new string[] { scopes };

    try {
        IPublicClientApplication app = PublicClientApplicationBuilder
                .Create(clientID)
                .WithAuthority(authority)
                .Build();

        var accounts = await app.GetAccountsAsync();

        AuthenticationResult result = null;
        if (accounts.Any()) {
            result = await app.AcquireTokenSilent(scopesArr, accounts.FirstOrDefault())
                .ExecuteAsync();
        }
        else {
            // you could acquire a token by username/password authentication if you aren't federated.
            result = await app.AcquireTokenByIntegratedWindowsAuth(scopesArr)
                //.WithUsername(fromAddress)
                .ExecuteAsync(CancellationToken.None);
        }

        Console.WriteLine(result.Account.Username);


        // SEND EMAIL
        var toAddress = "EMAIL_OF_RECIPIENT";
        var message = "{'message': {'subject': 'Hello from Microsoft Graph API', 'body': {'contentType': 'Text', 'content': 'Hello, World!'}, 'toRecipients': [{'emailAddress': {'address': '" + result.Account.Username + "'} } ]}}";

        var restClient = new RestClient("https://graph.microsoft.com/v1.0/users/" + result.Account.Username + "/sendMail");
        var request = new RestRequest(Method.POST);
        request.AddHeader("Content-Type", "application/json");

        request.AddHeader("Authorization", "Bearer " + result.AccessToken);
        request.AddParameter("", message, ParameterType.RequestBody);
        IRestResponse response = restClient.Execute(request);
        Console.WriteLine(response.Content);

    }
    catch (Exception e) {
        Console.WriteLine(e.Message);
        throw e;
    }

    return true;
}
0 голосов
/ 04 октября 2018

Я не знаю, что другие будут делать для этого, но я связался с Microsoft по поводу этого точного сценария: я хочу отправить письмо фиксированному пользователю (noreply@mycompany.com), у которого есть почтовый ящик в Azure.Я хочу отправлять это письмо из разных приложений или служб.

Человек, который сказал мне, что отправка почты без входа пользователя возможна только с маркером делегированного пользователя .

Таким образом, мы настроили наше приложение как родное приложение в Azure, как для мобильных приложений.Вход в систему для этого приложения с техническим пользователем на этапе установки дает мне токен делегированного пользователя для этого конкретного пользователя, который можно сохранить в почтовой службе или компоненте.Срок действия этого токена не истекает (по крайней мере, до тех пор, пока безопасность пользователя не изменится, например, пароль или что-то еще), и его можно использовать для вызова графа api для отправки писем, когда вы разрешаете этой учетной записи отправлять письма от.

Кроме того, мы даже связали другие общие почтовые ящики с этими учетными записями, чтобы иметь возможность отправлять почту и для этих почтовых ящиков.

Документация:

Сначала Вам необходима регистрация собственного приложения в Azure (невеб-API):

https://docs.microsoft.com/en-us/azure/active-directory/develop/native-app

Это приложение требует только одноразового входа в систему и подтверждения от пользователя, чтобы получить токен, который может представлять этого пользователя неопределенно долго.Мы создали учетную запись пользователя почты, которая будет использоваться для этого.Этот токен затем используется для получения токена доступа к Graph Api для отправки писем и, например,

Пример обработки токена:

https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/token-cache-serialization

с сохранением идентификационного токена (обычно a.файл кэша где-нибудь) вы можете запросить маркер доступа:

Клиент идентификации:

https://docs.microsoft.com/en-us/dotnet/api/microsoft.identity.client.publicclientapplication?view=azure-dotnet

 _clientApp = new PublicClientApplication(ClientId, "https://login.microsoftonline.com/{xxx-xxx-xx}, usertoken,...

authResult = await _clientApp.AcquireTokenSilentAsync (scopes, ...

        private static string graphAPIEndpoint = "https://graph.microsoft.com/v1.0/me";

    //Set the scope for API call to user.read
    private static string[] scopes = new string[] { "user.read", "mail.send" };
    private const string GraphApi = "https://graph.microsoft.com/";

            var graphclient = new GraphServiceClient($"{GraphApi}/beta",
                       new DelegateAuthenticationProvider(
                           (requestMessage) =>
                           {                                  
                                   // inject bearer token for auth
                                   requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", authResult.AccessToken);
                               return Task.FromResult(0);
                           }));

        var sendmail = graphclient.Users[User].SendMail(mail), true);
        try
        {
            await sendmail.Request().PostAsync();
        }
        catch (Exception e)
        {
...