メールが届いたら、そのメールの添付ファイルをSlackにアップロードしたいことがあって、そのタスク実行にMicrosoft(Office365)Flowを使おうとしました。
Microsoft(Office365)FlowにはSlackコネクターがあるので、それを使えば簡単に作れるかなと思ったのですが、 残念ながらFlowのSlackコネクターはテキストメッセージ投稿専用で、Slackへファイルのアップロードはできませんでした。
仕方ないので、FlowのHTTPアクションを使って、SlackのAPIで直接ファイルをアップロードすることにしました。
ここでは、そのMicrosoft(Office365)FlowからSlackにファイルをアップロードする手順をまとめました。
Slackのファイルアップロード方法について
Slackのファイルアップロード方法についての、ざっくりとした要件です。
Slack APIドキュメント
要件
- URL「
https://slack.com/api/files.upload
」に「POST」で「multipart/form-data」でファイルをアップロードします。- いわゆるhtmlのファイルアップロードフォームと同じ方法です
- 「file」にファイルの中身を指定します。
- ファイルの種類に合わせて「contents-type」の指定が必要です。
- 「contents-type」が無いとファイルをアップロードできても、中身が壊れてしまいます。
- APIの認証はベアラートークンで、「authorization」ヘッダーにトークンを「Bearer <トークン>」とセットします。
- 「Beare」とトークンの間にはスペースが1文字必要です。
- トークンは事前に取得しておきます。
- ファイルアップロードには「files:write:user」権限が必要です。
- 投稿先は「channels」でチャンネルIDを指定します。
SlackのAPIの使い方は、これはこれで色々ハマりポイントがあり、別記事にまとめましたので、詳しくはそちらを参照ください。
Flowの設定
上記Slack APIの呼び出しを、FlowのHTTPアクションで行います。
- メソッドを「POST」、URIを「
https://slack.com/api/files.upload
」にします。 - 認証は「authorization」ヘッダーに「Bearer <トークン>」と指定します。
後はヘッダー設定で「content-type」を「multipart/form-data」にして、ファイルとSlackのchannnelIDを設定してPOSTすれば終わり…とは行かず、 「multipart/form-data」のPOSTのやり方は少々トリッキーでした。
HTTPアクションで「multipart/form-data」するには、ヘッダーでは「content-type」を設定せず、本文の中に、送信するデータと合わせてJSONで記述する必要があります。
JSONは下記のようなものになり、これを本文に貼り付けます。
{ "$content-type": "multipart/form-data", "$multipart": [ { "headers": { "Content-Disposition": "form-data; name=file; filename=@{items('Apply_to_each')?['Name']}" }, "body": { "$content-type": "@{items('Apply_to_each')?['ContentType']}", "$content": @{items('Apply_to_each')?['ContentBytes']} } }, { "headers": { "Content-Disposition": "form-data; name=channels" }, "body": "xxx" } ] }
補足説明・注意点
ファイルアップロードに必要なパラメータ
ファイルオブジェクトから、「ファイル内容(file)」「ファイル種類(content-type)」「ファイル名(filename)」の3つの値を設定して、ファイルをアップロードしています。
JSON記述内容に関して
「@{items('Apply_to_each')?['Name']}」など、見慣れないオブジェクトがありますが、 本文に貼り付けると、Flowのエディタに「添付ファイル 名前」と表示されることから分かるように、ファイルに関する情報を指しています。
Flowは内部処理では「@{items('Apply_to_each')?['Name']}」の表記の方を使っているのですが、ユーザーには分かりやすいようGUI上では別の「添付ファイル 名前」が表示されるようになっています。
Flowで作業するにあたって、これらの関係性を知らないとハマることが多いので、Flowでのデータの参照方法について別記事にまとめました。
ファイルのコンテンツはバイナリーで送る必要があるので、「@{items('Apply_to_each')?['ContentBytes']}」は「"」でくくらないで、直接書く必要があります。
また、サンプルでは、添付ファイル一覧を「Apply to each」に入れて、ファイルを1つ1つ取り出したので、「items('Apply_to_each')」といった表記になりましたが、 「triggerBody()?['Attachments'][0]」で直接取り出す書き方も可能ですし、そもそもアップロードしたいファイルをどこから取得するかによって、何を表記するか変わってきます。
それらの表記の意味や、どういった表記になるかの見つけ方も、上記記事「Microsoft (Office365) Flow のデータの参照方法について整理する」にまとめました。
Slackの設定に関して
Slackの投稿先IDを「channels」に設定して送るのですが、その設定を下記でやっています。
{ "headers": { "Content-Disposition": "form-data; name=channels" }, "body": "xxx" }
「name=~」が引数名、「body」の値に、投稿したいSlackのチャンネルIDを指定しています。
同様にして「initial_comment」「title」を設定すれば、アップロードした時のコメントやタイトルも指定することができます。
実行
以上を実行すると、無事ファイルがアップされました!
感想など
最初、ヘッダーに「content-type」「multipart/form-data」を設定して、本文にデータをベタ書きして試していました。
実は、これはこれでファイルのアップができちゃうのですが、ファイルの中身は壊れてしまいます。
Flowのアクションのメニューで「コードのプレビュー」とすると、実行されるアクションデータが見れるので見てみます。
すると、本文にデータをベタ書きすると、本文データはStringと判定されるようで、ファイルのコンテンツが「base64ToString()」で強制的にStringに変換されていて、それが原因でファイルが壊れていました。
しかし、HTTPアクションでStringしか送れない仕様なんて本当なの?と、にわかに信じがたいのでマニュアルみたら、そんなことはなく、そのものズバリ「multipart/form-data」のデータの送り方が載っていました…。
この方法で渡すと「@{items('Apply_to_each')?['ContentBytes']}」と無事バイナリーで渡されていました。いやぁ~最初に見ておけばよかった……。
HTTPアクションは汎用的に作られているので、HTTPアクションを使えばあらゆるAPIが叩けそうですね。
でも、有りもののコネクターを使って楽したいので、Slackのファイルアップロードコネクター出して欲しいです!