python-o365 でメール送信

以前は Python で smtplib を使って Microsoft365 からメールを送信していましたが、認証方法が変更になったためにメール送信プログラムを作成したので、記録を残しておきます。

動作環境

だいぶ古いですが今回は Windows Server 2008 R2 で動作確認を行いました。サーバーOSが古い関係でインストールした Python のバージョンも古いです。

  • Windows Server 2008 R2
  • Python 3.7.9
  • Module python-o365

参考にしたページ

今回は以下のページを参考にさせて頂きました。

Azure AD に アプリ登録

この先の操作は管理者権限が必要になりますので、一般の方は組織の管理者にご相談ください。

  1. Azure Active Directory 管理センター に行く
  2. Azure Active Directory を開く
  3. 【アプリの登録】を開く
  4. 【新規登録】を開く
  5. 名前は任意です(例:sendMail365)
  6. アカウントの種類は【この組織ディレクトリのみに含まれるアカウント(シングル テナント)】を選ぶ
  7. リダイレクト URI は この時点では未入力
  8. 【登録】をする
  9. アプリ内に入ったら【統合アシスタント】を開く
  10. 【お客様がビルドしているアプリケーションの種類】は【デスクトップアプリ(Win、Linux、Mac)】を選ぶ
  11. 【アプリの登録を評価する】を押す
  12. 【推奨される構成】で【プラットフォームを追加して、デスクトップ アプリのリダイレクト URI を構成します。】で【操作が必要】となっているので、【…】から【ページへ移動する】を選ぶ
  13. 【プラットフォーム構成】で【プラットフォームを追加】を押す
  14. 【モバイル アプリケーションとデスクトップ アプリケーション】を選ぶ
  15. 【https://login.microsoftonline.com/common/oauth2/nativeclient】を選び【構成】する
  16. 【API のアクセス許可】を開く
  17. 【アクセス許可の追加】を開く
  18. 【API アクセス許可の要求】で【Microsoft Graph】を開く
  19. 【委任されたアクセス許可】を選ぶ
  20. フィルタで「mail」と入力し【Mail.ReadWrite】と【Mail.Send】を選ぶ
  21. フィルタで 「offline」と入力し【offline_access】を選ぶ
  22. 【アクセス許可の追加】を押す
  23. 【統合アシスタント】の概要で状態がすべて【完了】になっていることを確認する
  24. アプリの【概要】に表示されている ディレクトリ (テナント) 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日以内に一度はトークンを更新しないといけませんが、ジョブを登録すれば大丈夫かな。

コメントを残す

メールアドレスが公開されることはありません。

CAPTCHA


コメントする