Managed Service Column <システム運用コラム>

Emacs + mew でIMAP認証をOAuth2で行いMicrosoft 365のメールを読む方法

Category: 実践編

2022.11.22

はじめに

メールサーバ機能を Gmail や Microsoft 365 などの外部のサービスを用いて実現している企業は多いかと思います。当社でも、以前は自前でメールサーバを構築・運用していたのを Microsoft 365 の導入をきっかけに、メールサーバ機能もそちらに移すことになりました。

メーラーに関しては各自が好きなものを使っており、元々 UNIX/Linux 系の技術者が多い当社では、emacs + mew でメールを読み書きしている人もいます。

そのような中、Microsoft のセキュリティ強化の一環で 2022年10月より、Microsoft 365 のメールサーバへのアクセスには、OAuth2認証が必須となりました。Outlook 等では元々 OAuth2 認証なので何も気にすることはないのですが、UNIX 系のメーラーでは OAuth2 認証に対応させる必要があります。

ここでは、emacs + mew にて IMAP の認証を OAuth2 で行い、Microsoft 365 のメールサーバにアクセスするために行った設定方法についてまとめてみます。

Emacs + mew で IMAP 認証を OAuth2 で行い Microsoft 365 のメールを読むために必要なもの

すでに emacs + mew で LOGIN 形式の認証で IMAP によるメールは読めているとします。この状態から、新たに認証方式を OAuth2 に変更して Microsoft 365 のメールを読むために必要となるものを用意していきます。

Microsoft 365 における OAuth2 認証フローに関しては以下に詳細説明があります。

https://learn.microsoft.com/ja-jp/azure/active-directory/develop/v2-oauth2-auth-code-flow

emacs + mew

ここで、”Native App” に該当するものが emacs + mew です。

初回の認証には JavaScript が動作するブラウザを用いて /oauth2/v2.0/authorize に対して authorization code を要求する必要があります。また、 /oauth2/v2.0/authorize からのリダイレクトURLにおいて authorization code を受け取る必要があります(以下の赤枠の部分)。

emacs + mew

UNIX/Linux に X-Window を利用してログインしている場合は UNIX/Linux 上で firefox 等のブラウザを起動できますが、Windows PC などから teraterm や putty 等を使って ssh でリモートからテキストベースでのログインをしている場合は、手元の PC のブラウザを利用したくなります。

テキストベースのログインの場合、emacs 上で eww 等のテキストブラウザはありますが、 JavaScript が動作しないため、 OAuth2 の認証には利用できません。そこで、ここでは、初回認証(上記赤枠の処理)に手元の PC のブラウザが利用できるような工夫もします。

一通り必要なものをまとめると次の通りとなります。

  • 手元の PC のブラウザを用いて初回認証を行い、emacs へ authorization code のコピーを簡単にできる環境(プログラム)の準備
  • Azure AD アプリの設定
  • OAuth2 認証に対応した mew のインストールとその設定

これらの設定方法を順番に見ていきます。

手元の PC のブラウザを用いて初回認証を行い、emacs へ authorization code のコピーを簡単にできる環境(プログラム)の準備

用意するのは、

  • authorization code をリクエストするために使うプログラム
  • authorization code を受け取るために使うプログラム

の2種類です。以下にこれらを php で実装したものを掲載します。

authorization code をリクエストするためのプログラム

これは、次の2つから成ります。

  • request-auth.php

    手元 PC のブラウザからアクセスすべき URL を、emacs の(テキスト)ブラウザで emacs 上に表示するためのスクリプト

  • delegate-auth.php

    PC のブラウザにて Microsoft の authorization code 要求用 URL へアクセスさせるためのスクリプト

それぞれのコードは次の通りです。

request-auth.php:


<?php

$AUTHURL = "https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize";

print "<html><body>\n";

if ($_GET['client_id'] != "" && $_GET['response_type'] != "" && $_GET['scope'] != "") {
    $access_url = $AUTHURL . "?";
    foreach($_GET as $name => $value) {
        $access_url .= "$name=" . urlencode($value) . "&";
    }
    $access_url = rtrim ($access_url, "&");
    $pid = getmypid();
    print "Emacs で OAuth2 を利用する際の Authorization コードを取得します。
<br>\n"; print "以下の URL に手元のブラウザからアクセスしてください。<br>\n"; print "http://wwwhost.ns.rworks.jp/oauth2/delegate-request.php?p=$pid"; file_put_contents("/tmp/oauth-url." . $pid, $access_url); } else { print "エラー: リクエストが不正です。\n"; } print "</body></html>\n"; ?>

delegate-auth.php:


<?php
print "<!doctype html>\n";
print "<html lang=\"ja\">\n";
print "<head>\n";
print "  <meta charset=\"UTF-8\">\n";
print "  <title>OAuth2 Authorization コードリクエスト</title>\n";
print "</head>\n";
print "<body>\n";

if ($_GET['p'] != "") {
    $url_file = "/tmp/oauth-url." . $_GET['p'];
    if (file_exists($url_file)) {
        $url = file_get_contents($url_file);
        print "<p>以下にアクセスしてください。</p>\n";
        print "<a href=\"";
        print $url;
        print "\">Authorization コードリクエスト</a>\n";
        unlink($url_file);
    } else {
        print "<p>エラー: リクエスト URL を取得できませんでした。もう一度やり直 してください。</p>\n";
    }
} else {
    print "エラー: リクエストが不正です。\n";
}

print "</body></html>\n";
?>

authorization code を受け取るためのプログラム

これは、get-auth.php というスクリプトで、Microsoft のサイトからリダイレクトされた際に、authorization code を取得して、手元の PC のクリップボードにそれを簡単にコピーできるようにするものです。以下に内容を掲載します。

<?php
$AUTHURL = "https://login.microsoftonline.com/organizations/oauth2/v2.0/authoriz

print "<html><body>\n";

if ($_GET['error'] == '') {
    $code = $_GET['code'];
    if ($code == "" ) {
        print "エラー: Authorization コードを取得できませんでした。\n";
    } else {
        print "次の Authorization コードを Emacs にコピーしてください。<br>\n";

        print '<input id="copyTarget" type="text" size="120" value="';
        print $code;
        print '" readonly>';
        print '<button onclick="copyToClipboard()">クリップボードにコピー</button>';
        print "\n";
    }
} else {
    print "エラー: 認証できませんでした。\n";
}
print "</body></html>\n";
?>

<script type="text/javascript">

function copyToClipboard() {
    var copyTarget = document.getElementById("copyTarget");
    copyTarget.select();
    document.execCommand("Copy");
    alert("コピーしました: " + copyTarget.value);
}
</script>

以上、3つのファイルを php プログラムが動作するように設定された https (SSL) でアクセスできるウェブサイト上に配置します。Microsoft からリダイレクトされる先は https である必要があり、http では動作しません。

なお、配置するウェブサイトは、認証に利用する PC(ブラウザ) からアクセスできる場所でありさえすれば組織内に閉じたネットワーク上でも問題はなく、インターネット上に公開されたウェブサイトである必要はありません。また、SSL サーバ証明書は自己証明書でも問題ありません。

例えば、DocumentRoot 以下に oauth2 というディレクトリを作成して、その下に 3つのファイルを置いても良いでしょう。


<DocumentRoot>/oauth2/request-auth.php
<DocumentRoot>/oauth2/delegate-auth.php
<DocumentRoot>/oauth2/get-auth.php

例えば、ドメインが example.com の場合、それぞれのアクセス URL は次のようになります。

https://example.com/oauth2/request-auth.php
https://example.com/oauth2/delegate-auth.php
https://example.com/oauth2/get-auth.php

これらの URL は、後述の「Azure AD アプリの設定」や、「OAuth2 認証に対応した mew のインストールとその設定」で必要になります。 なお、ここで紹介したスクリプトを配置したウェブサーバは、組織内に 1つあれば十分です。Emacs + mew を利用するユーザが複数いたとしてもユーザごとに準備する必要はありません。

Azure AD アプリの設定

Microsoft 365 側では、Mew からの認証要求に応えるための設定が必要です。それには Microsoft 365 から提供される Azure AD にて、次の手順で Mew の OAuth2 認証に用いるアプリの登録を行います。

  1. Azure portal(https://portal.azure.com/)に Microsoft 365 アカウントでログイン
  2. "Azure Active Directory" をクリック
  3. “アプリの登録” をクリック
  4. "新規登録" をクリックし、アプリを作成。名前は任意のもので大丈夫ですが、ここでは、"Mew IMAP OAuth2" としました。
  5. "認証" メニューから、"リダイレクト URL" に authorization code をコピーするためのプログラムを配置する URL を追加(赤枠の部分)。前述の「手元のPCのブラウザを用いて初回認証を行い、emacs へ authorization code のコピーを簡単にできる環境(プログラム)の準備」の例に従うと、https://example.com/oauth2/get-auth.php となります。
  6. Azure ADアプリの設定
  7. "次のモバイルとデスクトップのフローを有効にする" を "はい" に設定(赤枠の部分)
  8. Azure ADアプリの設定
  9. "API のアクセス許可" メニューから、Microsoft Graph 配下の以下を追加(赤枠の部分)
  • IMAP.AccessAsUser.All
  • offline_access
  • POP.AccessAsUser.All
  • SMTP.Send
  • User.Read
Azure ADアプリの設定

以上で、Azure AD でのアプリの登録は完了です。

アプリの登録が完了したら、”概要” をクリックして、”アプリケーション (クライアント) ID” を控えておきます(赤枠の部分)。このIDは、後述の「OAuth2 認証に対応した mew のインストールとその設定」で利用します。

Azure ADアプリの設定

なお、アプリの登録は、ユーザごとに行う必要はなく組織で1つ行えば問題ありません。組織内に emacs + mew を使うユーザが複数いる場合は、一つの ”アプリケーション (クライアント) ID” を全ユーザで利用します。

OAuth2 認証に対応した mew のインストールとその設定

Mew および oauth2.el のインストール

Mew は公式には OAuth2 認証に対応していませんが、OAuth2 対応パッチが作成されており、以下から OAuth2 対応の mew をダウンロードできます。

https://github.com/yoshinari-nomura/Mew/tree/mew-support-xoauth2

“mew-support-xoauth2” というブランチのソースをダウンロードします。

ダウンロードしたソースから emacs を動かすUNIX/Linux マシンに次のようにインストールします。ここでは、インストール先を /usr/local/mew-oauth2 としました。


cd <ソースを展開したディレクトリ>
./configure --prefix=/usr/local/mew-oauth2
make
make install

続いて、oauth2.el をインストールします。以下から入手できますが、emacs で一般的な ELPA のからのインストール操作を行い、自身の環境にインストールすれば ok です。

https://elpa.gnu.org/packages/oauth2.html

Mew の OAuth2 認証設定

最後に Mew の設定を行います。 .emacsに次のような設定を行います。


(setq browse-url-browser-function 'eww-browse-url)

;;  Mew definition
(setq load-path
      (append '("/usr/local/mew-oauth2/share/emacs/site-lisp/mew")
              load-path))

(autoload 'mew "mew" nil t)
(autoload 'mew-send "mew" nil t)

(setq mew-config-alist
      '(
        (default
          (mew-imap-auth-list '("XOAUTH2"))
         (imap-server "outlook.office365.com")
         (imap-ssl t)
         (imap-ssl-port 993)
         (imap-user "XXX@example.com") ←自分のメールアドレス
         (name "XXXXXXX") ←自分の名前
         (mail-domain "example.com")
         )
))

(setq mew-ssl-verify-level 0)

;; OAuth2
(setq mew-auth-oauth2-client-id "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
(setq mew-auth-oauth2-client-secret nil)
(setq plstore-cache-passphrase-for-symmetric-encryption t)
(setq epa-file-cache-passphrase-for-symmetric-encryption t)
;(setq epa-pinentry-mode 'loopback)

(setq mew-auth-oauth2-auth-url "https://example.com/oauth2/request-auth.php")
(setq mew-auth-oauth2-token-url 
"https://login.microsoftonline.com/organizations/oauth2/v2.0/token") (setq mew-auth-oauth2-resource-url "openid offline_access
https://outlook.office.com/IMAP.AccessAsUser.All
https://outlook.office.com/POP.AccessAsUser.All
https://outlook.office.com/SMTP.Send") (setq mew-auth-oauth2-redirect-url "https://example.com/oauth2/get-auth.php")

ポイントとなる設定は次の通りです。

  • load-path
    OAuth2 対応 Mew をロードパスに追加しています。
  • mew-config-alist 内での mew-imap-auth-list '("XOAUTH2") の定義
    OAuth2認証を利用する設定です。
  • mew-auth-oauth2-client-id
    あらかじめ Azure AD 上に登録しておいた Mew の OAuth2 認証用のアプリの “アプリケーション (クライアント) ID” を指定します。
  • mew-auth-oauth2-client-secret
    Microsoft 365 へのアクセスでは secret は使用しません。必ず nil に設定します。
  • plstore-cache-passphrase-for-symmetric-encryption からの 3行
    Auth2 認証の token を Emacs でキャッシュさせるために必要なものです。なお、epa-pinentry-mode の定義は gpg1 系の場合は不要です。
  • mew-auth-oauth2-auth-url
    Authorization コードを取得するために、手元のブラウザでのアクセスに誘導するための URL です。前述の「手元のPCのブラウザを用いて初回認証を行い、emacs へ authorization code のコピーを簡単にできる環境(プログラム)の準備」の例に従うと、https://example.com/oauth2/request-auth.php です。
  • mew-auth-oauth2-resource-url
    メールアクセスの際に、Microsoft 365 のどのリソースへのアクセス許可を求めるかの設定です。
  • mew-auth-oauth2-redirect-url
    OAuth2 認証の Authorization code を取得し、手元の PC のクリップボードへそれをコピーするための URL です。前述の「手元のPCのブラウザを用いて初回認証を行い、emacs へ authorization code のコピーを簡単にできる環境(プログラム)の準備」の例に従うと、https://example.com/oauth2/get-auth.php です。

以上で、一通りの事前準備は完了です。

OAuth2 認証を用いてメールを読む(初回アクセス)

事前準備が完了したら、いよいよ emacs + mew による OAuth2 認証での初回 IMAP アクセスを行います。

Emacs から M-x mew で Mew を起動します。すると、次のように Authorization code を取得するための URL が表示されます(赤枠の部分)。

OAuth2認証を用いてメールを読む(初回アクセス)

このURLを手元のブラウザからアクセスします。次のような画面が表示されるので、”Authorizationコードリクエスト” をクリックします。

OAuth2認証を用いてメールを読む(初回アクセス)

次のような画面に遷移し、Authorization code が表示されます。”クリップボードにコピー” (赤枠の部分)をクリックすると、Authorization code を手元 PC のクリップボードにコピーできます。

OAuth2認証を用いてメールを読む(初回アクセス)

Emacs の画面に戻り、取得した Autorization code を “Enter the code your browser displayed: “ の部分にペーストします(赤矢印の部分)。

OAuth2認証を用いてメールを読む(初回アクセス)

続いて、Emacs が Authorization code を暗号化して保存する際のパスフレーズを設定します(赤矢印の部分)。任意のパスフレーズで問題ありません。(2回目以降のアクセス(次回以降の emacs + mew の起動)では、こちらのパスフレーズの入力が求められます。)

なお、暗号化した Authorization code は以下に保存されます。


~/.emacs.d/oauth2.plstore
OAuth2認証を用いてメールを読む(初回アクセス)

以上で、Microsoft 365 のメールサーバへ emacs + mew で IMAP アクセスし、OAuth2 認証でメールが読めるようになります。改めて、M-x mew 等でメールのサマリ画面を表示させ、その後 Mew の各種操作ができるはずです。

なお、うまくいかなかった場合は、以下のファイルを削除してから、「OAuth2 認証を用いて メールを読む(初回アクセス)」の手順を最初から実施してみると良いでしょう。


~/.emacs.d/oauth2.plstore
~/.emacs.d/oauth2.plstore~

OAuth2 認証を用いてメールを読む(2回目以降のアクセス)

Emacs + mew 起動後、mew の最初の操作を行った際にパスフレーズを聞かれますので「OAuth2 認証を用いて メールを読む(初回アクセス)」で設定したパスフレーズを入力します。その後は特別な操作なく、いつも通り mew を利用できます。

システム運用個別相談会(無料)

Contactお問い合わせ

お見積もり・ご相談など、お気軽にお問い合わせください。

single.php