概要(Teams 通知は「Python からチャネルにメッセージを飛ばす」技)
Teams 通知は、
「Python のスクリプトから、Microsoft Teams のチャンネルに自動でメッセージを送る仕組み」
です。
やりたいことは Slack 通知とほぼ同じで、
- バッチが正常に終わったら「成功しました」と Teams に投稿する
- エラーが起きたら「このバッチが落ちました」と即座に知らせる
- 毎朝の定期レポートを Teams に流す
といった “人間が見ている場所に、コード側から話しかける” ことです。
初心者が迷いがちなポイントは、
- Teams 側でどんな設定が必要なのか
- Python からどうやってメッセージを送るのか
- 実務でどう組み込むのがキレイか
なので、ここを重点的にかみ砕いていきます。
全体像(Python → Teams の流れをざっくりつかむ)
仕組みのイメージ:Incoming Webhook に JSON を投げる
Teams も Slack と同じように、Incoming Webhook という仕組みを提供しています。
構造はシンプルで、
- Teams 側で「このチャンネルに対する Webhook」を設定し、URL を1つ発行する。
- Python から、その URL に対して JSON を HTTP POST する。
これだけです。
Python から見ると、「決まった URL に requests.post で JSON を送るだけ」です。
その JSON の中身の形式(カードの形)は Teams 独自のルールがありますが、
最初はかなりシンプルな形から始めて大丈夫です。
Teams の Incoming Webhook のイメージ(準備側の話)
何が手に入るのかだけ理解しておけばOK
実際のクリック手順はここでは細かく書きませんが、
「何が最終的に必要なのか」だけ押さえれば、あとが理解しやすくなります。
Teams のチャンネルに「Incoming Webhook」を追加すると、
次のような URL が1つ発行されます。
https://outlook.office.com/webhook/....
あるいはhttps://<テナント>/webhook/...
この URL は、
「ここに正しい形式の JSON を POST してくれたら、このチャンネルにメッセージを表示しますよ」
という専用の入り口です。
Python から見れば、
- この URL は “宛先”
- JSON は “メッセージ内容”
- HTTP POST が “投げ方”
というだけです。
この URL は「秘密の入口」なので、後でセキュリティの話もします。
一番シンプルな Teams 通知コードを書いてみる
requests を使った最小サンプル
まずは、余計なことを全部削ぎ落とした「最小の Teams 通知」を見てみましょう。
import requests
import json
TEAMS_WEBHOOK_URL = "https://outlook.office.com/webhook/......" # 実際のURLを設定
def send_teams_message(text: str):
payload = {
"text": text
}
headers = {
"Content-Type": "application/json"
}
resp = requests.post(
TEAMS_WEBHOOK_URL,
data=json.dumps(payload),
headers=headers,
timeout=5
)
resp.raise_for_status()
return resp
if __name__ == "__main__":
send_teams_message("Python から Teams 通知テストです。")
Python行ごとに意味をかみ砕いていきます。
TEAMS_WEBHOOK_URL
Teams で発行した Incoming Webhook の URL を入れます。
ここに向かってメッセージを投げます。
payload = {"text": text}
Teams に送るデータです。
最もシンプルな形として、text フィールドを持つ JSON を送ると、
チャンネルにそのままテキストとして表示されます。
headers = {"Content-Type": "application/json"}
「これから送るのは JSON ですよ」と伝えるヘッダーです。
Teams の Webhook はこのヘッダーを期待しているので、必ず付けます。
requests.post(..., data=json.dumps(payload), headers=headers, timeout=5)
HTTP POST で JSON を送っています。
ここでは json= ではなく data= で明示的に json.dumps していますが、
Teams 側は JSON を文字列として受け取るので、この形が分かりやすいです。timeout=5 は「5秒以上かかったら諦める」というタイムアウトです。
resp.raise_for_status()
もし Teams 側が 400 や 500 系のエラーを返した場合、ここで例外が投げられます。
「通知に失敗した」ことをきちんと検知するために、必ず入れておきましょう。
これだけで、Python から Teams のチャネルに一行メッセージを投稿できます。
自動化バッチに組み込むための形に整える
通知関数を作って、成功時と失敗時で使い分ける
実務で使うなら、「どこからでも呼べる通知関数」として切り出しておくと便利です。
import os
import json
import logging
from pathlib import Path
import requests
BASE_DIR = Path(__file__).resolve().parent
LOG_FILE = BASE_DIR / "batch.log"
TEAMS_WEBHOOK_URL = os.environ.get("TEAMS_WEBHOOK_URL")
def setup_logging():
logging.basicConfig(
filename=LOG_FILE,
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(name)s - %(message)s"
)
def send_teams(text: str):
if not TEAMS_WEBHOOK_URL:
logging.warning("TEAMS_WEBHOOK_URL が設定されていないため、Teams 通知をスキップします。")
return
payload = {"text": text}
headers = {"Content-Type": "application/json"}
try:
resp = requests.post(
TEAMS_WEBHOOK_URL,
data=json.dumps(payload),
headers=headers,
timeout=5
)
resp.raise_for_status()
except Exception as e:
logging.exception(f"Teams 通知の送信に失敗: {e}")
def main():
logging.info("日次バッチ開始")
# ここにメイン処理を書く
# 例: 1 / 0 でわざとエラー
logging.info("日次バッチ正常終了")
if __name__ == "__main__":
setup_logging()
BATCH_NAME = "日次売上集計バッチ"
try:
main()
send_teams(f"[OK] {BATCH_NAME} 正常終了")
except Exception:
logging.exception(f"{BATCH_NAME} で予期せぬ例外")
send_teams(f"[ERROR] {BATCH_NAME} 異常終了。ログを確認してください。")
raise
Pythonこのパターンは、現場でもそのまま使える“定番の形”です。
重要なポイントを深掘りします。
最初に、Webhook URL を環境変数から読んでいること。
URL をソースコードにベタ書きして Git に上げるのは危険なので、TEAMS_WEBHOOK_URL は環境変数で渡すのが安全です(.env や設定ファイルから読むのも可)。
次に、通知関数の中で try/except を入れていること。
Teams 通知自体もネットワークに依存しているので、失敗します。
そのときに、通知エラーのせいで元のバッチの例外情報が隠れないよう、
ここでは logging.exception だけに留めて、本体の例外フローを壊さないようにしています。
最後に、成功と失敗でメッセージを分けていること。
Teams のタイムラインを見たときに、
「どのバッチがいつ成功したのか」「どれが失敗なのか」がひと目で分かるようにするのが大事です。
メッセージ内容を設計する(何を書いておくと助かるか)
「見た瞬間に状況が分かる」情報の組み立て方
通知メッセージには、全部の詳細を書く必要はありません。
むしろ、長すぎると読まれなくなります。
欲しいのは、「何が起きたかを一瞬で理解するための要約」です。
例えば、次のような情報があると便利です。
- バッチ名(何の処理か)
- 環境名(dev / staging / prod)
- 成功なのか、失敗なのか
- 実行開始・終了の時刻
これを踏まえて、メッセージ組み立ての関数を作ってみます。
from datetime import datetime
def build_success_message(batch_name: str, env: str = "prod") -> str:
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
return f"[OK][{env}] {batch_name} 正常終了\n完了時刻: {now}"
def build_error_message(batch_name: str, env: str = "prod") -> str:
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
return f"[ERROR][{env}] {batch_name} 異常終了\n発生時刻: {now}\n詳細はログを確認してください。"
Pythonこうすると、main 側は次のように書けます。
if __name__ == "__main__":
setup_logging()
BATCH_NAME = "日次売上集計バッチ"
ENV = "prod"
try:
main()
send_teams(build_success_message(BATCH_NAME, ENV))
except Exception:
logging.exception(f"{BATCH_NAME} で予期せぬ例外")
send_teams(build_error_message(BATCH_NAME, ENV))
raise
PythonTeams を開いた瞬間に、
- どの環境
- どの処理
- 成否
- 時刻
がすぐに分かるようになります。
詳細(エラー内容)はログと役割分担する
「スタックトレースやエラーメッセージ全部を Teams に流したい」という気持ちは分かりますが、
現場ではあまりおすすめしません。
理由は、
- メッセージが長くなりすぎて見づらい
- チャネルがエラーログで埋まる
- スマホで見ると地獄
だからです。
基本は、
- Teams には「気づきのための要約だけ」
- 詳細なエラー内容やスタックトレースは logging のログファイルで確認
という役割分担にしたほうが、運用が長続きします。
どこまで通知するか(頻度としきい値の考え方)
すべてのエラーを Teams に飛ばすと、すぐに死ぬ
例えば、バッチの中で 1000 レコードを処理していて、
その中の 10 レコードだけ形式がおかしくてスキップしたとします。
この 10 レコードそれぞれで「エラー通知」を飛ばしてしまうと、
チャネルはあっという間にノイズだらけになります。
人間はすぐに慣れてしまい、
- 最初はちゃんと読む
- 次第に「またか」で流し読み
- 最後はミュートして、重大な通知も見なくなる
というパターンに陥ります。
そこで、
- バッチ全体が止まったときだけ ERROR 通知。
- レコード単位の失敗はログにのみ記録。
- 失敗件数があるしきい値を超えたら Warning 通知。
といったルールを決めると良いです。
しきい値ベースの Teams 通知例
例えば、「API 失敗が 10 件以上あったら注意喚起したい」というケース。
ERROR_THRESHOLD = 10
def run_batch():
error_count = 0
for uid in user_ids:
try:
fetch_user(uid)
except Exception:
logging.exception(f"ユーザー情報取得エラー: user_id={uid}")
error_count += 1
if error_count >= ERROR_THRESHOLD:
send_teams(f"[WARN] ユーザー情報取得エラーが多発しています: {error_count}件")
Pythonこれで、
- 1〜2件の偶発的な失敗 → ログのみ
- 10件以上の異常な失敗 → Teams に Warning 通知
というメリハリがつきます。
セキュリティと堅牢性で気をつけるポイント
Webhook URL は「パスワードと同じ扱い」にする
Teams の Webhook URL が漏れると、
その URL を知っている誰でも、そのチャンネルに勝手に投稿できてしまいます。
なので、
- ソースコードに直書きしない
- GitHub など公開リポジトリに絶対含めない
- 共有するときは環境変数や設定ファイル経由にする
といった配慮が必要です。
初心者でもすぐできる対策は、
Python 側では os.environ.get("TEAMS_WEBHOOK_URL") のように環境変数から読む。
各環境(ローカル・テスト・本番)の設定は OS 側に持たせる。
という形です。
通知処理が「本体のエラー」を上書きしないようにする
通知処理も I/O を含むので、
Teams 側の障害やネットワーク不良で失敗することがあります。
このときにやってはいけないのは、
通知で起きた例外が、元の本番処理の例外を隠してしまうこと
です。
先ほどのコードのように、
- 本体の例外は、トップレベルで logging.exception+raise
- Teams 通知の中では try/except し、失敗はログにだけ残す
という二段構えにしておくと、
少なくとも「元のエラー原因はログで追える」状態を保てます。
まとめ(Teams 通知は「自動化とチームをつなぐ声」)
Python 自動化における Teams 通知の要点を整理すると、こうなります。
Teams 通知は、Python スクリプトから Teams チャンネルにメッセージを飛ばす仕組みで、バッチの成功・失敗やレポート配信と相性が良い。
Incoming Webhook を使えば、「発行された Webhook URL に JSON を POST するだけ」でメッセージを送れる。
通知関数(send_teams)を用意し、トップレベルの try/except の中で「成功時」「失敗時」に呼び分けると、自動化バッチにきれいに組み込める。
メッセージには「バッチ名・環境・時刻・成功/失敗」を含め、詳細はログに任せることで、Teams は“気づき”に専念させる。
Webhook URL や認証情報は環境変数などで管理し、通知する範囲と頻度(どのエラーで通知するか、しきい値をどうするか)を決めておくことで、通知疲れを防ぐ。
ここまで押さえれば、「Python のバッチが Teams にしゃべりかけてくる」状態はいつでも作れます。
