はじめに
この記事は、GAS で Webex Teams bot を作る記事の続編になります。Webex Teams bot の作り方は、下記の記事を参考にしてください。
https://qiita.com/hiroactivity/items/7e319de7821bba36ba4a
ここでは bot に Excel を Multipart で添付して送るサンプルコードを紹介します。
実際の動作
まずはコードの紹介
手っ取り早くコピペで作りたい方のためにまずはコードを紹介します。下記のような感じです。
function sendSpreadsheetAsExcel(){
// Google Spreadsheet を Excel で取得して Webex に添付してつぶやきます
// Webex 関連
const webexToken = "<bot token>";
const webexRoom = "<roomId>";
const webexUrl = 'https://webexapis.com/v1/messages/';
// google spreadsheet の ID, URL の /d/<この値>/edit? を抜き出す
const spreadsheetId = 'abcabcabcabc';
// spreadsheet を Excel で取得するための URL
const fetchUrl = "https://docs.google.com/feeds/download/spreadsheets/Export?key="+
spreadsheetId+"&exportFormat=xlsx";
// OAuth2 設定
const fetchOpt = {
"headers": {Authorization: "Bearer " + ScriptApp.getOAuthToken()},
"muteHttpExceptions": true
};
// Excel を blob で取得
const xlsxFile = UrlFetchApp.fetch(fetchUrl, fetchOpt).getBlob();
// multipart/form-data のための boundary やヘッダ設定
const boundary = "myBoundary";
const headers = {
'Authorization': 'Bearer ' + webexToken,
'Content-Type': "multipart/form-data; boundary=" + boundary
};
// multipart/form-data を作成
const payload = Utilities.newBlob(
'--'+boundary+'\r\nContent-Disposition: form-data; name="roomId"\r\n\r\n'+webexRoom+'\r\n' +
'--'+boundary+'\r\nContent-Disposition: form-data; name="text"\r\n\r\nファイルです!\r\n' +
'--'+boundary+'\r\nContent-Disposition: form-data; name="files"; filename="myexcel.xlsx"\r\n'+
'Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\r\n\r\n').getBytes()
.concat(xlsxFile.getBytes())
.concat(Utilities.newBlob('\r\n\r\n--'+boundary+'--\r\n').getBytes()
);
const options = {
'method': 'POST',
'muteHttpExceptions': true,
'headers': headers,
'payload': payload
};
res = UrlFetchApp.fetch(webexUrl, options);
console.log(res.toString());
}
動作結果
上記コードに Bot token, Room ID, Google spreadsheet ID を埋めて GAS で動かしていただくと、下記のように Webex Teams にファイルを添付してつぶやいてくれるはずです。
解説
multipart/form-data
今回のメインである GAS で multipart/form-data をどのように送るかの解説です。
Webex API のガイドを見ると、下記のような Python のコードが掲載されています。
参考: https://developer.webex.com/docs/basics
m = MultipartEncoder({'roomId': 'Y2lzY2.....',
'text': 'example attached',
'files': ('example.png', open('example.png', 'rb'),
'image/png')})
今回 GAS で同じことをしようと思ったのですが、GAS では MultipartEncoder のような便利なものは(おそらく)存在しなかったので、自分で作ってみたというのがこの記事の内容になります。ただ上記の Python ではどのように multipart になっているのかわからず、一度 Python でコードを書いて解析しました。その結果、下記のようになっていれば良いようです。これに沿って作ったのが、今回の GAS のコードになります。
--boundary\r\nContent-Disposition: form-data; name="roomdId"<roomId>\r\n
--boundary\r\nContent-Disposition: form-data; name=text"テキストメッセージ\r\n
--boundary\r\nContent-Disposition: form-data; name="files"; filename="任意のファイル名" \r\n
Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\r\n\r\n
<ファイルの blob>
\r\n\r\n--boundary--\r\n
ここで、ファイルの blob の後に \r\n を入れるのが重要です。最初これを忘れていてかなりハマりました。