この記事は、リンクバルアドベントカレンダー2023の1日目の記事です。
はじめに
Slackで同じ内容のDMを複数のユーザーに送りたいことってありますよね?
30人程度までなら手動でもいいですが、それ以上だとめんどうなので、GAS(Google Apps Script)を使って送る方法を紹介します。
GASでDMを送る方法は検索したりChatGPTに聞けばいろいろ出てきます。
が、今回は以下の要件があったので、少しスプレッドシートで工夫します。
- 社員ユーザーにだけ送りたい
- 取引先のユーザーなどには送らない
- その他記事の本筋からずれる要件
- スプレッドシートにメッセージのテキストを用意したい
- 用意したテキストをランダムに送りたい
- 定期的に送りたい
コードだけ知りたい方はこちらまで飛んでください!
準備
1 Slack Appの作成
https://api.slack.com/apps の 右上の Create New App
ボタン から作成できます。
詳細は公式のヘルプや、以下のような記事を参考にしてください!
参考記事
botに必要なスコープ
- chat:write
- im:write
あとはtokenが必要なので、控えておいてください。
2 DM送信対象者のUser IDの取得
botからDMを送るには、送信対象ユーザーのSlackのUser IDが必要です。
Slackの画面から個別に取得することもできますが、人数が多いとしんどすぎるので、Analytics画面からCSVを取得します。
1 Analytics画面のMembersを開く
https://linkbal.slack.com/stats#members です。
2 Edit Columns
で、必要な項目をチェックする&不要な項目のチェックを外す
最低限 User ID
さえあれば送信できます
今回は管理と社員だけに送るために、画像のようにチェックしています。
Included in bill
は、有料ユーザーがどうかです。当社の場合は、社員以外は基本的に有料ユーザーがいないので、このデータで社員判定をします。
もし社員以外にも有料ユーザーがいたり、有料ユーザーだけど社員でない人がいる場合などは、例えばスプレッドシートで特定のドメインがEmail列に含まれているか、など工夫しましょう。
3 Export CSV
でCSVをダウンロードする
データ量次第ですが、早ければ1,2秒でSlack BotからDMで送られます
3 スプレッドシートとGASの作成
なんでもいいのでスプレッドシートを1つ準備してください。
1 先ほどのCSVをアップロードする
メニューの ファイル
> インポート
> アップロード
でできます。
画像のモーダルが出るので、操作した状況に合わせて適切なものを選択してください。
基本的に 新しいシートを挿入する
か 現在のシートを置換する
のどちらかになります。
2 社員ユーザーだけに対象を絞る
CSVをインポートしたシートの名前が Slackインポート用
だとします。
1つシートを追加して、A1に以下の関数を入れます。
=QUERY(
'Slackインポート用'!B:G,
"select
C
where
G = 1",
1
)
やってることは単純で、QUERY関数で、CSVデータからG列が1の行のC列を抽出しているだけです。
最後の1は、ヘッダー行があることを表しています。
今回のCSVは、C列がUser IDで、G列が Included in bill
です。
コメントをつけるとこんな感じです。
=QUERY(
'Slackインポート用'!B:G, // 対象範囲
"select
C // 取得する列
where
G = 1", // 取得する行の条件。G列が1の行
1 // ヘッダー行があることを明示
)
QUERY関数の公式ドキュメント
https://support.google.com/docs/answer/3093343?hl=ja
2 シートと紐づくGASのプロジェクトを作成する
メニューの 拡張機能
> Apps Script
で、スプレッドシートに紐づいたGASのプロジェクトを作成しましょう。
GASの作成
記事の主題からはそれますが、、、
前提として、画像のようなデータから、分類をランダムで選び、その分類のテキストからランダムに送るようになっています。
やること
- GASのエディタに以下のコードを貼り付ける
- 最初からある
myFunctio
などの3行のコードは不要なので消してOKです
- 最初からある
- ショートカットのctrl+sやcmd+sか、フロッピーディスクのアイコンで保存する
コード
コメントで説明しています。
// 特定ユーザーだけにしたテスト実行用
function doTest() {
main('テスト用Slack_UserID抽出'); // 名前は実際のシートに合わせる
}
function main(targetSheetName) {
const spreadsheet = SpreadsheetApp.getActive(); // スプレッドシートからスクリプト作成した前提
const slackUserSheet = spreadsheet.getSheetByName(targetSheetName); // SlackのUserID記載のシート名を指定
const targetUserIds = slackUserSheet.getDataRange().getValues().slice(1); // ヘッダー行を対象から外す
// ========== ここから:ランダムにテキストを送るための実装 ==========
// スプレッドシートからテキストデータを取得
const textSheet = spreadsheet.getSheetByName('テキストシート名'); // 名前は実際のシートに合わせる
const textRange = textSheet.getDataRange().getValues().slice(1); // ヘッダー行を対象から外す
// 大分類ごとにテキストをグループ化
const classifiedTextObjects = createClassifiedTextObjects(textRange);
// ========== ここまで:ランダムにテキストを送るための実装 ==========
targetUserIds.forEach(function(row) {
const targetUserId = row[0];
if (!targetUserId) return; // 空のセルは無視
sendSlackDM(targetUserId, getSlackMessage(classifiedTextObjects)); // 定型文を送るだけなら、この第二引数に文字列をそのまま渡せばOK
});
}
// メンバーにDMを送信する
function sendSlackDM(targetUserId, message) {
const payload = {
token: 'xxxxx', // 作成したAPIのtokne
channel: targetUserId,
text: message
}
const slackEndPoint = 'https://slack.com/api/chat.postMessage'
const option = {
"method" : "post",
"payload" : payload
}
const response = UrlFetchApp.fetch(slackEndPoint, option)
// Logger.log(response) // デバッグ
}
// 全UserID 誤って実行しないよう注意!!!!!
function doProd() {
main('Slack_UserID抽出'); // 名前は実際のシートに合わせる
}
// ========== 以下はランダムにテキストを送るための実装 ==========
// テキストの種類とテキストそのもののオブジェクトを作成する
function createClassifiedTextObjects(range) {
const classifiedTextObjects = {};
range.forEach(function(row) {
const textType = row[0];
const textSentence = row[1];
if (!classifiedTextObjects[textType]) {
classifiedTextObjects[textType] = [];
}
classifiedTextObjects[textType].push(textSentence);
});
return classifiedTextObjects;
}
// テキストをランダムに返す
function getRandomTextType(classifiedTextObjects) {
const textTypes = Object.keys(classifiedTextObjects);
return textTypes[Math.floor(Math.random() * textTypes.length)];
}
// textType のテキストをランダムに返す
function getRandomTextSentence(classifiedTextObjects, textType) {
const textSentences = classifiedTextObjects[textType];
return textSentences[Math.floor(Math.random() * textSentences.length)];
}
function getSlackMessage(classifiedTextObjects) {
const randomTextType = getRandomTextType(classifiedTextObjects);
const randomTextSentence = getRandomTextSentence(classifiedTextObjects, randomTextType);
const message = `定型文
${randomTextType}
${randomTextSentence}
定型文`;
// Logger.log(message); デバッグ
return message;
}
テスト実行
doTest
というテスト用の関数を作っています。
私は誤って2回テストのメッセージを全員に送ってしまったので、上記作成しました。
doTest
のシートのA2とA3に、自分のSlackのUser IDを入れておきましょう。
2行入れておけば、DMが2通来たらテスト実行だとわかります。1通しか来なかったらミスってます...
画像の部分が doTest
になっていることを確認したら、実行
ボタンを押しましょう。
作成したSlack Appから、自分にDMが2つ来るはずです!
来ない場合は、以下を確認しましょう。
- シートの作り
- Slack Appの権限が足りているか
- Slack AppのTokneがGASに設定されたいるか
- GASでエラーが出ていないか
GAS初見だったりプログラミング未経験の方はトラブルシューティングが難しいので、どうしてもわからないときはプロフィール記載のSMSにメッセージなり送っていただければ、(多分)回答します!
本番実行(定期実行)
サイドメニューの トリガー
> 右下の トリガーを追加
> 画像のように設定して 保存
重要なポイント
-
実行する関数
はdoProd
を選択すること -
イベントのソースを選択
やそれ以降の設定は、適切なものを選択すること
こうすれば、設定した内容で定期実行されます。
おわりに
おつかれさまでした!