2026年6月17日

2026年6月17日

PythonでSlack通知を送る方法|Incoming WebhookとBotトークン(slack_sdk)の使い分け

Python から Slack に通知を送る方法は、大きく分けて「Incoming Webhook の URL に JSON を POST する」方法と、「Bot トークンを使って Web API の chat.postMessage を呼ぶ」方法の2つです。決まったチャンネルにお知らせを流すだけなら Webhook、送り先を切り替えたい・スレッドに返信したい・ファイルを送りたいなら Bot トークンが向いています。この記事では、両方の準備と Python のコード、メッセージの整形、エラーやレート制限への備え、URL やトークンの安全な保管方法までを説明します。

2つの方法の違い

Incoming Webhook は、Slack アプリに発行される専用の URL に HTTP POST するだけでメッセージを投稿できる仕組みです。URL は1つのチャンネルに結びついており、コードからは送り先を変えられません。外部ライブラリが無くても標準ライブラリだけで送れるので、サーバー監視やバッチ処理の完了通知のような用途に向いています。

Bot トークン(Web API) は、xoxb- で始まるトークンを使って Slack の Web API を呼ぶ方法です。chat.postMessage でチャンネルを指定して投稿できるほか、スレッドへの返信、投稿の更新、ファイルのアップロードなど、Webhook ではできない操作も扱えます。その分、アプリに与える権限(スコープ)の設定と、ボットをチャンネルに参加させる手順が必要です。

どちらも Slack のワークスペースに「Slack アプリ」を作成するところから始まります。古い「カスタムインテグレーション」形式の Webhook は Slack 側で非推奨とされているため、これから作るなら Slack アプリ経由にしてください。管理画面のメニュー名や手順は変わることがあるため、迷ったら Slack の開発者向けドキュメント(api.slack.com)で最新の手順を確認するのが確かです(2026年10月現在)。

方法1:Incoming Webhook で送る

Webhook URL を発行する

おおまかな流れは次のとおりです。

  1. Slack の開発者向けページでアプリを新規作成し、対象のワークスペースを選ぶ
  2. アプリの設定で Incoming Webhooks の機能を有効にする
  3. ワークスペースに Webhook を追加し、投稿先のチャンネルを選んで許可する
  4. 発行された https://hooks.slack.com/services/... 形式の URL を控える

ワークスペースによっては、アプリのインストールに管理者の承認が必要です。承認待ちのまま止まる場合は、ワークスペースの管理者に相談してください。

標準ライブラリだけで送るコード

Webhook URL はパスワードと同じ扱いの秘密情報です。URL を知っている人は誰でもそのチャンネルに投稿できてしまうため、コードに直接書かず、環境変数から読み込みます。

import json
import os
import urllib.error
import urllib.request

WEBHOOK_URL = os.environ["SLACK_WEBHOOK_URL"]  # コードやGitに直書きしない


def notify(text: str) -> None:
    payload = json.dumps({"text": text}).encode("utf-8")
    req = urllib.request.Request(
        WEBHOOK_URL,
        data=payload,
        headers={"Content-Type": "application/json; charset=utf-8"},
        method="POST",
    )
    try:
        with urllib.request.urlopen(req, timeout=10) as res:
            body = res.read().decode("utf-8")
            print(res.status, body)  # 成功時は 200 と "ok"
    except urllib.error.HTTPError as e:
        # 失敗時は本文にエラー理由が入る(例: invalid_payload, no_text など)
        print("送信失敗:", e.code, e.read().decode("utf-8"))
        raise


if __name__ == "__main__":
    notify("バックアップが完了しました")

実行前に、シェルで環境変数を設定します(値はダミーです)。

export SLACK_WEBHOOK_URL="https://hooks.slack.com/services/your/webhook/url"
python notify.py

成功すると HTTP 200 とともに本文 ok が返ります。失敗した場合は、HTTP ステータスと本文のエラー文字列を見ます。よくある原因は次のとおりです。

  • **400 系で invalid_payload**:JSON の形式が崩れている。json.dumps() を使わずに文字列を組み立てていると起きやすい
  • **no_text**:text(または blocks)が空
  • 403 や 404:URL が無効になっている。アプリが削除された、Webhook が取り消された、チャンネルがアーカイブされた、などが考えられます。新しい URL を発行し直します

方法2:Bot トークンと slack_sdk で送る

アプリの権限とチャンネルへの参加

アプリの設定で Bot Token のスコープに chat:write を追加し、ワークスペースにインストールすると、xoxb- で始まる Bot User OAuth Token が発行されます。スコープを後から追加した場合は、再インストールしないと反映されません。

次に、投稿したいチャンネルにボットを参加させます。チャンネルで /invite @アプリ名 を実行するか、チャンネルの設定から連携アプリとして追加します。これを忘れると、後述の not_in_channel エラーになります。

slack_sdk で投稿する

Slack 公式の Python SDK slack_sdk を使うと、API 呼び出しとエラーの判定を簡潔に書けます。

pip install slack_sdk
import os

from slack_sdk import WebClient
from slack_sdk.errors import SlackApiError

client = WebClient(token=os.environ["SLACK_BOT_TOKEN"])


def post(channel: str, text: str, thread_ts: str | None = None) -> str:
    try:
        res = client.chat_postMessage(channel=channel, text=text, thread_ts=thread_ts)
        return res["ts"]  # 投稿のタイムスタンプ。スレッド返信や更新に使う
    except SlackApiError as e:
        # e.response["error"] に not_in_channel / channel_not_found などが入る
        print("投稿失敗:", e.response["error"])
        raise


ts = post("C0123456789", "デプロイを開始しました")
post("C0123456789", "デプロイが完了しました", thread_ts=ts)

チャンネルはチャンネル名ではなくチャンネル ID(C で始まる文字列)で指定するのが確実です。ID はチャンネルの詳細画面などで確認できます。上の例では、最初の投稿の ts を thread_ts に渡して、2通目をスレッドへの返信にしています。開始と完了の通知を1つのスレッドにまとめると、チャンネルが流れにくくなります。

エラー文字列ごとの対処は次のとおりです。

  • **not_in_channel**:ボットがチャンネルに参加していない。招待する
  • **channel_not_found**:ID の誤り、またはボットから見えないプライベートチャンネル
  • **missing_scope**:chat:write などのスコープ不足。追加後に再インストール
  • **invalid_auth / not_authed**:トークンの誤りや失効。環境変数の値を確認

なお、slack_sdk には Webhook 用の WebhookClient も含まれています。すでに slack_sdk を使っているプロジェクトなら、WebhookClient(url).send(text="...") の形で Webhook にも送れます。

メッセージを見やすく整形する

text では Slack 独自の記法(mrkdwn)が使えます。*太字*、_斜体_、` コード 、<https://example.com|リンク文字> のような書き方です。ユーザー入力やログをそのまま埋め込む場合、&、<、> はそれぞれ &amp;、&lt;、&gt;` に置き換える必要があります。置き換えないと、意図しないリンクやメンションとして解釈されることがあります。

見出しや区切りのあるレイアウトにしたい場合は、Block Kit の blocks を使います。

blocks = [
    {"type": "header", "text": {"type": "plain_text", "text": "ディスク使用率の警告"}},
    {"type": "section", "text": {"type": "mrkdwn", "text": "*サーバー:* web01\n*使用率:* 92%"}},
]
client.chat_postMessage(
    channel="C0123456789",
    blocks=blocks,
    text="web01 のディスク使用率が 92% です",  # 通知やプレビューに表示される代替テキスト
)

blocks を使うときも text を一緒に指定してください。プッシュ通知や一部の表示では text のほうが使われます。レイアウトは Slack が提供している Block Kit Builder で事前に確認できます。

送りすぎ・送り損ねを防ぐ

レート制限への備え

Slack の API にはレート制限があり、chat.postMessage は1つのチャンネルに対しておおむね1秒に1件程度が目安とされています(短時間の集中はある程度許容されます)。制限を超えると HTTP 429 が返り、Retry-After ヘッダーに待つべき秒数が入ります。エラーが大量に出たときに1件ずつ通知すると、すぐにこの制限に当たります。

対策としては、同じ種類の通知は一定時間まとめて1通にする、ループの中から通知しない、などの設計で件数そのものを減らすのが効果的です。slack_sdk にはレート制限時に自動で待って再試行する仕組み(RateLimitErrorRetryHandler)も用意されています。

通知の失敗で本処理を止めない

Slack 側の障害やネットワークの問題で通知が失敗することがあります。バックアップや集計など本来の処理の結果を、通知の成否に引きずられないようにするのが基本です。通知処理は try/except で囲み、失敗した場合はログに記録して処理を続けます。重要な監視であれば、Slack 以外の経路(メールなど)も併用します。

秘密情報の扱い

Webhook URL と Bot トークンは、どちらも漏れると第三者に投稿されてしまう秘密情報です。

  • コードに直書きせず、環境変数やサーバーの設定ファイル(権限を絞ったもの)から読み込む
  • .env を使う場合は .gitignore に追加し、リポジトリにコミットしない
  • ログやエラー通知の中に URL やトークンを出力しない
  • 漏れた可能性がある場合は、Slack のアプリ設定で Webhook を取り消す、トークンを再発行する

cron などで定期実行する場合は、実行ユーザーの環境変数が読み込まれないことがあるため、スクリプトの中で設定ファイルを読み込むか、cron 側で環境変数を指定します。

まとめ

  • 固定のチャンネルに通知するだけなら Incoming Webhook、送り先の切り替えやスレッド返信が必要なら Bot トークンと chat.postMessage
  • Webhook は成功時に ok、失敗時は本文のエラー文字列で原因を判断する
  • Bot は chat:write スコープとチャンネルへの招待が必要。not_in_channel は招待忘れ
  • mrkdwn では &、<、> をエスケープし、blocks を使うときも text を付ける
  • 通知はまとめて件数を減らし、失敗しても本処理を止めない。URL とトークンは環境変数で管理する

お気軽にご相談ください

お見積りへ お問い合わせへ
▲