🈲

# GASとLINE連携して、応答bot作ろうと思ったらドハマリした話

に公開

LINEのwebhook応答の「2秒ルール」、無料アカウントでのID取得の厳しさ、等々にめちゃめちゃ振り回された話です。

AIを使って、個人でGASとLINEの連携でなにか小規模開発を考えている人向けの記事です。

僕自身がプログラミングスキルはヒヨっこなんで
経験豊富な方から見ればアホなこと書いてると思いますが、ご笑覧ください。

Notionと連携してリマインダを作りたかっただけなのに

始まりはここからでした。
仕事のタスクデータベースをNotionに作っているので
それをLINEでリマインドできればいいな、と、よくある感じでスタートしました。

といっても
僕の本業は
WEBライティングとか
LステップでステップLINEの構築とか
商品宣伝の動画の台本作成とか

どちらかというとマーケ寄りなので
プログラミングのスキルは全然です。

また今度、詳細な記事を書きますが
ここ数年のAIの進歩のお陰で、まがりなりにもコードが書けるようになり
めちゃくちゃAIの恩恵を享受しているタイプの人間です。

特にCursorの出現はデカかった!
それまでコピペでいちいち各AIに作成途中コードを投げなくてはいけなかったのが
サクサク背景事情を理解してくれるのがありがたいのなんのって✨

素人の状態から、いきなり数万行のコードを書いたのは良い思い出です。

まあこのへんは、脇道へそれる話になるので本題へ。

Cursorを使って、Notion→GAS→LINE公式アカウントの連携へ

このへんの詳細なやり方は、僕なんかが足元にも及ばない諸先輩方が
各所にわかりやすい記事を上げてると思うので、割愛します。

Notionのタスクデータベースを読み込んで

翌営業日が期限のタスクを見つけて

担当者に、リマインド文を書いたLINEを送る

という機能を作りたいと思ってました。

(最終的に作ったコードは、僕のしょーもない初心者向けのコメントつきで、後段に全部載せます)

doPostの地獄へ

LINE公式アカウントが用意できたので

じゃあ、まずCursorにさくっとdoPostを書いてもらって
リマインドを送りたいLINEグループのIDを取得しよう


そして
ついでに
メンション機能をつけよう!

と思ったのが、迷走の始まりでした。

doPost: LINE側からGASに送られてきた内容を処理するには、必ずこの名前に関数(機能)をコード内に書かないといけない

メンション機能: @ ●●さん みたいに、青文字になって誰宛てのメッセージか、LINEでわかりやすくする機能

🔵 ハマりその1: ユーザーIDの取得がめんどい!

タスクのリマインドするにも、送り先がわからないとコードは動いてくれないわけで
グループ(or 名称未設定複数人トークルーム)のIDを取得する必要があります。

でもこのへんは、Cursorに

doPostで、LINE公式アカウントがグループに参加(joinイベント)したときに、グループIDを取得するGAS書いて

って投げれば秒で作ってくれるし、それで動きます。

問題は
ユーザーIDの取得でした。

メンション機能を使うには、ユーザーIDの取得が必須です。

まず前提として、昨今のLINE社の方針として
個人情報保護の観点から、ユーザーIDの取得のハードルがかなり高いです。

基本的に公式アカウントを友だち追加してもらって、1:1トークで何かしらメッセージを送ってもらわないと、ユーザーID取得できません。

でも、コードを書き始めた時の僕は、そんなLINE社の姿勢や昨今の環境なんか知りません。


AIからは

「グループに公式アカウントが招待された瞬間に、グループIDと、参加しているユーザーIDが全部取得できるよ!」
と調子の良い返答が来ます。

当然そんなコードでテストしてみても、ユーザーIDは取れません。

AIを問い詰めたら

とのこと。

送信可能メッセージ数が多くなるような「有料プラン」に入っても関係ない
あくまでLINE公式が認証しない限り無理

とのこと。

最初に言えよマジで
と。

AIあるあるの
こちらのコンテキストを全部説明しとかないと頓珍漢な回答をされる
という洗礼を浴びたわけです。

じゃあユーザーID取得どうすんの?

たかが仕事の補助のリマインドbotで認証取得なんかやってられません。

その場合は以下です。


・memberJoinedイベントで取得する
つまり、先に公式アカウント(以下bot)をグループに入れといて、あとから来た(joinした)メンバーのIDは取得できるようです。

ということは
既に作ってあるグループにbotを招待しても
時既に遅し、ということになります。(既にみんな参加して、あとから来る人はいないから)

じゃあ他にないのか、というと

・messageイベント
誰かが発言したときに、その人がbotを友だち追加済みであれば
ユーザーIDが取得できる
ということでした。

じゃあその2本柱で運用しよう、ということでテスト開始。

すると、あらラッキー

友だち追加されていないアカウントでも
スプレッドシート(以下スプシ)に書かせたログには
ユーザーIDが書き込まれていました!

addMember_: 開始 (sourceId: C4XXXXXXXXXXXXXXXXX, userId: UbXXXXXXXXXXXXXX)

LINEの方針がさらに厳しくならない限りは、memberjoined、message、両イベントの2本柱で、ユーザーIDを取得するのが良さそうです。

🔵 ハマりその2: メンション機能の実現がめんどい!

ユーザーIDがわかったので、意気揚々と
AIに言われた通りに実装しても全然メンション機能が反応しない。


Cursorのモデルを Claude4.5にしようがgpt5にしようが
全然原因がわからず

Cursorから離れて、普通にchatGPTのo3に聞いて、ようやく判明します。

これ実は
LINEのbotで、メンション機能が使えるようになったのって
2024年10月から

AIはそれ以前のデータも混ざってるから、ふつーにハルシネーション起こされてたわけです。

参考↓(僕とは無関係な方の記事です)

https://qiita.com/n0bisuke/items/2eac7089a7bda8f3cfba

重要なのは
LINEメッセージを作る関数で

substitutionというプロパティの中に、メンションデータを入れること

AIに再説明させた内容は以下です。

 @memo LINEメンションの仕組み (textV2 方式)
 LINEで特定のユーザーにメンション(通知)を送るには、textV2 という新しいメッセージ形式を利用します。
    1. メッセージ本文 (text):
    - 本文中に `@ユーザー名` と直接書く代わりに、`{m0}` `{m1}` といったプレースホルダーを埋め込みます。
    -: `{m0} {m1} お疲れ様です。`

    2. プレースホルダーの定義情報 (substitution):
    - どのプレースホルダーが、どのLINEユーザーIDに対応するのかを紐付ける情報を substitution オブジェクトとして渡します。
    - 具体的には、`{ m0: { type: 'mention', mentionee: { type: 'user', userId: '...' } } }` のような形式です。

🔵 ハマりその3: doPostの時間制限がしんどい!

LINEからイベントデータ受け取って、2秒以内にOKを返さないとタイムアウト(エラー)扱いになる仕様がマジでしんどいです。

これもはや「応答botとかは大規模システムでやって、GASなんかで運用すんな」
っていうLINE社のステルスメッセージな気がします。

いや、LINE側に「これタイムアウトエラーや」って認識されても、別にこっちでちゃんと機能が動けば、ぶっちゃけ知ったこっちゃないんですが

botの規模感が大きくなってくると
さすがにペナルティ食らったりするの怖いですからね。

以下執筆中

・とにかく最速応答になるように、前処理をdoPostの外に分けて、トリガーで叩くようにした

・そうするとGASの仕様上、全部の処理が最低でも1分後になる(トリガーは1分単位だから)

・HtmlサービスでOK返すと302エラーは少なくとも出ない

・全部1分遅れってことは、即時応答botの機能は少なくとも使えない

・即時応答の内容はスクリプトプロパティに読み込ませといて、即時応答での返信内容はテキスト限定(画像はあきらめる)にするのか

・タイムアウト上等で即時応答botをこれまで通り↓運用するのか

https://zenn.dev/sh102/articles/c7b36f41d61ebc

とりあえず書いたコードは、順次下記記事に掲載

https://zenn.dev/sh102/articles/ef54872fe80014

Discussion