【.NET C#】Microsoft365アカウントで先進認証使用のメール送信

# はじめに
Microsoft365のメールサーバを利用して、Windows上の.NET コンソールプログラムからメール送信をするのに、基本認証が使用出来なくなってしまったようで（※2022/12/8現在）、OAuthなる認証を使用して、Tokenを取得してからのメール送信までやってみました。

送信元となるアカウントはMicrosoft365の管理者権限を保有しないユーザを想定していますが、一部に管理者権限を必要とする操作があります。

# Azure Potalでの設定（管理者権限なし）
STMP送信のAPIを利用可能なアプリの登録をします。

1. メール送信元となるMicrosoft365アカウントでAzure Potalにログインします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3036782/e98d01c6-d959-3967-a3f8-83318dc5c488.png)

2. 左上”ポータルメニュー”から`Azure Active Directory`をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3036782/d04ffcb0-2d42-0e33-b046-759a82ec933a.png)

3. `アプリの登録`をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3036782/19fc5d95-2acc-6732-d4f7-e4a8ba54f78d.png)

4. `新規登録`をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3036782/5628d950-9645-3a0e-e82a-a3f8630cba37.png)

5. `名前`には任意の名称を入力します。（ここではsend_mailとしました）
   `サポートされているアカウントの種類`はデフォルトの`この組織ディレクトリのみに含まれるアカウント`を選択します。
   `登録`ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3036782/ebfddcdc-65b2-5a6e-8689-9e54b9b42717.png)

6. 新規アプリが作成され、各種IDが生成されています。（マスクで隠している箇所です）
   `アプリケーション (クライアント) ID`、`ディレクトリ (テナント) ID`はToken取得の際に必要な項目となります。
   `APIのアクセス許可`をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3036782/d1193227-b246-0986-f685-40b4045e1bb0.png)

7. `アクセス許可の追加`をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3036782/a552bf2f-56ac-af85-c887-62866d896886.png)

8. `Microsoft Graph`をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3036782/87d01a47-23f3-6315-e836-8707c0aa8c4c.png)

9. `委任されたアクセス許可`をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3036782/7d37d97f-f8d9-4f90-9166-97a630e92912.png)

10. `検索窓`に”smtp”と入力すると、下にアクセス許可の候補として表示されます。
   `SMTP.Send`をチェックをして、`アクセス許可の追加`ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3036782/d7cdf88f-e088-74fe-e953-d7a9b44f2c4c.png)

11. アクセス許可`SMTP_Send`が追加されています。
   `認証`をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3036782/ffb73a07-bcda-3a6b-b36b-4ccdcc87470b.png)

12. `プラットフォームを追加`をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3036782/89ed40ea-d35f-7481-4ebb-d8a307f96e97.png)

13. `モバイル アプリケーションとデスクトップ アプリケーション`をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3036782/0d92080f-4ad5-2b1c-d22e-9c887198a953.png)

14. `リダイレクト URI`は`https://login.microsoftonline.com/common/oauth2/nativeclient`
をチェックし、`構成`ボタンを押します。
これはToken取得の際に必要な項目となります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3036782/60a94969-7328-596a-051a-8e51fea40485.png)

15. プラットフォームが追加されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3036782/3804db6f-31e9-3cd6-37f6-bb5de07b1e31.png)

16. `サポートされているアカウントの種類`はデフォルトの`この組織ディレクトリのみに含まれるアカウント`をチェックします。
   `パブリック クライアント フローを許可する`ー`次のモバイルとデスクトップのフローを有効にする`を`はい`にして、`保存`ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3036782/62dca2c7-59b3-b672-b97a-b326fa6022fe.png)

# Azure Potalでの設定（※管理者権限あり）
送信元アカウントで作成したアプリに、許可を付与します。

1. 管理者権限を保有するMicrosoft365アカウントでAzure Potalにログインします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3036782/e98d01c6-d959-3967-a3f8-83318dc5c488.png)

2. 左上”ポータルメニュー”から`Azure Active Directory`をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3036782/d04ffcb0-2d42-0e33-b046-759a82ec933a.png)

3. `アプリの登録`をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3036782/19fc5d95-2acc-6732-d4f7-e4a8ba54f78d.png)

4. `すべてのアプリケーション`タブをクリックすると、作成済みアプリ`send_mail`があるのでクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3036782/fc960b8a-8d6a-7238-d0fc-c9e17838d4d2.png)

5. `APIのアクセス許可`をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3036782/c8c41515-24eb-3f1e-2030-8475539eccc5.png)

6. `[ポータル名]に管理者の同意を与えます`をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3036782/d854789c-c373-a48e-1916-08e46c297ee3.png)

7. `管理者の同意の確認を与えます。`で`はい`ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3036782/51a5a6ca-d26e-f692-51cf-347f04cc79ae.png)

8. 状態にチェックが表示されます。`[ポータル名]に付与されました`となりアクセス許可が委任されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3036782/fc629dcf-bd40-5fb0-83c2-76a20cc845eb.png)

# Microsoft365管理センターでの設定（※管理者権限あり）
送信元アカウントの認証済みSMTPを有効化します。

1. 管理者権限を保有するアカウントでログインし、`管理`をクリックします。 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3036782/61afb941-b3d0-389f-b57f-650c3261d98a.png)

2. 送信元アカウントをクリックします。（ここではguest1@xxx.onmicrosoft.com）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3036782/1163952b-b78f-ce5a-785f-f328955f6109.png)

3. `メール`タブをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3036782/be7c5856-b5e3-d4de-48e0-1215dbfd5f70.png)

4. `メール アプリを管理する`をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3036782/8f335e06-3c26-6baa-c12a-16c1f876af39.png)

5. `認証済み SMTP`をチェックし、`変更の保存`ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3036782/de55cd60-8136-6570-6512-ce0ba0a32161.png)

6. 設定が変更されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3036782/56848914-7fde-954d-4ce0-304737837653.png)

# メール送信（.NET C#）
Windows10Pro21H2 .NET6.0.11にて検証しました。
追加ライブラリはMicrosoft.Identity.Client 4.48.1、MailKit 3.4.3 です。

Codespaces上でも動作したので、Linux・MacOSでもいけるはず。
```
// Azure Portalで登録したアプリのアプリケーション (クライアント)ID
private static string CLIENT_ID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
// Azure Portalで登録したアプリのディレクトリ (テナント) ID
private static string TENAMT_ID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"; 
// M365メールのアカウント（送信元アカウント）
private static string USER_ACCOUNT = "xxx@zzz.onmicrosoft.com"; 
// M365メールのパスワード
private static string USER_PASSWORD = "*****"; 
// 送信先メールアドレス
private static string TO_MAIL_ADDRESS = "aaai@bbb.com"; 

static void Main(string[] args)
{
    try
    {
        // トークン取得
        var accessToken = GetAccessToken();
        accessToken.Wait();

        // メール送信
        SendMail(accessToken.Result).Wait();
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.ToString());
        throw;
    }
}

/// <summary>
/// トークン取得
/// </summary>
/// <returns>認証結果</returns>
public static async Task<AuthenticationResult> GetAccessToken()
{
    var options = new PublicClientApplicationOptions
    {
        ClientId = CLIENT_ID,
        TenantId = TENAMT_ID,               
        RedirectUri = "https://login.microsoftonline.com/common/oauth2/nativeclient" // Azure PortalのリダイレクトURI
    };

    var publicClientApplication = PublicClientApplicationBuilder
        .CreateWithApplicationOptions(options)
        .Build();

    var scopes = new string[] {
                    "https://outlook.office.com/SMTP.Send",
    };
    var user = USER_ACCOUNT;
    var password = USER_PASSWORD;

    AuthenticationResult authToken = await publicClientApplication.AcquireTokenByUsernamePassword(scopes, user, password).ExecuteAsync();

    return authToken;
}

/// <summary>
/// メール送信
/// </summary>
/// <param name="authToken">認証結果</param>
static async Task SendMail(AuthenticationResult authToken)
{
    var oauth2 = new SaslMechanismOAuth2(authToken.Account.Username, authToken.AccessToken);

    var message = new MimeKit.MimeMessage();
    // 送信元アドレス
    message.From.Add(new MimeKit.MailboxAddress("ユーザー", USER_ACCOUNT));
    // 送信先アドレス
    message.To.Add(new MimeKit.MailboxAddress("テスト", TO_MAIL_ADDRESS));
    // CC、BCCを設定
    // message.Cc.Add("a@b.com");
    // message.Bcc.Add("aa@bb.com");
    // メールタイトル
    message.Subject = "subject";

    // 本文作成
    var textPart = new MimeKit.TextPart(MimeKit.Text.TextFormat.Plain);
    textPart.Text = "body";

    // MimeMessage作成
    message.Body = textPart;

    using (var client = new MailKit.Net.Smtp.SmtpClient())
    {
        await client.ConnectAsync("smtp.office365.com", 587, SecureSocketOptions.Auto);
        await client.AuthenticateAsync(oauth2);
        await client.SendAsync(message);
        await client.DisconnectAsync(true);
    }

    return;
}
```
***
参考サイト

https://learn.microsoft.com/ja-jp/exchange/client-developer/legacy-protocols/how-to-authenticate-an-imap-pop-smtp-application-by-using-oauth