GASでSlack APIを使う：ユーザーIDからメールを取得する

こんにちは、ユーゴです。
今回は、GASでSlack APIを使っていたときに直面した問題について紹介します。

この記事を書く前にネットで調べ尽くしましたが、GASでSlackのアカウントのメール→ユーザーIDを取得するはあっても、ユーザーID→メールを取得するがなかったので、記事化しました。

# 対象読者
・ひとまずSlackアプリの追加・作成ができる人
・GASがなんとなく書ける人

# 本記事でわかること
GASでSlack APIを使用し、SlackのユーザーIDからSlackのメールアドレスを取得する方法。

# 結論
以下が、SlackのユーザーIDから、メール含むアカウント情報を根こそぎ取得する方法です。
コピペ、商用利用OK。ただしあらゆる損害に対して自己責任でお願いします。

```javascript:UsersInfoGet.gs
function doPost(e) {
    //いろんなユーザー情報が入ってる
    var userInfo = getUserInfoByUserId(e.parameter.user_id);
    //「example@gmail.com」的なのが返ってくる。gmailでなくてもいけるはず。
    var userEmail = userInfo.user.profile.email;
    //あとは好きな処理をする
}

function getUserInfoByUserId(user_id) {
    var options =
    {
        "method": "get",
        "payload":
        {
            //xoxb-で始まるはず。トークン何それ、どこ...という人は、まずSlackアプリを作成するところから始めましょう
            "token": 'ここにアプリのBot User OAuth Tokenを入れる',
            "user": user_id
        }
    };

    //ここのURLはそのまま。SlackのWeb APIで、ユーザ情報を取得する
    var userInfo_str = UrlFetchApp.fetch('https://slack.com/api/users.info', options).getContentText();
    //文字列「{"ok":true,"user":{"id":""W012A3CDE",...」が返されるが、それだと扱えないので扱いやすい変数の型にするだけ。
    var userInfo = JSON.parse(userInfo_str);
    return userInfo;
}
```

一応書いておきますが、GASのエディタから実行を押してもdoPost(e)のeにSlack上の値を投げられないため上手くいきません。Slack上でEvent Subscriptionsなどを経由して実行してください。

# 解説
### doPost(e)
doPost(e)は、mainメソッドと同じで名前がこれじゃなきゃダメです。GASを動かすだけならdoPost(e)でなくてもいいと思います。しかし、Slackで「Event Subscriptions」「Slash Commands」「Interactive Components」など使うときは必ず使うことになると思います。

### e.parameter.user_id
こちらは、Slackから投げられたアカウントの情報から、user_idを取り出しています。~~e.parameter.emailで取得できろよと思った。~~

### options{ "method": "get", "payload": { "token": 'トークン', "user": user_id } }
これが最初は難解ですが、APIでユーザ情報を取得するための必要な引数です。
"method":"get"では、データを受信するよ、という宣言をしています。なので、Slackにメッセージを送るときは"post"って書いたはずです。
"token":'トークン',"user_id":user_idでは、Slackのアカウントを検索するためのワードを指定しています。多分。(本来ならuser_idだけでいけるはずであり、トークンは認証的な話だと思うが)

### UrlFetchApp.fetch('```https://slack.com/api/users.info```', options).getContentText()
UrlFetchApp.fetch('```https://slack.com/api/users.info```', options)：Slack APIの一種「users.info」を使用しています。先ほど指定したoptionsからユーザー情報を取得します。ここにSlackのメールアドレスが含まれています。
.getContentText()：取得した「users.info」はHTTPResponse型の扱いにくい変数です。getContentTextはそれをString型にします。
ちなみに、返ってくる文字列は以下のような感じになります。欲しいのは、"user"の"profile"の"email"の項目です。

```json:users.infoの中身
{
    "ok": true,
    "user": {
        "id": "W012A3CDE",
        "team_id": "T012AB3C4",
        "name": "spengler",
        "deleted": false,
        "color": "9f69e7",
        "real_name": "Egon Spengler",
        "tz": "America/Los_Angeles",
        "tz_label": "Pacific Daylight Time",
        "tz_offset": -25200,
        "profile": {
            "avatar_hash": "ge3b51ca72de",
            "status_text": "Print is dead",
            "status_emoji": ":books:",
            "real_name": "Egon Spengler",
            "display_name": "spengler",
            "real_name_normalized": "Egon Spengler",
            "display_name_normalized": "spengler",
            "email": "example@gmail.com",
            "image_original": "https://.../avatar/e3b51ca72dee4ef87916ae2b9240df50.jpg",
            "image_24": "https://.../avatar/e3b51ca72dee4ef87916ae2b9240df50.jpg",
            "image_32": "https://.../avatar/e3b51ca72dee4ef87916ae2b9240df50.jpg",
            "image_48": "https://.../avatar/e3b51ca72dee4ef87916ae2b9240df50.jpg",
            "image_72": "https://.../avatar/e3b51ca72dee4ef87916ae2b9240df50.jpg",
            "image_192": "https://.../avatar/e3b51ca72dee4ef87916ae2b9240df50.jpg",
            "image_512": "https://.../avatar/e3b51ca72dee4ef87916ae2b9240df50.jpg",
            "team": "T012AB3C4"
        },
        "is_admin": true,
        "is_owner": false,
        "is_primary_owner": false,
        "is_restricted": false,
        "is_ultra_restricted": false,
        "is_bot": false,
        "updated": 1502138686,
        "is_app_user": false,
        "has_2fa": false
    }
}
```

### JSON.parse(userInfo_str)
手前のメソッドでString型の情報を取得したが、ではSplitを使って情報を取得するのでしょうか？不可能ではないですが、酷く手間をかけるでしょう。
そこで、JSON.parse(文字列)を使います。返り値は万能型のObject型です。そうすると、先ほど示した"user"の"profile"の"email"を、「userInfo.user.propfile.email (→```example@gmail.com```)」と取得できます。

# ちなみに
会社で「データ編集中」というような、githubでコンフリクトを防ぐためスプレッドシートがありました。データを編集しているとその欄に自分のメアドが記入されるのですが、作業完了してもこれをよく消し忘れてしまい、ご迷惑をかけまくっていました。なので、Slackから「確認してくれ」と入力すると、たくさんあるスプレッドシートから自分のメールがある欄から「シート名：データ名」を出力してくれる仕組みを作ろう、と思った時のコードの一部です。

# まとめ
いかがだったでしょうか。今回は、GASでSlack APIを用いて、ユーザーIDからメールアドレスを取得するプログラムを紹介しました。

Web APIは結構難しいと思います。今回のプログラムも、とても簡潔に書いたつもりですが、行数で見れば大変そうに見えて、自力でやろうとすると心が折れかけます。そんなときに、日本語で解説してあり、コピペOKなものが見つかれば楽だよね...と思い、本記事を書きました。

このように、プログラミングやアプリ開発で得た知見・技術に関して、初心者〜上級者向けのいろんな記事を書いていこうと思います。主に、Unityでアプリ開発周りの知見が多くなると思います。
この記事が役に立った・気に入ったという方は、ぜひLGTM&フォローの方、よろしくお願いいたします。