OAuth2の認証よる0365メール受信の必要があり、ネットで手法を探したのですがなかなかうまくいかず、思考錯誤の結果下記の手法に落ち着きました。
概要図にもあるように、認証はpythonで行いメール受信をOAuth2対応のFetchMail7を使い、受信したメールをメールサーバ(devocot)に保存させ、
そのメールサーバにPop3でphpで受信させる手法となってます。
<概要図>
<利用インフラ>
OS:almaLinux9.5
※almaLinuxは9.5以上が必須。
php:php8.3
<ソフトウェア>
python3.9
fetchmail7
devocot
postfix
実装手順を記載します。
<設定の流れ>
・OS上の準備
・pythonのインストール
・token取得とプログラム作成
・postfixのインストール
・ssl証明書の入手と配置
・fetchmail7のインストールと設定
・dovecotのインストールと設定
・php受信プログラムへの反映
OS上の準備
・受信するユーザを作成によりメール受信BOXのフォルダーが生成、OSのアップデート
# groupadd グループ名
# useradd -g グループ名 アカウント名
# passwd アカウント名
********
********
//受信BOXのフォルダーの権限変更
# chmod 600 /var/mail/アカウント名 //受信メールはこのファイルに格納されていきます。
//OSのupdate
# yum update
ツールの準備
//automakeのインストール
# dnf install automake
//wgetインストール
# dnf -y install wget
//perlインストール
# dnf install perl
pythonのインストールと準備
pythonにてOAuth2の認証を行います。
・インストール済みのpythonのアンイストール、必要ツールとpythonのインストール
//python3 のアンインストール
# yum erase python
# yum erase python3
//ツールのインストール
# dnf install openssl-devel libffi-devel bzip2-devel -y
# dnf groupinstall "Development Tools"
# gcc --version gccインストール確認
出力例)gcc (GCC) 11.5.0 20240719 (Red Hat 11.5.0-2)
//gccがない場合
# dnf install gcc
//python3.9のインストール
# dnf install python39
# python3 --version バージョン確認
出力例)Python 3.9.19
//pipのアップデート
# curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
# python3 get-pip.py
# yum remove python3-requests
# pip3.9 install o365
# vi /usr/local/lib64/python3.6/site-packages/O365/connection.py
447行目ぐらいを下記のようにコメントアウトを記述しリダイレクト先を記述する
#self.oauth_redirect_url = 'https://login.microsoftonline.com/common/oauth2/nativeclient'
self.oauth_redirect_url = 'https://ドメインもしくはIPアドレス/PHPMailer/get_oauth_token.php'
//oauthlib3.2.0のインストール
# pip install oauthlib==3.2.0
//pipのモジュールインストール
# pip3.9 install urllib3==1.26.6
//トークンの格納先作成
# mkdir /root/oauth2
# mkdir /root/oauth2/アカウント名/
OAuth2認証token取得プログラム作成
<サンプルプログラム> get_token.py
TENANT等の各IDは情シス管理者に確認し環境に合わせ記述変更してください。
#!/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' //テナントIDを記述
CLIENT_ID = '****7f62-9c16-49e9-b5f4-******921bd1' //クライアントIDを記述
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:
このように表示されます。
5〜10行目に表示されたURL https://login.microsoftonline.com/ 〜 &access_type=offline までの7行を
コピーして任意のパソコンのブラウザのアドレス欄にペーストして接続します。
接続後リダイレクトされブラウザのアドレス欄に新しい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分毎にトークンの更新を行う。
1,11,21,31,41,51 * * * * root cd /root/oauth2/アカウント名/; python3 get_token.py > /dev/null 2>&1
<解説>
上記ブラウザ認証時にマイクロソフトから0365の認証確認があります。その際はテナントIDに属しているID(例:操作者のアカウント)でもOKです。
もし、TENANT_IDやCLIENT_ID、CLIENT_SECRETの記述に間違いがあると0365の認証もないままマイクロソフト社によりアラートが表示されます。
認証が通った場合でも下記のPHPのエラーがブラウザに表示される場合がありますがこれは認証に問題ありません。無視してください。
postfixのインストール
# dnf install postfix
/etc/postfix/main.cfの編集 下記を最終行に追記
message_size_limit = 204800000 //200MB
mailbox_size_limit = 10000000000 //メールBOXのファイルサイズ(重要)10GB
//過去のメール受信で容量オーバー時配信不能メールが送信される。
//受信するメールBOXのサイズに合わせて設定
# systemctl start postfix //サービスの起動
# service postfix reload //設定の適用 設定変更時
# systemctl enable postfix //サービスの自動起動設定
ssl証明書の入手と配置
fetchmailが利用するssl証明書(o365、DigiCertのルート、DigiCertのグローバルルートCA)が必要となります。
<入手>
・o365
ブラウザよりhttps://outlook.office365.com/にアクセスしサインインを行う。
https://outlook.office365.comにリダイレクトされ自分のメールが表示されます。
表示後、URLの直ぐ左にある「サイト情報を表示」のアイコンをクリックしここから証明書をエキスポートします。
「この接続は保護されてます」ー「証明書は有効です」ータブ「詳細」を順にクリック
証明書フィールドの下段(下から2段目)の「証明書」をクリックしフィールド値を表示させます。
その下の「エクスポート(X)」ボタンのクリックによりダウンロードできます。
ダウンロードされたファイル名を識別しやすいようにoutlook.comをo365.pemに変更します。(ファイル名は任意)
・DigiCertのルート
ブラウザよりhttp://cacerts.digicert.com/DigiCertGlobalRootCA.crt をダウンロード
ダウンロードしたファイルをpem形式に変換
openssl x509 -inform der -in DigiCertGlobalRootCA.crt -out DigiCertGlobalRootCA.crt.pe (ファイル名は任意)
・DigiCertのグローバルルートCA
ブラウザよりhttp://cacerts.digicert.com/DigiCertCloudServicesCA-1.crt をダウンロード
ダウンロードしたファイルをpem形式に変換
openssl x509 -inform der -in DigiCertCloudServicesCA-1.crt -out ca.pem (ファイル名は任意)
<証明書の配置>
/root/oauth2/fetchmail/certs/のディレクトリーを作成しこの3つの証明書を配置します。
<証明書のシンボリックを作成>
fecthmailの場合、直接証明書ファイルを見てくれないのでシンボリックを作成します。
シンボリック作成のため下記をインストールします。
# dnf install openssl-perl
# dnf install /usr/bin/c_rehash
# cd /root/oauth2/fetchmail/certs
シンボリック作成コマンド
# openssl rehash /root/oauth2/fetchmail7/certs
# c_rehash シンボリックの反映
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
# make
# make install
# cd /root/oauth2
/root の直下に.fetchmailrc7 を作成
記述内容は環境に合わせサンプルファイルの記述を変更する
※サンプルファイル、証明書は下記に記述
/root/.fetchmailrc7 のパーミッションを700に変更
# chmod 700 /root/.fetchmailrc7
//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)を生成します。
これにより認証トークンが初期化され受信が再開されます。