MailKit OAuth2 SMTP Office365 Отправить почту

Поскольку Microsoft объявила об удалении базовой поддержки smtp для аутентификации, я пытаюсь найти другой способ отправки электронных писем из моего приложения. Мои приложения являются серверными приложениями, поэтому это должен быть неинтерактивный поток.

Когда я использую поток паролей, все работает отлично, однако поток предоставления пароля является устаревшим, поскольку он также раскрывает пароль пользователя:

static async Task<string> GetAccessToken(FormUrlEncodedContent content, string tokenEndpoint)
{
    var client = new HttpClient();
    var response = await client.PostAsync(tokenEndpoint, content).ConfigureAwait(continueOnCapturedContext: false);
    var jsonString = await response.Content.ReadAsStringAsync();
    client.Dispose();

    var doc = JsonDocument.Parse(jsonString);
    JsonElement root = doc.RootElement;
    if (root.TryGetProperty("access_token", out JsonElement tokenElement))
        return tokenElement.GetString()!;

    throw new Exception("Failed to get access token");
}

static void SendO365(SaslMechanism accessToken, string host, int port, string from, string to)
{
    using (var client = new SmtpClient())
    {
        client.ServerCertificateValidationCallback = (s, c, h, e) => true;

        try
        {
            client.Connect(host, port, SecureSocketOptions.Auto);
            client.Authenticate(accessToken);
            var msg = new MimeMessage();
            msg.From.Add(MailboxAddress.Parse(from));
            msg.To.Add(MailboxAddress.Parse(to));
            msg.Subject = "Testing SMTP";
            msg.Body = new TextPart("plain") { Text = "This is a test message." };
            client.Send(msg);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
}

var content = new FormUrlEncodedContent(new List<KeyValuePair<string, string>>
{
    new KeyValuePair<string, string>("client_id", "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx"),
    new KeyValuePair<string, string>("client_secret", "yyy"),
    new KeyValuePair<string, string>("grant_type", "password"),
    new KeyValuePair<string, string>("resource", "https://outlook.office365.com"),
    new KeyValuePair<string, string>("scope", ".default"),
    new KeyValuePair<string, string>("username", "[email protected]"),
    new KeyValuePair<string, string>("password", "zzz"),
});

string tenantId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx"
string tokenEndpoint = $"https://login.microsoftonline.com/{tenantId}/oauth2/token";
var accessToken = GetAccessToken(content, tokenEndpoint).Result;

var userEmail = "[email protected]";
var smtpServer = "smtp.office365.com";
var smtpPort = 587;
var toEmail = "[email protected]";

SendO365(new SaslMechanismOAuth2(userEmail, accessToken), smtpServer, smtpPort, userEmail, toEmail);

В Entra я установил область действия Mail.Send.

Я попробовал переключиться на поток client_credentials, так как он более безопасен, но всегда получаю сообщение об ошибке Authentication unsuccessful на client.Authenticate(accessToken).

У кого-нибудь есть идея?

Редактировать

Репозиторий GitHub: https://github.com/tsafadi/MailKit-OAuth-SMTP/tree/master/MailKit.SMTP-OAuth

Learn.microsoft.com/en-us/exchange/client-developer/…
SoftwareDveloper 10.06.2024 20:16
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
1
184
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

Я задокументировал, что вам нужно сделать, здесь: https://github.com/jstedfast/MailKit/blob/master/ExchangeOAuth2.md (в частности, см. документацию по веб-службам).

Повторная публикация здесь, чтобы порадовать StackOverflow.

Регистрация вашего приложения в Microsoft

Независимо от того, пишете ли вы настольное, мобильное или веб-приложение, первое, что вам нужно сделать, это зарегистрировать свое приложение с платформой идентификации Microsoft. Для этого зайдите на сайт Microsoft Краткое руководство и следуйте инструкциям.

Настройка правильных разрешений API для вашего приложения

Существует несколько различных разрешений API, которые вы можете настроить в зависимости от того, какие протоколы намерено использовать ваше приложение.

Следуйте инструкциям по добавлению разрешений POP, IMAP и/или SMTP в приложение Entra AD.

Веб-сервисы

Регистрация участников службы для вашего веб-сервиса

После регистрации вашей веб-службы администратору клиента необходимо будет зарегистрировать вашего субъекта службы.

Чтобы использовать командлет New-ServicePrincipal, откройте Azure Powershell. терминал, установите ExchangeOnlineManagement и подключитесь к своему арендатору, как показано ниже:

Install-Module -Name ExchangeOnlineManagement -allowprerelease
Import-module ExchangeOnlineManagement 
Connect-ExchangeOnline -Organization <tenantId>

Затем зарегистрируйте принципала службы для вашего веб-сервиса:

New-ServicePrincipal -AppId <APPLICATION_ID> -ObjectId <OBJECT_ID> [-Organization <ORGANIZATION_ID>]

Предоставление разрешений для вашего веб-сервиса

Чтобы предоставить вашей веб-службе разрешения на доступ к учетной записи Office365 и/или Exchange, вам необходимо сначала получить Идентификатор участника службы, зарегистрированный на предыдущем шаге с помощью следующей команды:

Get-ServicePrincipal | fl

Получив идентификатор участника службы для вашей веб-службы, используйте следующую команду, чтобы добавить полный Разрешения почтового ящика для учетной записи электронной почты, к которой будет обращаться ваша веб-служба:

Add-MailboxPermission -Identity "[email protected]" -User 
<SERVICE_PRINCIPAL_ID> -AccessRights FullAccess

Аутентификация веб-службы с помощью OAuth2

Теперь, когда у вас есть строки Client ID и Tenant ID, вам нужно будет подключить эти значения в ваше приложение.

В следующем примере кода используется Microsoft.Identity.Client. пакет nuget для получения токена доступа, который понадобится MailKit для передачи на Exchange. сервер.

var confidentialClientApplication = ConfidentialClientApplicationBuilder.Create (clientId)
    .WithAuthority ($"https://login.microsoftonline.com/{tenantId}/v2.0")
    .WithCertificate (certificate) // or .WithClientSecret (clientSecret)
    .Build ();
 
var scopes = new string[] {
    // For IMAP and POP3, use the following scope
    //"https://ps.outlook.com/.default"

    // For SMTP, use the following scope
    "https://outlook.office365.com/.default"
};

var authToken = await confidentialClientApplication.AcquireTokenForClient (scopes).ExecuteAsync ();
var oauth2 = new SaslMechanismOAuth2 (accountEmailAddress, authToken.AccessToken);

using (var client = new SmtpClient ()) {
    client.Connect ("smtp.office365.com", 587, SecureSocketOptions.SslOnConnect);
    client.Authenticate (oauth2);
    client.Send (message);
    client.Disconnect (true);
}

Дополнительные ресурсы

Для получения дополнительной информации посетите Microsoft.Identity.Client документация.

Я попробую это, спасибо!

Tom el Safadi 13.06.2024 08:44

Я выполнил все в точности, как вы сказали, но продолжаю получать 535: 5.7.3 Authentication unsuccessful [FR4P281CA0165.DEUP281.PROD.OUTLOOK.COM 2024-06-13T14:41:10.853Z 08DC8A68B4EFA073]

Tom el Safadi 13.06.2024 16:41

Нет, пробовал несколько раз и даже все удалял, но не работает. Есть несколько вещей, которые меня смущают. Во-первых, в предоставленной вами статье MSFT, в которой показано, как добавлять разрешения к приложению, показан снимок экрана с «SMTP.SendAsApp», который я не могу найти. Я предполагаю, что теперь это Mail.Send. Кроме того, когда я пытаюсь создать своего субъекта-службы, я не могу использовать идентификатор объекта регистрации приложения, мне нужно использовать идентификатор объекта корпоративного приложения. Это все очень запутанно, и я не могу заставить это работать

Tom el Safadi 13.06.2024 17:55

Я создал репозиторий GitHub. Может быть, вы сможете проверить это и посмотреть, есть ли что-то не так.

Tom el Safadi 13.06.2024 18:11

Нет, разрешение Mail.Send предназначено ТОЛЬКО для HTTP REST API (также известного как Microsoft.Graph API) и НЕ РАЗРЕШАЕТ отправку SMTP. Вот почему вы терпите неудачи.

jstedfast 13.06.2024 19:21

Это работает, большое спасибо! Я действительно использовал неправильное разрешение.

Tom el Safadi 14.06.2024 08:39

Мне нужно использовать SMTP и IMAP с OAUTH2 на адресе электронной почты потребителя Outlook.com (т. е. без активного каталога). Во всех решениях говорится о наличии клиента Azure с активной подпиской. У меня нет такого. Как использовать OAUTH2 на потребительском адресе электронной почты Outlook.com с помощью MailKit?

Andrew17856 21.07.2024 21:23

Вам нужна учетная запись Azure с клиентом, потому что именно так вы регистрируете свою программу. Без этого вы не сможете получить идентификатор клиента или секрет, необходимые для процесса аутентификации OAuth2. Outlook, Thunderbird и т. д. имеют свои собственные идентификаторы/секреты клиентов, которые компании, владеющие этими приложениями, зарегистрировали в Azure. Но если вы пишете собственную программу, вам понадобится собственная учетная запись Azure. Обойти это невозможно.

jstedfast 22.07.2024 23:31

Другие вопросы по теме

Похожие вопросы

Как добавить 32-разрядный пользовательский элемент управления Windows Forms в панель инструментов Visual Studio в vs2022 (64-разрядная версия)
Как добавить строку или разделитель в UniformGrid в WPF?
Почему я получаю исключение User-Unhandled?
Невозможно подключиться к SQLLite в MAUI (.NET 8)
Как преобразовать тип в универсальный тип, фактический тип которого известен в момент преобразования?
Как решить проблему «ManagedIdentityCredential.GetToken не удалось получить токен доступа». при использовании Azure ServiceBusTrigger и управляемого удостоверения?
Селектор шаблонов данных нажимается только один раз, а не при обновлении полного свойства
Как разрешить окну использовать стиль по умолчанию, но не стиль инфраструктуры пользовательского интерфейса (Lepoco WPFUI) в WPF?
Можно ли сохранить только отношение и определенную таблицу в отношении «многие ко многим» с помощью Entity Framework Core?
ASP.NET Core — отключить HTTP/2 в HttpSys