facebook Graph API を使ってworkplaceのグループチャットに添付ファイルを送信する


この記事は [MicroAd Advent Calendar 2021](https://qiita.com/advent-calendar/2021/microad) の7日目の記事です。

## 背景など

マイクロアドでは、社内コミュニケーションツールとしてWorkplaceという社内SNS的なものを使用しています。

システム的には、ビジネスサイドや営業サイドのメンバーに通知したいときに、バッチ処理でWorkplaceのグループチャットにメッセージを送信するなどしていますが、その処理にfacebook Graph APIを使用しています。

参考

https://qiita.com/mtakagi555/items/9ce78624f4ea32e0a365


## メッセージ通知の制約
workplaceのグループチャットにメッセージを送信することはできるのですが、
・文字数上限が2000文字
・チャットは横幅が狭いので、長い文字列は折り返されて見づらい
という問題があります。

そこで、それなりの分量のメッセージを送信したい場合は、添付ファイルとしてメッセージを送信することができます。

## 添付ファイル送信に使用するAPIの概要

2段階構成で添付ファイルを送信することができます。

#### 1. Attachment Upload API

添付ファイルをアップロードするAPIです。
成功すると、添付ファイルIDを返してくれます。※この時点ではまだチャットにメッセージは送信されていません。

```
https://graph.facebook.com/v10.0/me/message_attachments?access_token=<PAGE_ACCESS_TOKEN>
```

#### 2. Send API

メッセージを送信するAPIです。
様々なオプションがあり、↑で取得した添付ファイルIDをパラメータに指定することで、添付ファイルをメッセージすることができます。

```
https://graph.facebook.com/v10.0/me/messages?access_token=<PAGE_ACCESS_TOKEN>
```

## 実際に添付ファイルを送信してみる

### サンプルコード

```qiita.txt
workplaceに送信する
ファイルの内容です。
```

```post_message_attachments_app.py
from datetime import datetime
import os
import requests
import subprocess
import textwrap
import json
import time

GRAPH_URL_PREFIX = "https://graph.facebook.com/v10.0"

TOKEN = os.environ.get('TOKEN')  # 環境変数に入れておくと管理が楽かも

THREAD_KEY = "t_1234567890123456"  # 適当な数字にしています

FILEPATH = './qiita.txt'

def _message_attachments():
    """
    ファイルをworkplaceのサーバに送信する
    この時点ではまだメッセージとしては送信されていない
    attachment_idが取得できる
    """
    graph_url = GRAPH_URL_PREFIX + '/me/message_attachments'
    curl_url = graph_url + '?access_token=${TOKEN}'

    form_message = 'message={"attachment":{"type":"file", "payload":{"is_reusable":true}}}'
    form_filedata = 'filedata=@' + FILEPATH

    cmd = f"""
        curl --form '{form_message}' --form '{form_filedata}' "{curl_url}"
    """
    cmd = textwrap.dedent(cmd).strip()
    print(f'execute command:{cmd}')

    proc = subprocess.run(cmd, shell=True, encoding='utf-8', stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    proc.check_returncode()

    ret_json = json.loads(proc.stdout)
    if not 'attachment_id' in ret_json:
        print('attachment_id is not in response.')
        return 0
    attachment_id = int(ret_json['attachment_id'])
    print(f'attachment_id:{attachment_id}')
    return attachment_id


def _send_file_message_workplace(attachment_id):
    """
    workplaceのサーバに送信したファイルを、添付ファイルとしてメッセージ通知する
    """
    headers = {
        'Content-type': 'application/json',
        'Authorization': 'Bearer ' + TOKEN
    }

    data = {
        "recipient": {
            "thread_key": THREAD_KEY
        },
        "message": {
            "attachment": {
                "type":"file",
                "payload":{
                    "attachment_id": attachment_id
                }
            }
        }
    }
    print(f'data:{data}')

    graph_url = GRAPH_URL_PREFIX + '/me/messages'
    print(f'graph_url:{graph_url}')

    response = requests.post(graph_url, headers=headers, json=data)

    if response.status_code == 200:
        print('OK')
    else:
        print('NG')


if __name__ == "__main__":
    if TOKEN is None or TOKEN == '':
        print('TOKEN is not set')
        exit(1)

    print('--- call _message_attachments ---')
    attachment_id = _message_attachments()

    if attachment_id:
        print('--- call _send_file_message_workplace ---')
        _send_file_message_workplace(attachment_id)
```

### 実行

```bash
python3 post_message_attachments_app.py
```

### 実行後

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/870283/add703e2-4995-be54-fb2c-2d4a0eec8c47.png)

## まとめ

添付ファイルをメッセージ通知することができました！

## 参考

グラフAPI 概要
https://developers.facebook.com/docs/graph-api/overview

Sending Messages
https://developers.facebook.com/docs/messenger-platform/reference/send-api

Attachment Upload API Reference
https://developers.facebook.com/docs/messenger-platform/reference/attachment-upload-api/