GNU Emacs + Gnus + Outlook.com + OAuth2 の環境を作ろう

# はじめに

タイトルは大変お世話になったページのリスペクトです。

このドキュメントにダイレクトに来られた方は申し訳ありません。こっちの<a href="https://qiita.com/waiseiningenchokon/items/faca52752c2f78284ecd">ドキュメント</a>の続きになっています。Gmail興味ねーよという方でも動かすまでの手順はリンク先のドキュメントに書かれているので、目を通してください。以下は目を通していただいた前提で書いています。

Emacs+Gnus+OAuth2でマルチアカウント対応を行ったので調子に乗ってGmail以外のアカウントにも手を出してみました。そうしたら結構大変だったのでその記録です。

2021/10月の更新1

9月末くらいから無料の方のoutlook.com(下にあるテナントの説明のconsumersテナントの方)で、IMAPアクセスが不能になりました。どうもこの<a href="https://techcommunity.microsoft.com/t5/exchange-team-blog/basic-authentication-and-exchange-online-september-2021-update/ba-p/2772210?lightbox-message-images-2772210=312528iD378155F018779A6">ドキュメント</a>の内容が影響しているような気がします。このドキュメントの内容、2020/4->2020/6->2021/2ところころ更新されているので、消えてしまうかもしれれないので一応引用してくと

> Basic Authentication and Exchange Online – September 2021 Update
>
> In February 2021, we announced some changes to our plan for turning off Basic Authentication in Exchange Online. In summary, we announced we were postponing disabling Basic Auth for protocols in active use by your tenant until further notice, but that we would continue to disable Basic Auth for all protocols not being used. The overall scope of the program was also extended to include Exchange Web Services (EWS), Exchange ActiveSync (EAS), POP, IMAP, Remote PowerShell, MAPI, RPC, SMTP AUTH and OAB.

という内容でした。ようするにExchange Onlineで基本認証をオフにするよという内容なのですが、ここでいう基本認証というの はOAuth2認証以外のことのようです。Google様が2021年6月に行った対応のと同等の内容をMicrosoft様が実施しようとしているように見えます。

このドキュメントはOAuth2認証を使う方式なので、対象外のはずですがなぜかひっかかってしまいます。しかもエラーになるのはIMAPだけでSMTPの方はOAuth2認証が通ります。SMTPサーバーはExchangeじゃないんでしょうか?よく分かりません。

回避方法などは<a href="https://admin.microsoft.com/">Microsoft 365 管理センター</a>を使うようですが、これって有料の方のoutlook.com(下にあるテナントの説明のorganizationsテナントの方)じゃないと開けないんですよね。無料の方は切り捨てるつもりなのでしょうか?

私もここに書いた方法でアクセスしているので困っているのですが、とりあえずの回避方法として、.authinfoのパスワードをアプリパスワードにするという方法があります。当然ながら認証は通常のログイン認証になるので、この<a href="https://qiita.com/waiseiningenchokon/items/faca52752c2f78284ecd">ドキュメント</a>のelisp等を入手しなくてもアクセス可能です。~~つまりこのドキュメントと先のドキュメントを読むこと自体、時間の無駄ということです。~~2021/11月の更新で直ったのを確認しました。無駄じゃなくなりました。まぁ人によってだと思いますが

SMTPサーバー辺りの動きを見ると、単純に対応が間に合っていないだけのような気がしますが、もしかしたら無料の方はOAuth2認証を非対応にする方針なのかもしれません。その場合はさすがにアナウンスがあると思うので、少し様子をみてみます。現状では無料版の方ではここの記載内容は無効です。 

2021/10月の更新2

outlook.comとは別にlive.jpのアカウントも持っているのですが、そちらはOAuth2認証が通るようになりました。やっぱり対応が間に合っていないように見えます。Microsoft様は段階的なロールアウトとかいうのをやるらしいので、もうしばらく待つと直るのかもしれません。まぁそんな悠長に対応されても困るんですけどね。

2021/11月の更新

outlook.comの方もOAuth2認証が通るようになりました。やっぱり何かおかしなことになっていたんですね。OAuth2認証が通らない間もアクセストークンの更新はできていたのですが、古いアクセストークンは使ってはいけないようです。一度、plstoreからキーを削除して許可をやり直す必要がありました。

plstoreから特定アカウントのキーを削除するための<a href="https://qiita.com/waiseiningenchokon/items/faca52752c2f78284ecd#%E3%81%8A%E3%81%BE%E3%81%915-plstore%E3%82%92%E3%81%A1%E3%82%87%E3%81%A3%E3%81%A8%E6%93%8D%E4%BD%9C%E3%81%A7%E3%81%8D%E3%82%8B%E3%82%88%E3%81%86%E3%81%AB%E3%81%99%E3%82%8B">ツールの記載</a>を追加しました。もしplstoreからキーの削除が必要な場合は参考にしてください。

先のMicrosoft様のドキュメントを下の方まで読んでいくと、2022年10月までは基本認証を使うための回避設定が行えるようです。でも2022年10月に全面禁止(SMTP AUTHは大丈夫かも)ようなのでまた激震が走るかもしれません。その場合は、今回のように気長に待ちましょう。Webの方は動くと思いますので、その間はおとなしくWeb版を使いましょう。

# Outlook.comのアプリ登録
Google様にアプリ登録しておんぶにだっこしてもらったように、Microsoft様にもアプリ登録が必要です。このドキュメントのメインはほぼこの節(section)です。2021年4月版です。変わる可能性があるので最新情報はググるかBingってください。

## Auzre Portal
Mirosoft様の場合、アプリ登録を行うには<a href="https://portal.azure.com">Auzre Portal</a>を使用します。ログインアカウントはアプリ登録を行おうとしているアカウントです。ログインすると何か通知が来るかもしれませんが、最終的に以下のようになると思います。

![Auzre Portal](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555574/b9063d2c-ef8c-eaca-586a-aeb58abee3c2.png)

## Azure Active Directory
この画面の左上のメニューをクリックしAzure Active Directoryを選択します。

![Azure Active Directory1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555574/3566ee6e-c79c-0884-25f7-4598ca32ff25.png)

選択すると以下のような状態になると思います。

![Azure Active Directory2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555574/ac3ebea9-58c6-5f74-3909-9125111b2716.png)


## アプリの登録

左のナビゲーションに出ているアプリの登録を選択します。この画面は初期画面です。アプリ登録が存在すれば既存のアプリが表示されます(そんな人はこのドキュメント見る必要無いと思いますが)。上の新規登録を選択してください。

![アプリの登録1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555574/236d24d9-1562-ccbe-4633-9bc36699192b.png)

名前はなんでも良いです。ご自身で分かりやすい名前を設定してください。アカウントの種類は後でまた出てきますが、個人であれば画像通りで問題ありません。

![アプリの登録2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555574/4a5df03a-41c5-a314-c5aa-049e6d8b6da0.png)

## client secretの追加
登録したアプリが選択された状態に遷移します。ナビゲーションもそれに合わせて変わります。証明書とシークレットを選択します。

![client secret1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555574/69b3ba90-91e7-e499-a203-ceb0786cd7b4.png)

新しいシークレットの追加を選択します。ここで生成される値がclient secretになります。説明は入力しなくても大丈夫です。有効期限は個人使用なのでなしで良いでしょう。追加するとクライアントシークレットが追加され、値の部分にclient secretが表示されます。その横のIDはAzureの内部管理上のIDのことです。client idではありませんで注意してください。

![client secret2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555574/a598aa17-97c4-5e19-4ca7-e2c50249be79.png)

## APIのアクセス許可(スコープの許可)
APIのアクセス許可を選択します。ここで選択した内容がOAuth2のスコープになります。選択が必要な内容は以下です。

1. offline_access
2. IMAP.AccessAsUser.All
3. POP.AccessAsUser.All
4. SMTP.Send

POPなんか使わねーからいらないだろうと思った方、私も最初はそう思ってました。でもこれを選択しないとSMTP AUTHにもOAuth2拡張が使えないのです。理由は不明です。このドキュメントの肝のひとつはここです。

![APIのアクセス許可1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555574/bd227dde-66fd-7091-1bca-dc4dda1767f5.png)
![APIのアクセス許可2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555574/9eb50fe6-b7d5-f5d7-59ca-6c482ed05a20.png)
![APIのアクセス許可3](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555574/4177edf2-2ef8-ab9f-76a9-f44e68d20861.png)
![APIのアクセス許可4](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555574/cd96d84e-3bd2-88f9-831a-fb459be4b433.png)
![APIのアクセス許可5](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555574/069968e6-70f6-8162-7301-e867f26ee3b0.png)
![APIのアクセス許可6](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555574/3e2d54d4-45de-834d-b595-cbbf9d593ad8.png)

最終的に以下のようになっていれば大丈夫です。
![APIのアクセス許可7](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555574/d40fe93f-0f1b-9c25-b850-db1a169f2307.png)

## プラットホームの追加
次に認証を選択します。
![プラットホームの追加1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555574/76375341-5896-b649-6290-fd006901f40a.png)

プラットホームを追加を選択しWebアプリケーションのWebを選択します。
![プラットホームの追加2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555574/29006329-26d2-f7b4-d4f9-9878db557db4.png)

リダイレクトURIには以下の内容を指定します。

```http
https://login.microsoftonline.com/common/oauth2/nativeclient
```
![プラットホームの追加3](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555574/947457b9-39fa-b473-2813-63b7f01b97c2.png)

この指定ですが、Gmailでは

```http
urn:ietf:wg:oauth:2.0:oob
```

となっていた部分で、コード表示画面が表示される指定をしていたところです。Outlook.comにはコード表示画面は存在せず上のURLが使用されます。後で画面イメージもつけていますが、許可を行うと

```http
https://login.microsoftonline.com/common/oauth2/nativeclient?CODE=XXXX
```

というURLに遷移します。`CODE=`の後ろのコードが許可コードなので、これをGnusの`Enter the code youer browser displayed:`に入力します。ここも肝のひとつです。

## client idの確認
これでアプリの登録で入力が必要な部分は終了です。概要を選択してください。画面上はマスクしてますが、アプリケーション(クライアント)..:の部分に表示されている値がclient idです。先のclient secretとともに取得してください。

![client idの確認](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555574/e4da1249-84ee-1b43-c02b-ef119af263d7.png)

# Gnusの設定
以下のような定義を行います。nnimapの横の文字列がグループ名になります。アカウント名等でも良いですが、ハイフンなど使えない文字もあるので英数字で定義した方が無難です。nnima-addressはIMAPサーバーのアドレスです。最新情報で変わっているようなら変更してください。

```Lisp:.gnus.el
(add-to-list
 'gnus-secondary-select-methods
 '(nnimap "outlook"
          (nnimap-address "outlook.office365.com")
          (nnimap-server-port 993)
          (nnimap-stream ssl)
          ;; Search
          (nnir-search-engine imap)))
```

nnimapのキーワードはグループ名になるので`gnus-permanently-visible-groups`を調整する必要があるかもしれません。outlookとした場合は以下のように指定します。

```Lisp:.gnus.el
(setq gnus-permanently-visible-groups "^nndraft:drafts\\|^nnimap\\+outlook:")
```

nnimapのキーワードとアカウントの紐づけのため.authinfoを定義します。outlookの文字列はnnimap側を変えたのなら合わせてください。SMTPサーバーの定義は、最新情報で変わっているようなら変更してください。

```Lisp:.authinfo
machine outlook login あなたのアカウント password notrecord
machine smtp.office365.com login あなたのアカウント port 587 password notrecord
```

アカウントの定義は以下のようにします。

```Lisp:.gnus.el
(setq gnusimapoauth2-accounts
      '(
	(:user "あなたのアカウント"
	       :smtp-server "smtp.office365.com"
	       :smtp-port 587
	       :smtp-user "あなたのアカウント"
	       :smtp-password "notrecord"
	       :smtp-auth-supported xoauth2
	       :smtp-stream-type starttls
	       :oauth2-client-id "[あなたのアカウントのclient id]"
	       :oauth2-client-secret "[あなたのアカウントのclient secret]"
	       :oauth2-scope "offline_access https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/POP.AccessAsUser.All https://outlook.office.com/SMTP.Send"
	       :oauth2-auth-url "https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize"
	       :oauth2-token-url "https://login.microsoftonline.com/consumers/oauth2/v2.0/token"
	       :oauth2-redirect-url "https://login.microsoftonline.com/common/oauth2/nativeclient"
	       )
	))
```

:oauth2-scopeはアプリ登録で指定した許可したAPIの名前です。offline_accessとそれ以外で指定方法が違いますが、そういうものらしいので気にしないでください。同様に:oauth2-redirect-urlはアプリ登録のプラットフォームで追加したURIです。例通りなら合っていると思いますが、変えているなら書き換えてください。

## テナント
この<a href="https://docs.microsoft.com/ja-jp/azure/active-directory/develop/active-directory-v2-protocols#endpoints">ドキュメント</a>によると、:oauth2-auth-urlと:oauth2-token-urlは以下のような形式になるそうです。

```http
https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize
https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
```

{tenant}のテナントの定義は以下のようになるそうです。

| 値                                                                  | 説明                                                                                                           |
|:--------------------------------------------------------------------|:---------------------------------------------------------------------------------------------------------------|
| common                                                              | 個人の Microsoft アカウントと Azure AD の職場/学校アカウントのどちらでもアプリケーションにサインインできます。|
| organizations                                                       | Azure AD の職場/学校アカウントを持つユーザーのみがアプリケーションにサインインできます。                      |
| consumers                                                           | 個人の Microsoft アカウント (MSA) を持つユーザーのみがアプリケーションにサインインできます。                  |
| 8eaef023-2b34-4da1-9baa-8bc8c9d6a490 または contoso.onmicrosoft.com | Azure AD テナントのフレンドリ ドメイン名か、テナントの GUID 識別子のいずれかを使用できます。                  |

わけが分からないですよね。私もよくわからずに、commonにして接続したら怒られまくりました。で、エラーコードなどを調べた結果、ようする以下のようなことだと分かりました。

| 値                 | ようするに                                                                                  |サインインするときのアカウントの種類   |
|:-------------------|:--------------------------------------------------------------------------------------------|:-------------------------------------|
| organizations      | Microsoft365の有料outlookを使う場合。Exchange Onlineに繋げる場合                            |職場または学校アカウント IT部署が作成 |
| consumers          | hotmail由来の無料outlookを使う場合。UIは変わっているけどWindows Live Mailに繋げる場合       |個人のアカウント お客様が作成         |

同じアカウント(メールアドレス)に2つの接続先が発生してしまっているのは、Microsoft様の都合なので、OAuth2プロトコル的には知らないということになります。本当はプロトコルに職場のアカウントなのか、個人のアカウントなのを指定できれば良かったんでしょう。で、それではMicrosoft様は困るのでテナントというので、区分けしているみたいです。

今回のケースでは個人のアカウントの方を使うので、consumersを指定しています。ここも肝のひとつです。

私はExchange Onlineは使っていないので、多分になるのですが、アプリの登録をMicrosoft365が提供している組織のAzure ADで行えば、organizationsの指定も可能なんだと思います。その場合はアプリの登録時のアカウントの種類も組織ディレクトリ内のアカウントにする必要があると思います。

えっ。commonとか上以外のテナントの意味ですか? ここまでの説明した内容だけ分かれば接続できるので深追いしてません。こうやって中途半端な知識が増えていくんですよね。困ったもんだ。

2021/4/9の追記

気になったのでMicrosoft365の方で確認してみました。Enterprise E5のアカウントは持っているのです。やっぱりMicrosoft365のAuzre Portalで同じことを行えば、接続できるようになります。違いは以下の通りです。

1. アプリ登録時のアカウントの種類は、『この組織ディレクトリのみに含まれるアカウント』にします。
2. client secretの有効期限なしは選択できなくなります。最大3年というのが期限になります。

これ以外は一緒です。.gnus.elなどもテナント以外は同じでうまくいきます。でも許可時に職場または学校アカウントか個人のアカウントを選んでログインするので、テナントってあんまり意味ないような気がします。Microsoft様の都合なんですかね。詳細はわかりません。

SMTPの送信を行う場合は、SMTP AUTHを許可しないといけません。<a href="https://admin.microsoft.com/">Microsoft 365 管理センター</a>を開き、『ユーザ』->『アクティブユーザ』で該当ユーザを選択してください。その後、『メール』を選択し『メールアプリの管理』で『認証済SMTP』をチェックします。

この設定画面にはIMAPの許可などもあります。ここがチェックされていないとそもそもIMAPでアクセスできないので、うまく行かない場合は確認してみましょう。組織のポリシーで、この画面を出せないこともあるかもしれません。その場合は、頑張って説得してくださいとしか言えません。

デフォルトのメールフォルダの構成が大きく異なりました。以下のようになります。予定表もIMAPでアクセスできるみたいです。Exchangeってそういうものなんですか?この辺りの話はExchangeに詳しい人に確認してください。

| フォルダ名        |
|:------------------|
| INBOX             |
| アーカイブ        |
| ジャーナル        |
| タスク            |
| メモ              |
| 下書き            |
| 予定表            |
| 予定表/日本の休日 |
| 予定表/誕生日     |
| 会話の履歴        |
| 削除済みアイテム  |
| 迷惑メール        |
| 送信トレイ        |
| 送信済みアイテム  |
| 連絡先            |

# 許可
ここまでくれば後は接続するだけです。`M-x gnus`で起動しましょう。minibufferに`Enter the code youer browser displayed:`というメッセージが表示され、ブラウザが起動します。接続許可の画面が以下のように出ます。

![許可1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555574/51f6c82d-4113-6bb6-0ccf-2c888d00d82b.png)

![許可2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555574/06a1ee1f-9f06-b374-6d81-72441fe8c4b5.png)

ここで許可すると先に説明したリダイレクトURIの画面になります。真っ白になるのでびっくりしないでください。CODE=の横をコピペしてminibufferに入力すればOAuth2認証完了です。

![許可3](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555574/42908636-1b89-1030-4b40-5077847f3824.png)

# 問題の修正1 Gmail以外でSMTP認証のアクセストークン切れが発生した場合
アクセストークン切れでメール送信を行った場合、問題があることが分かりました。<a href="https://qiita.com/waiseiningenchokon/items/faca52752c2f78284ecd">こちら</a>で修正しましたので、申し訳ありませんが参照してください。ついでにドキュメント内のtypoなども修正しました。

# あとがき

昔、新世紀エヴァンゲリオンの考察同人誌というのを読んだことがあって、”あとがき”みたいな部分に、”この本を書く上でいろいろなことを調べた(死海文書?とか)。異論や反論があるなら、最低限自分と同じレベルの調査を行ってからじゃないと聞く耳持たない。”というようなことが書いてあって同人誌っていうのは凄い世界だなぁと思いました。