OAuth2の認証よる0365メール受信の必要があり、ネットで手法を探したのですがなかなかうまくいかず、思考錯誤の結果下記の手法に落ち着きました。
概要図にもあるように、認証はpythonで行いメール受信をOAuth2対応のFetchMail7で、この受信したメールをメールサーバ(devocot)
に保存させ、そのメールサーバにPop3でphpで受信させる手法となってます。
<概要図>
<利用インフラ>
OS:centOS7.7
php:php7
<ソフトウェア>
fetchmail7
devocot
python3.9
それでは実装手順を記載していきます。
<設定の流れ>
・OS上の準備
・pythonのインストール
・token取得とプログラム作成
・fetchmail7のインストールと設定
・dovecotのインストールと設定
・php受信プログラムへの反映
OS上の準備
・受信するユーザを作成によりメール受信BOXのフォルダーが生成、OSのアップデート
# groupadd グループ名
# useradd -g グループ名 アカウント名
# passwd アカウント名
********
********
//受信BOXのフォルダーの権限変更
# chmod 600 /var/mail/sis
//OSのupdate
# yum update
pythonのインストールと準備
・インストール済みのpythonのアンイストール、必要ツールとpythonのインストール
//python3 のアンインストール
# yum erase python
# yum erase python3
//opensslのインストール
# cd /root
# wget --no-check-certificate https://www.openssl.org/source/openssl-1.1.1k.tar.gz
# tar zxvf openssl-1.1.1k.tar.gz
# cd openssl-1.1.1k
# ./config --prefix=/usr/local/openssl-1.1 shared zlib
# make //5分ほど
# make install //5分ほど
# cd ..
//ツールのインストール
# yum groupinstall "Development Tools" -y
# yum install openssl-devel libffi-devel bzip2-devel -y
//pythonのインストール
# wget https://www.python.org/ftp/python/3.9.2/Python-3.9.2.tgz
# tar xvf Python-3.9.2.tgz
# cd Python-3.9.2
# ./configure
# make 10分ほど
# make altinstall
# cd ..
//pipのアップデート
# /usr/local/bin/python3.9 -m pip install --upgrade pip
# pip3.9 install o365
v# i /usr/local/lib64/python3.6/site-packages/O365/connection.py
420行目ぐらいを下記のようにコメントアウトを記述しリダイレクト先を記述する
#self.oauth_redirect_url = 'https://login.microsoftonline.com/common/oauth2/nativeclient'
self.oauth_redirect_url = 'https://ドメインもしくはIPアドレス/PHPMailer/get_oauth_token.php'
//pipのモジュールインストール
# pip3.9 install urllib3==1.26.6
# python3.9 /root/oauth2/sis/get_token.py
//トークンの格納先作成
# mkdir /root/oauth2
# mkdir /root/oauth2/アカウント名
token取得プログラム作成
<サンプルプログラム> get_token.py コピペして記述変更してください。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# BSD 2-clause
from O365 import Account, MSGraphProtocol, FileSystemTokenBackend
# TENANT等の各IDは環境に合わせ記述変更ください。
TENANT_ID = '****7558-3**5-48**-**ac-0809******a6'
CLIENT_ID = '****7f62-9c16-49e9-b5f4-******921bd1'
CLIENT_SECRET = '****Q~v2VSq.ZF9z*****E_1b******~OTJ9J**P'
TOKEN_FILENAME='token.json'
TOKEN_PATH='.'
AUTH_FLOW='authorization'
SCOPES = ['offline_access', 'https://outlook.office365.com/POP.AccessAsUser.All', 'https://outlook.office365.com/IMAP.AccessAsUser.All', 'https://outlook.office365.com/SMTP.Send']
token_backend = FileSystemTokenBackend(token_path=TOKEN_PATH, token_filename=TOKEN_FILENAME)
credentials=(CLIENT_ID, CLIENT_SECRET)
account = Account(credentials=credentials, scopes=SCOPES, token_backend=token_backend, auth_flow_type=AUTH_FLOW, tenant_id=TENANT_ID)
if not account.is_authenticated:
account.authenticate()
print('Authenticated!')
else:
account.connection.refresh_token()
print('Refreshed!')
with open('access_token', mode='w') as f:
f.write(token_backend.get_token()['access_token'])
<解説>
下記を環境に合わせ記述を変更
8行目 TENANT_ID = 'テナントID'
9行目 CLIENT_ID = 'クライアントID'
10行目 CLIENT_SECRET = 'クライアントシークレット値'
/root/oauth2/アカウント名 直下にget_token.pyを配置する
tokenの生成
//トークンの生成(初期化) ※最初は処理は必須
# cd /root/oauth2/アカウント名
# python3.9 ./get_token.py
Visit the following url to give consent:
https://login.microsoftonline.com/****7558-3**5-48**-**ac-0809******a6/
oauth2/v2.0/authorize?response_type=code&client_id=****7f62-9c16-49e9-
b5f4-******921bd1&redirect_uri=https%3A%2F%2F10.47.128.13%2FPHPMailer
%2Fget_oauth_token.php&scope=https%3A%2F%2Foutlook.office365.com%2FSMTP
.Send+https%3A%2F%2Foutlook.office365.com%2FPOP.AccessAsUser.All+offline_access
+https%3A%2F%2Foutlook.office365.com%2FIMAP.AccessAsUser.All&state
=gw**********ptiQ7WgdcMasbpX7DX0g&access_type=offline
Paste the authenticated url here:
このように表示されます。
この表示されたURL
https://login.microsoftonline.com/ 〜 &access_type=offline までを
コピーして任意のパソコンのブラウザのアドレス欄にペーストして接続します。
接続後リダイレクトされブラウザのアドレス欄に新しいURLが表示されます。
この新しくリダイレクトされたURLをコピーして
Paste the authenticated url here: にペーストすると下記にように認証されます。
Authentication Flow Completed. Oauth Access Token Stored. You can now use the API.
Authenticated!
/root/oauth2/アカウント名 配下にaccess_token、token.jsonが生成されます。
//crontabを設定 ※10分毎にtokenの更新を行う。
9,19,29,39,49,59 * * * * root cd /root/oauth2/アカウント名/; python3 get_token.py > /dev/null 2>&1
<解説>
初回ブラウザ認証時にマイクロソフトから0365の認証確認がります。その際はテナントIDに属しているID(例:操作者のアカウント)でもOKです。
もし、TENANT_IDやCLIENT_ID、CLIENT_SECRETの記述に間違いがあると0365の認証もないままマイクロソフト社によりアラートが表示されます。
認証が通った場合でも下記のPHPのエラーが表示される場合がありますがこれは認証に問題ありません。無視してください。
PHPMailerのget_oauth_token.phpのエラーです。認証のリダイレクトが受け取れるかどうかだけを見ているようです。
fetchmailのインストール
//ツールautoconf-2.71インストール
# cd /root/oauth2
# wget --no-check-certificate https://ftp.gnu.org/gnu/autoconf/autoconf-2.71.tar.gz
# tar zxvf autoconf-2.71.tar.gz
# cd autoconf-2.71
# ./configure
# make
# make install
# cd /root/oauth2
//ツールbison3.8をインストール
# wget --no-check-certificate https://ftp.gnu.org/gnu/bison/bison-3.8.tar.gz
# tar zxvf bison-3.8.tar.gz
# cd bison-3.8
# ./configure
# make
# make install
# cd /root/oauth2
//fetchmail7のインストール
# git clone https://gitlab.com/fetchmail/fetchmail.git
# cd fetchmail
# git checkout next
# ./autogen.sh
# ./configure --with-ssl=/usr/local/openssl-1.1
# make
# make install
# cd /root/oauth2
/root の直下に.fetchmailrc7 を作成
記述内容は環境に合わせサンプルファイルの記述を変更する
※サンプルファイル、証明書は下記に記述
/root/.fetchmailrc7 のパーミッションを700に変更
# chmod 700 /root/.fetchmailrc7
・証明書を下記フォルダーに配置
/root/oauth2/fetchmail/certs
ca.pem
DigiCertGlobalRootCA.crt.pem
o365.pem
//Fetchmail7起動
# /usr/local/bin/fetchmail -f /root/.fetchmailrc7
※下記警告がでますが問題なく稼働しております。無視でいいかと思われます。
12月 19 14:54:16 fetchmail: 警告: root アカウントでの実行はお勧めできません。
fetchmail:/root/.fetchmailrc7:24: アカウント WARNING: ssl is obsolescent. Pleas use tlsmode wrapped instead. , サーバ ssl
fetchmail: unable to access /root/oauth2/アカウント名/access_token: そのようなファイルや ディレクトリはありません
※重要:サーバを再起動した場合、自動でFetchmail7起動できません。(OSに登録できなできない)
# /usr/local/bin/fetchmail -f /root/.fetchmailrc7 //都度コマンドで起動のこと
//起動確認
# ps -aux
/root/oauth2/fetchmail/fetchmail -f /root が表示されていればOK
設定ファイル作成
<サンプルプログラム> .fetchmailrc7 コピペして記述変更してください。 ファイル名先頭の.忘れずに
set daemon 600 # 600秒間隔でメールチェックを行なう
set postmaster root # 最終的なメールの送信先
set no bouncemail # エラーメールをpostmasterに送る
set syslog
# 全サーバー共通デフォルト設定
defaults
bad-header accept # ヘッダ異常のあるメールも取り込む
protocol auto
uidl
no mimedecode
no flush
no fetchall # 未読メールのみ取り込む場合
#fetchall # 既読・未読にかかわらず全てのメールを取り込む場合
keep # 取り込んだメールをサーバー上に残しておく場合
fetchsizelimit 0
# プロバイダアカウント宛メール取り込み設定※POP3Sが提供されている場合
poll outlook.office365.com # プロバイダ受信メールサーバー名
protocol pop3
port 995
auth oauthbearer username メールアカウント
passwordfile /root/oauth2/アカウント名/access_token
is sis here keep
ssl
sslcertck
sslcertpath '/root/oauth2/fetchmail/certs'
<解説>
このファイルはfetchmailの受信するアカウントの設定ファイルです。このファイルを/rootの配下に配置して下さい。
/root/.fetchmailrc7 のパーミッションを700に変更
# chmod 700 /root/.fetchmailrc7
dovecotのインストール
//dovecotのインストール
https://www.sakura-vps.net/centos7-setting-list/dovecot-settings-for-sakura-vps-centos7/に従い設定
# yum -y install dovecot
各設定ファイルの編集
/etc/dovecot/dovecot.conf 編集
/etc/dovecot/10_mail.con 編集
10_mail.confのみ下記追加で設定(32行目)
mail_location = mbox:~/mail:INBOX=/var/mail/%u
/etc/dovecot/10-auth.conf
/etc/dovecot/10-ssl.conf
dovecotの起動と自動起動設定
# systemctl start dovecot
# systemctl enable dovecot
firewallの設定
# firewall-cmd --permanent --zone=public --add-port=25/tcp
# firewall-cmd --permanent --zone=public --add-port=587/tcp
# firewall-cmd --permanent --zone=public --add-port=110/tcp
# firewall-cmd --permanent --zone=public --add-port=143/tcp
# firewall-cmd --reload
受信プログラム
このあとは、本サイトの
メール受信に従ってdovecotよりメール受信できます。
<変数・定数(メールアカウント)>
$mail_host = 'dovecotをインストールしたサーバドメインもしくはIPアドレス';
//利用している送信サーバを指定
$port = "995"; //ポート番号
$user = 'OSの準備で設定したアカウント名@sample.jp'; //認証ユーザアドレス
$pass = 'OSの準備で設定したパスワード'; //認証ユーザパスワード
$pop = new Net_POP3();
既知の不具合と対処について
不具合事象として、認証がうまくできないことがあります。原因は不明です。その際fatchmailがo365の認証ができないとアラートメールが送信されます。
このメールはdovecotのメールBOXに登録されるのでこのアラートメールはPHPで受信ができます。
・エラーメール件名
fetchmail authentication failed
この件名のメールが受信された場合、認証エラーとして識別できるようプログラムを作っていくことが必要です。
・対処方法
認証の初期化を行います。認証トークン(access_token、token.json)を削除します。
# cd /root/oauth2/アカウント名
# rm -f access_token token.json
次に、tokenの生成に記載されている同様の作業により認証トークン(access_token、token.json)を生成します。
これにより認証トークンが初期化され受信が再開されます。