Google Apps ScriptとMicrosoft Graph APIの連携 – Teams投稿編

対Slack用にMicrosoftがMicrosoft365に用意してきたチャットツールとして、Microsoft Teamsがあります。Googleで言えばHangout Chatがそれになります。このTeamsにエントリー投稿しかまだ出来ないのですが、Google Apps Scriptから投稿する事が可能です。Graph APIでも可能なのですが、TeamsにはWebookという便利な機能があるので、今回これを使ってみます。

Incoming Webhookへ送りつけるケースは通常のPOSTで送りつけるだけで送信出来ます。より詳細なコントロールをする場合は、Graph APIを使って認証を行った上でAPIリクエストが必要です。今回はこの両方について作成します。

※2018年7月12日より、Microsoft365ユーザ以外も無償版としてTeamsが使えるようになっています。サインアップが必要です。

難易度:


今回使用するファイル

事前準備

Microsoft Graph API連携の時と同じように、アプリケーションIDとシークレット、スコープを設定する必要があります。また、OAuth2.0認証の為に、ライブラリも追加しましょう。Webhookを使うケースは、Incoming Webhookを準備するだけでOKです。

※今回はチャンネルへの投稿なので、個人宛投稿については、別途Graph APIのchatMessage APIを利用する必要があります。

ライブラリの追加

以下の手順でOAuth2 for Apps Scriptライブラリを追加しましょう。

  1. スクリプトエディタを開きます。
  2. メニューより「リソース」⇒「ライブラリ」を開きます。
  3. ライブラリを追加欄に「1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF」を追加します。
  4. 現時点ではバージョンは30が最新ですので、それを選択しておきます。
  5. 保存ボタンを押して完了

これで、OAuth2.0認証にまつわる様々な関数を手軽に利用できるようになります。

コールバックURLを取得する

コールバックURLとは、認証を完了しAccess Tokenを取得したら戻るべきURLを指定するものです。これは、スクリプトIDをもとに作られているので、スクリプトIDを取得して組み立てます。

  1. スクリプトエディタのメニューより「ファイル」⇒「プロジェクトのプロパティ」を開く
  2. 情報の中にある「スクリプトID」を控えておく。
  3. https://script.google.com/macros/d/スクリプトID/usercallback として組み立てる。これがコールバックURLとなる。

図:スクリプトIDはファイル毎に異なるのです。

対象チャンネルのURLを取得する

Graph APIで叩く場合に必要です。このURLの取得はいたって簡単。

  1. ChromeでTeamsにログインする
  2. Teamsの対象のチャンネルを開く
  3. URLが出てると思うのでこれをコピーしておく
  4. あとで関数でこのURLからgroupIdとChannelIdを取り出すようにしています。

Azureプロジェクトの作成

  1. アプリの登録にて登録を開始する
  2. 新規登録をクリックする
  3. 名前を入力(今回はoutlookmanと入力しました)、リダイレクトURIは「webを選択しhttps://script.google.com/macros/d/スクリプトID/usercallback」を入力
  4. 登録ボタンをクリックする
  5. 出てきた中で、「アプリケーション(クラと書かれているのがクライアントID」なので、このコードをメモしておく
  6. 左サイドバーより、「証明書とシークレット」をクリック
  7. 「新しいクライアントシークレット」をクリックする
  8. 今回は特に有効期限を設けないで追加をクリック
  9. これで値に「クライアントシークレット」が生成されて手に入りました。このシークレットはこの時だけしか表示されないので、注意してください。
  10. つづけて、左サイドバーより「APIのアクセス許可」をクリックする
  11. Microsoft APIの中にある「Microsoft Graph」をクリックする。
  12. 「委任されたアクセス許可」をクリックする
  13. デフォルトでUser.ReadがすでにONなので、今回はProfile、User.Read、Files.ReadWrite、offline_access、ChannelMessage.Sendを検索してONにしましょう。
  14. アクセス許可の追加をクリックする
  15. 追加出来たら、xxxxxに管理者の同意を与えますをクリックします。すると、状態が緑色になります。今回は管理者の権限を要求するものは無いのでしなくても大丈夫だと思う
  16. 次に左サイドバーより「認証」をクリック
  17. 暗黙の付与にて、「アクセストークン」にチェックを入れる
  18. サポートされているアカウントの種類に於いては、「マルチテナント」にしておきました。
  19. 保存をクリック
  20. 概要のエンドポイントをクリックすると、いろいろなエンドポイントURLが出る。
  21. 概要のディレクトリ(テナントの数値はメモっておきます。あとでプログラム中で使用します。
  22. デフォルトでは組織アカウントでなければOAuth2.0認証が出来ません。フリーのMicrosoftアカウントでも認証できるようにするためには以下の手順が必要です。
  23. 左サイドバーのマニフェストをクリックします。
  24. マニフェストエディタが起動します。その中にあるsignInAudienceの値を「AzureADandPersonalMicrosoftAccount」へ変更して保存をクリック。これで例えばhotmailアカウントでも認証が通るようになります。

※3.でWebを選ばないSPAを選んでしまうと、Proof Key for Code Exchange by OAuth Public Clientsといったエラーが出てしまい認証ができませんので注意。

※個人アカウントでうまく動作しないなぁと思った場合には、Azure Portalのユーザ画面にてonmicrosoft.comのアカウントを作成してそれで認証作業を行うと良い。この時、グループとロールにおいては「アプリケーション管理者、クラウド アプリケーション管理者」の2つが割り当てられてればOKです。個人的にはこの作業をオススメします。以降、ログイン認証等もこのアカウントで行います。

今回のスコープは管理者承認が不要なものだけで構成されており、実はGroup.ReadWrite.Allの権限がなくても送信だけは行うことが出来ます(Graph Explorer上だとこの権限をアクセス許可で求められますが、ChannelMessage.Sendの承認のみでOK)

図:アプリの登録から全ては始まります。

図:Graphを選択する

図:スコープの設定で許可するアクションを選びます。

Incoming Webhookを追加する

Teams単体でもGraph APIを使って投稿ができるのですが、ID調べたりチャンネルID調べたりが面倒なので、この機能をTeamsに追加し、Webhook URLに対して投稿処理を実行します。以下の手順で追加します。

  1. Teamsの左サイドで「チーム」を選択します。チームを作成していない場合には適当に作成しておいてください。
  2. 作ったチームをクリックすると、デフォルトチャネルとして「一般」というものがありますので、その隣の「︙」をクリック。
  3. コネクタをクリックします。
  4. いろいろなコネクタが出てくるのですが、ここでは、Incoming Webhookを追加します。
  5. 構成画面が出るので、適当に名前を入れます。これが投稿者の名前になります。
  6. 投稿者の画像を変更する場合にはここで画像をアップロードしておきます。
  7. 作成ボタンを押して準備完了
  8. Webhook URLが下の方に出てくるので、コピーして控えておきます。このあとコード内に記述します。
  9. 完了ボタンを押して終了。

図:Incoming Webhookを追加します。

図:Webhook構成画面

ソースコード

今回、認証を行う部分のソースコードは準備編を参照してください。Teamsにエントリーを投稿する部分のコードを記載します。

Webhookへ送りつけるケース

こちらのケースはIncoming Webhookを追加しそのURLを叩くだけの簡単な仕様です。OAuth認証などは必要ありません。

HTML側コード(teams.html)

  • disp関数でGAS側のpostTeamChat関数へタイトルとチャット内容を送り込んでいます。
  • 送信時に連続送信しないように、プログレス表示に切り替えを追加しています。

図:チャット投稿用ダイアログ

GAS側コード

  • 今回のスクリプトは、graphapicall関数にpayloadの引数を1つ追加しています。
  • payloadには、タイトルとチャット内容を含めてPOSTで送り込みます。

Graph APIを叩くケース

こちらは、OAuth2認証が必要になります。そのため、複雑なコードが必要ですが、非常に細かなTeams操作が可能になります。

認証を行う処理を作成する

OAuth2 for Apps Scriptのページの「Create the OAuth2 Service」にあるコードを元に、Google Apps Script側で構築をします。この時、Microsoft365側で取得したアプリケーションIDやシークレットを使います。また、今回はいつもよりも要求するアクセス権限が多い点に注意が必要です

GAS側コード

  • 今回利用するGraph APIのエンドポイントはhttps://graph.microsoft.com/1.0となります。
  • 要求する権限はscopeに半角スペースで区切って、Azure AD側で用意したものと同じものを設定します。
  • startoauthを実行して認証を実行すれば、スクリプトプロパティにAccess Tokenが格納されます。
HTML側コード

template.htmlというダイアログ用のファイルを用意します。ここでアクセス承認を実行し、ログインをすると、アクセストークンその他が取得可能になります。

  • 実際にこれらのコードで、startoauthを実行すると、スプレッドシート上で認証用のダイアログが出ます。
  • 認証でMicrosoft365アカウントにログインします(もしくは作成したonmicrosoft.comのアカウント)
  • 取得したAccess Tokenほかはスクリプトプロパティのoauth2.Graphという項目にガッツリ値が格納されます。ここにはAccess Token, Refresh Token, expire_inのタイムなどが入っています。
  • reset関数はログアウトされて、再度認証ができるようになります。
  • Chrome v83.xを利用している場合、認証実行時にリダイレクトURLにジャンプ出来ずにエラーになることがあります。認証用URLの中のredirect_uriの文字がオカシナ文字に置き換わっていてredirect_uriが違うと怒られるケースがあります。その場合はURLを直接リダイレクトURIの部分を書き換えてください。

図:無事に認証画面へ到達出来た

図:スクリプトプロパティにAccess Tokenが格納された

Graph APIを叩く関数

  • メール送信はPOSTメソッドを使って送る必要があります。
  • urlfetchAppのQuotaはGsuite Basicの場合、100,000回/日呼び出し以外にも、連続して利用する場合には同一アカウントで実行時に10秒間に2アクセスが限界(それ以上になると、3回目のアクセスで403エラーや429エラーが発生する)。sleep処理が必須です。
  • TeamsのチャンネルURLからgroupIdとchannelIdを取り出す関数を別途用意して利用しています。
  • bodyにimportantをつけると、メッセージ重要度を変更することができます。Highで重要というメッセージに変わります。
  • メンションを送る場合には、bodyのcontentTypeはhtmlでなければなりません。
  • bodyのcontentにメッセージ本文を入れます
  • mentionsは基本このままのスタイルでつけると、そのチャンネル全員に対してメンションになります。
  • conversationのidはchannelIdと同じIDを利用します。これが送信先チャンネルへのメンションとなります。
  • メンションを使う場合は、bodyのcontentに必ず<at id = 0>メンション名称</at>を加えるようにします。そうでないとメンションを送れません。

実行と結果

まずはともあれ、認証を実行しAccess Tokenを実行しましょう。メニューより「OAuth認証」⇒「認証の実行」をして、Microsoft365側の認証を取得しておきます。その後、メニューより、「Teams投稿」⇒「エントリーの投稿」を実行すると、チャット投稿用のダイアログが出現します。ここにタイトルとチャット内容を投稿することで、Teamsエントリーが投稿されます。

投稿内容は、スプレッドシートにも記録として書き込みがなされます。

図:OAuth認証の実行画面。承諾しましょう。

図:Webhookからの投稿が反映しています。

図:Graph APIからの投稿が反映しています。

個人宛にチャットを送る場合

事前準備

前項までの方法は、チャネル宛にメッセージを送る方法です。個人(もしくは複数名)宛にチャットを送信したいケースは結構あると思いますが、そのためにはChatMessageのAPIを利用する必要性があります。しかし、送信するには「Chat-ID」が必要であり、このIDの取得が結構厄介です。よって予め、データベースとして対象のメアドを元に

  1. 対象ユーザのユーザIDを取得する(例:1234dcee-5678-9a10-bc11-12e1dfad314bのような文字列が取得できる)- GETメソッド
  2. ユーザIDを元に自身のユーザIDと対象ユーザのIDの2つ以上を元にチャットの作成(例:19:1234dcee-5678-9a10-bc11-12e1dfad314b_2468dff1-ba01-2ea1-a4bd-1d82022f2428@unq.gbl.spacesのようなChat-IDが取得できる)。この文字列は、19:自身のユーザID_相手のユーザID@unq.gbl.spacesで構築できる(ユーザIDの区切りはアンダーバー) – POSTメソッド
  3. このChat-IDを元にメッセージ送信をJSON形式のBodyでメッセージ指定をして送信 – POSTメソッド

の手順で送信が必要です。1:1であれば、2.のChat-IDは簡単に行えるので、実質、3.の送信部分が壁になります。

※1:1の場合は、@unq.gbl.spacesのようなChat-IDになりますが、複数名でのグループチャットの場合は、2.の手順で作成をする19:4e5cb6968cdf48d7af9f5375970cda4b@thread.v2といった@thread.v2のついたChat-IDになるので要注意です。

チャットの送信

Chat-IDを取得することが出来たので、これを元に以下の手順でGraph Explorerでテストしてみます。

  1. Graph Explorerを開き、組織アカウントでログインしておく
  2. 送信メソッドはPOSTを指定
  3. v1.0を指定
  4. https://graph.microsoft.com/v1.0/chats/chat-id/messages をクエリ欄に入力
  5. 要求ヘッダは、キーはContent-Type、値はapplication/jsonを指定する
  6. アクセス許可の修正にて、Chat.ReadとChat.ReadWriteに許可を与える
  7. 要求本文は、以下のようなJSON形式でメッセージを入れておく

なお、これをGraph APIで叩く場合には、AzureADのAPIのアクセス許可では、

  • Chat.Read
  • Chat.ReadWrite
  • Chat.Message.Send

の3つを追加しておく必要性があります。いずれも管理者の承認は不要です。これを元に、前述の認証を行う処理を作成するの項目にて、Scopeに追加しておき認証を実行。関数の中では、エンドポイントとして4.のクエリ、bodyに要求本文を追加してHTTPリクエストで叩けば、Node.jsから個人宛にチャット送信が可能です。

※トークンリフレッシュ時のコードにもscopeがあるので追記が必要です。

図:APIのアクセス許可は複数必要

図:Graph Explorerでメッセージ送信テスト

関連リンク

共有してみる:

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください。

前の記事

Cloud PrintをGoogle Apps Scriptから使う