python-o365 でメール送信
以前は Python で smtplib を使って Microsoft365 からメールを送信していましたが、認証方法が変更になったためにメール送信プログラムを作成したので、記録を残しておきます。
動作環境
だいぶ古いですが今回は Windows Server 2008 R2 で動作確認を行いました。サーバーOSが古い関係でインストールした Python のバージョンも古いです。
- Windows Server 2008 R2
- Python 3.7.9
- Module python-o365
参考にしたページ
今回は以下のページを参考にさせて頂きました。
- GitHub – O365/python-o365: A simple python library to interact with Microsoft Graph and Office 365 API
- python-o365 を使って O365 アクセストークンを取得する
Azure AD に アプリ登録
この先の操作は管理者権限が必要になりますので、一般の方は組織の管理者にご相談ください。
- Azure Active Directory 管理センター に行く
- Azure Active Directory を開く
- 【アプリの登録】を開く
- 【新規登録】を開く
- 名前は任意です(例:sendMail365)
- アカウントの種類は【この組織ディレクトリのみに含まれるアカウント(シングル テナント)】を選ぶ
- リダイレクト URI は この時点では未入力
- 【登録】をする
- アプリ内に入ったら【統合アシスタント】を開く
- 【お客様がビルドしているアプリケーションの種類】は【デスクトップアプリ(Win、Linux、Mac)】を選ぶ
- 【アプリの登録を評価する】を押す
- 【推奨される構成】で【プラットフォームを追加して、デスクトップ アプリのリダイレクト URI を構成します。】で【操作が必要】となっているので、【…】から【ページへ移動する】を選ぶ
- 【プラットフォーム構成】で【プラットフォームを追加】を押す
- 【モバイル アプリケーションとデスクトップ アプリケーション】を選ぶ
- 【https://login.microsoftonline.com/common/oauth2/nativeclient】を選び【構成】する
- 【API のアクセス許可】を開く
- 【アクセス許可の追加】を開く
- 【API アクセス許可の要求】で【Microsoft Graph】を開く
- 【委任されたアクセス許可】を選ぶ
- フィルタで「mail」と入力し【Mail.ReadWrite】と【Mail.Send】を選ぶ
- フィルタで 「offline」と入力し【offline_access】を選ぶ
- 【アクセス許可の追加】を押す
- 【統合アシスタント】の概要で状態がすべて【完了】になっていることを確認する
- アプリの【概要】に表示されている ディレクトリ (テナント) ID と アプリケーション(クライアント)ID をメモする
インストール
Python のモジュールをインストールします。
pip install O365
以下の sendMail365.py を適当なディレクトリーに配置します
プログラム内の tenantID と clientID にメモした内容を貼り付ける
messageSubject、messageFrom、saveDir などは状況に合わせて調整する
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import logging
from O365 import Account, MSGraphProtocol, FileSystemTokenBackend
tenantID = '99999999-9999-9999-9999-999999999999' # ディレクトリ (テナント) ID
clientID = '99999999-9999-9999-9999-999999999999' # アプリケーション(クライアント)ID
clientSecret = '' # 空文字のまま
messageSubject = '件名' # 件名
messageFrom = 'example@example.jp' # 送信者
saveDir = 'C:/temp' # トークン保存場所
tokenFile = 'token365.txt' # トークンファイル名
logFile = saveDir + '/sendMail365.log'
logFormat = '{asctime} [{levelname:.4}] {message}'
logLevel = logging.INFO
# 引数を取得
args = sys.argv
fileName = args[1] # ファイル名
messageTo = args[2] # 送信先
logging.basicConfig(format=logFormat, filename=logFile, level=logLevel, style='{')
logging.info('fileName = ' + fileName + ' messageTo = ' + messageTo)
# 本文の読み込み
fp = open(fileName, encoding='utf-8')
messageBody = fp.read()
fp.close()
# Microsoft 365 認証
credentials = (clientID, clientSecret)
token_backend = FileSystemTokenBackend(token_path=saveDir, token_filename=tokenFile)
account = Account(credentials=credentials, token_backend=token_backend, tenant_id=tenantID)
if not account.is_authenticated:
rtn = account.authenticate(scopes=['basic', 'message_all'])
logging.info('Authenticate: ' + str(rtn))
else:
rtn = account.connection.refresh_token():
logging.info('Refresh: ' + str(rtn))
# メッセージ送信
if rtn:
m = account.new_message()
m.to.add(messageTo)
m.sender.address = messageFrom
m.subject = messageSubject
m.body = messageBody
sts = m.send()
logging.info('Send: ' + str(sts))
プログラムで認証する(初回のみ)
UTF8 で作成したメールの本文 test.txt を用意して、example@example.com に送信するコマンドは次の通りになります。example@example.com は受信可能なメアドに読み替えて実行する。
python sendMail365.py test.txt example@example.com
プログラムを実行すると画面に「Visit the following url to give consent:」と表示されて、認証用のURLが表示されますので、コピーしてブラウザで開く。
組織の管理者権限でアカウントの認証を進めると「要求されているアクセス許可」が表示される。
「組織の代理として同意する」をチェックして「承認」する。
ブラウザのURLをコピーして、実行しているプログラムの画面の「Paste the authenticated url here:」に張り付ける。貼り付けたら改行する。
まとめ
python-o365 では、3つの認証方法がありますが、今回はシークレットを使わない方法で作ってみました。90日以内に一度はトークンを更新しないといけませんが、ジョブを登録すれば大丈夫かな。