📤
Node-REDでSlackへ画像を投稿する(Slack API版)
Slackの「files.upload」APIが、2025年春に廃止されたため、Slackのファイルアップロード用APIを利用して画像を投稿する方法について説明します。
Slackの準備
Slackの準備は、以下の記事を参考にしてください。
今回は、ワークスペース「Node-RED開発」のチャンネル「node-red_alert」に画像を投稿します。

SlackのファイルアップロードAPIについて
SlackのファイルアップロードAPIを利用して画像を送信するには、次の3つのステップを行います。
- files.getUploadURLExternal APIを呼び出してファイルのアップロードに使用するURLとファイルIDを取得する
- 取得したURLにPOSTリクエストを送信してファイルをアップロードする
- files.completeUploadExternal APIにファイルIDに加えてチャンネルIDなどを送信して、アップロード処理を完了させる
Node-REDによるフローの作成
Node-REDで、Slackへ画像を投稿するためのフローを作成します。
Node-REDのインストール方法は、以下のページを参考にしてください。
ノードの設定
- Node-REDのワークスペースに以下のノードを追加し、図のように配置します。
- injectノード
- read fileノード
- functionノード x 3
- http requestノード x 3
- debugノード

- read fileノードをダブルクリックします。ファイル名に送信したいローカルの画像の絶対パスを入力して、出力形式に「バイナリバッファ」を選択します。「完了」ボタンをクリックします。

- 各functionノードをダブルクリックして、次のようにコードを入力します。
- function 1ノード

function 1ノード
// 設定項目
const token = "xoxb-xxxx-xxxx-xxxx";
const filename = "D:\logo\node-red-icon-2.png";
// 画像データ(Buffer)を一時保存し、ファイルサイズを取得
msg.imageBuffer = msg.payload;
const fileSize = msg.payload.length;
// Slackへのリクエスト設定
msg.url = "https://slack.com/api/files.getUploadURLExternal";
msg.method = "POST";
msg.headers = {
"Authorization": "Bearer " + token,
"Content-Type": "application/x-www-form-urlencoded"
};
// 送信データの設定
// filename: Slack上での名前、length: バイト数
msg.payload = {
filename: filename,
length: fileSize
};
return msg;
function 1ノードの説明
function 1ノードでは、アップロード用URLを取得します。
- 定数 token:
xoxb-から始まるSlackアプリのトークンを設定します。 - 定数 filename: 送信する画像のパスを設定します。
- msg.url: ファイルアップロードAPIを指定します。「files.getUploadURLExternal」はファイルをアップロードするURLを取得するAPIです。
- msg.method: 「POST」リクエストを指定します。
- msg.headers: 投稿する画像のパラメータを指定します。
- Authorization: Bearer <Slackアプリのトークン>
- msg.payload: 投稿する画像のパラメータを設定します。
- filename: アップロードするファイルの名前
- file: アップロードするファイルのサイズ
- function 2ノード

function 2ノード
// Slackからのレスポンスをチェック
if (!msg.payload.ok) {
node.error("URL取得失敗: " + msg.payload.error);
return null;
}
// 後の完了報告のためにfile_idを保存
msg.fileId = msg.payload.file_id;
// 送信先をSlackが発行したupload_urlに変更
msg.url = msg.payload.upload_url;
msg.method = "POST";
msg.headers = {
"Content-Type": "image/png"
};
// payloadを画像データ(バイナリ)に戻す
msg.payload = msg.imageBuffer;
return msg;
function 2ノードの説明
function 2ノードでは、取得したURLに画像をアップロードします。
- msg.url: アップロード用URLを指定します。
- msg.method: 「POST」リクエストを指定します。
- msg.headers: 投稿する画像のパラメータを指定します。
- Content-Type: 画像の種類
- msg.payload: 投稿する画像のパラメータを設定します。
- function 3ノード

function 3ノード
// 設定項目
const token = "xoxb-xxxx-xxxx-xxxx";
const channelId = "Cxxxxxxxxxx"; // 投稿先のチャンネルID
// Slackへのリクエスト設定
msg.url = "https://slack.com/api/files.completeUploadExternal";
msg.method = "POST";
msg.headers = {
"Authorization": "Bearer " + token,
"Content-Type": "application/json; charset=utf-8"
};
// 完了報告のデータをセット
msg.payload = {
files: [
{ id: msg.fileId, title: "ロゴ画像" }
],
channel_id: channelId,
initial_comment: "ロゴ画像をアップロードしました。"
};
return msg;
function 3ノードの説明
function 3ノードでは、アップロード用URLを取得します。
- 定数 token: function 1ノードと同じトークンをを設定します。
- 定数 channelId: 投稿先のチャンネルIDを設定します。
- msg.url: アップロードを完了するAPIを指定します。「files.completeUploadExternal」はfiles.getUploadURLExternalで開始したアップロードを完了するAPIです。
- msg.method: 「POST」リクエストを指定します。
- msg.headers: 投稿する画像のパラメータを指定します。
- Authorization: Bearer <Slackアプリのトークン>
- msg.payload: 投稿する画像のパラメータを設定します。
- files: ファイルIDとそれに対応するタイトル
- channel_id: 投稿先のチャンネルID
- initial_comment: ファイルを紹介するメッセージ テキスト
- 各http requestをダブルクリックして、次のように設定します。
- http request 1ノード
メソッド:前段のfunctionノードで設定している「msg.method」の定義を使用する
出力形式:結果をJSONオブジェクトで取得する

- http request 2ノード
メソッド:前段のfunctionノードで設定している「msg.method」の定義を使用する
出力形式:結果が「ok」という文字列で返ってくるので、UTF8文字列で取得する

- http request 3ノード
メソッド:前段のfunctionノードで設定している「msg.method」の定義を使用する
出力形式:結果をJSONオブジェクトで取得する

- 「デプロイ」ボタンをクリックします。

- 完成したフローです。

作成したフローのJSONを以下に貼っておきます。
Node-REDのメニューから「読み出し」->「クリップボード」で配置することができます。
各functionノードの定数tokenや定数channelIdは再設定してください。
[{"id":"2f606c6d28d294c5","type":"tab","label":"フロー 1","disabled":false,"info":"","env":[]},{"id":"23e61e6e5d131c36","type":"inject","z":"2f606c6d28d294c5","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":140,"y":60,"wires":[["596c473eeed00a51"]]},{"id":"596c473eeed00a51","type":"file in","z":"2f606c6d28d294c5","name":"","filename":"D:\\logo\\node-red-icon-2.png","filenameType":"str","format":"","chunk":false,"sendError":false,"encoding":"none","allProps":false,"x":380,"y":60,"wires":[["abf20a9642a0401b"]]},{"id":"abf20a9642a0401b","type":"function","z":"2f606c6d28d294c5","name":"function 1","func":"// 設定項目\nconst token = \"xoxb-xxxx-xxxx-xxxx\";\nconst filename = \"D:\\logo\\node-red-icon-2.png\";\n\n// 画像データ(Buffer)を一時保存し、ファイルサイズを取得\nmsg.imageBuffer = msg.payload;\nconst fileSize = msg.payload.length;\n\n// Slackへのリクエスト設定\nmsg.url = \"https://slack.com/api/files.getUploadURLExternal\";\nmsg.method = \"POST\";\nmsg.headers = {\n \"Authorization\": \"Bearer \" + token,\n \"Content-Type\": \"application/x-www-form-urlencoded\"\n};\n\n// 送信データの設定\n// filename: Slack上での名前、length: バイト数\nmsg.payload = {\n filename: filename,\n length: fileSize\n};\n\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":320,"y":120,"wires":[["4a874d8cb5465605"]]},{"id":"4a874d8cb5465605","type":"http request","z":"2f606c6d28d294c5","name":"","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":490,"y":120,"wires":[["7ec210b40906aa94"]]},{"id":"7ec210b40906aa94","type":"function","z":"2f606c6d28d294c5","name":"function 2","func":"// Slackからのレスポンスをチェック\nif (!msg.payload.ok) {\n node.error(\"URL取得失敗: \" + msg.payload.error);\n return null;\n}\n\n// 後の完了報告のためにfile_idを保存\nmsg.fileId = msg.payload.file_id;\n\n// 送信先をSlackが発行したupload_urlに変更\nmsg.url = msg.payload.upload_url;\nmsg.method = \"POST\";\nmsg.headers = {\n \"Content-Type\": \"image/png\"\n};\n\n// payloadを画像データ(バイナリ)に戻す\nmsg.payload = msg.imageBuffer;\n\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":320,"y":180,"wires":[["3881ff9fe9655264"]]},{"id":"3881ff9fe9655264","type":"http request","z":"2f606c6d28d294c5","name":"","method":"use","ret":"txt","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":490,"y":180,"wires":[["e7a1b21bcebaa077"]]},{"id":"e7a1b21bcebaa077","type":"function","z":"2f606c6d28d294c5","name":"function 3","func":"// 設定項目\nconst token = \"xoxb-xxxx-xxxx-xxxx\";\nconst channelId = \"Cxxxxxxxxxx\"; // 投稿先のチャンネルID\n\n// Slackへのリクエスト設定\nmsg.url = \"https://slack.com/api/files.completeUploadExternal\";\nmsg.method = \"POST\";\nmsg.headers = {\n \"Authorization\": \"Bearer \" + token,\n \"Content-Type\": \"application/json; charset=utf-8\"\n};\n\n// 完了報告のデータをセット\nmsg.payload = {\n files: [\n { id: msg.fileId, title: \"ロゴ画像\" }\n ],\n channel_id: channelId,\n initial_comment: \"ロゴ画像をアップロードしました。\"\n};\n\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":320,"y":240,"wires":[["a043c954ed1ae6e7"]]},{"id":"a043c954ed1ae6e7","type":"http request","z":"2f606c6d28d294c5","name":"","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":490,"y":240,"wires":[["33c0e56032660f8c"]]},{"id":"33c0e56032660f8c","type":"debug","z":"2f606c6d28d294c5","name":"debug 1","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":660,"y":240,"wires":[]}]
動作確認
injectノードの左側のボタンをクリックすると、Slackのチャンネル「node-red_alert」へNode-REDのロゴ画像が投稿されます。


Discussion