slack botからメールアドレスを利用してDMを送りたい！

# この記事に書いてある事
1. メールアドレスを利用して、slack botからDMを送る
1. GASで実装
1. ハマりポイント
1. まとめ

## 1. メールアドレスを利用して、slack botからDMを送る
### ゴール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/289114/4e2a8fcc-adea-72fb-fc6f-6345d21445db.png)
testというbotの権限を持っているslack appからDMを送るようにしました。
DMを送る対象は、メールアドレスをスプレットシートで管理してます。

### 構成

![1min check構成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/289114/7195ca51-6ed9-e931-d894-7f0b5295e4e3.png)


## 2. GASで実装
### 処理の流れ
1. spread sheetから対象のメールドレス一覧取得
2. slack apiでslackのuser id取得(member idともいう)
    3. [users.lookupByEmail](https://api.slack.com/methods/users.lookupByEmail)
3. slack apiでDMを送れる状態にする
    4.  [conversations.open](https://api.slack.com/methods/conversations.open)
4. slack apiでDM送信
    5. [chat.postMessage](https://api.slack.com/methods/chat.postMessage)

### :point_up: サンプルコード

1. spread sheetから対象のメールドレス一覧取得

```javascript
function getRequiredMailList () {
  let member_list_sheet_id = $spread_sheet_id
  let sheet = SpreadsheetApp.openById(member_list_sheet_id).getSheetByName($シート名)
  var lastRow = sheet.getLastRow(); // Note: 空白の行は要らないから、入力のある行の最後の行を取得
  return sheet.getRange(1, 1, lastRow, 1).getValues().map(row => row[0]) //Note: 行, 列, 何行, option何列
}
```

2.slack apiでslackのuser id取得(member idともいう)

```javascript
const token = PropertiesService.getScriptProperties().getProperty('SLACK_ACCESS_TOKEN');  // Note: 環境変数にTOKEN保存しておいてね
var userInfoUrl = 'https://slack.com/api/users.lookupByEmail?token=' + token + '&email=' + email + '&pretty=1'
const userId = JSON.parse(UrlFetchApp.fetch(userInfoUrl)).user.id
```

3.slack apiでDMを送れる状態にする

```javascript
// Note: userIdは ☝️ 2 で取得したものを利用
const url = 'https://slack.com/api/conversations.open?token=' + token + '&users=' + userId + '&pretty=1'
const channel = JSON.parse(UrlFetchApp.fetch(url)).channel
```

4.slack apiでDM送信

```javascript
const messageOptions = {
    "method" : "post",
    "contentType": "application/x-www-form-urlencoded",
    "payload" : {
      "token": token,
      "channel": channel.id, // Note: channelは ☝️ 3 で取得したものを利用 
      "text": "DMで送りたい内容はここに書くよ〜"
    }
  };
  var result = UrlFetchApp.fetch('https://slack.com/api/chat.postMessage', messageOptions);
```

:relaxed: :relaxed: :relaxed: :relaxed: 完成 :relaxed: :relaxed: :relaxed: :relaxed: 
 
## :exclamation: 3. ハマりポイント :exclamation: 
### botの権限系
#### 何の権限付ければ良いの問題 :thinking: 
今回の構成なら、とりあえずこれをつけておけばオケ :ok_hand: ごにょごにょしまくってたから、もしかしたら不要なのもあるかも。
![スクリーンショット 2020-10-17 21.42.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/289114/1dd88287-0f1d-aa8f-5e6b-8cb2672cefa4.png)


#### 言われた権限付けても、変わらず同じエラーなんですけど問題 :rage: 
 :exclamation:  :exclamation:  :exclamation: __Reinstall Appをする！__ :exclamation:  :exclamation:  :exclamation: 
権限をいじったら、毎回Reinstall Appをしないと反映されないから超注意 :exclamation: 
![スクリーンショット 2020-10-17 21.35.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/289114/7f64731c-0745-15c8-dd3f-0b3ad8f3c9df.png)


(ポエム):point_down: ここら辺に赤文字で大きく、「権限変えたらReinstall Appしてね！！」って書いておいて欲しかった。(めっちゃハマった)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/289114/fce36ff8-e105-76f1-8348-da4cb8c542b3.png)

#### 社員のmemberIdどうやって知るんだ問題
##### 課題
DMを送るためには、slackのmember IDを知る必要があります。
@erikaadno とかのメンションとは別に、slackのアカウントがある人全員に割り振られてるIDのこと。
「View Full Profile」から飛んだ、これ :point_down: 
![スクリーンショット 2020-10-17 18.36.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/289114/e4db4dcb-2881-c396-66c6-7d4039a3c25c.png)

##### ソリューション
[lookupByEmail](https://api.slack.com/methods/users.lookupByEmail)というslack apiを使います。
画面上からだと、member idだけど、APIのresponseはuser id :v:

```javascript
const token = PropertiesService.getScriptProperties().getProperty('SLACK_ACCESS_TOKEN'); 
var userInfoUrl = 'https://slack.com/api/users.lookupByEmail?token=' + token + '&email=' + email + '&pretty=1'
const userId = JSON.parse(UrlFetchApp.fetch(userInfoUrl)).user.id

```

## 4. まとめ
- 権限変えてもaccess deniedで続けるの謎だから、本当にreinstall Appをしないと反映されないよって開発してる全員が何回も目に留まるところに書いておいて欲しい。 
- slack apiはAPIドキュメントにtesterがあって直ぐに試せるので最高。