【GoogleAppsScript】スマホからワンタップ、GAS経由でGmailを送る方法

***
# 注意
本記事で実装しているコード及び、レシピ、設定等は、セキュリティリスクを許容している勉強用のサンプルです。実運用される際は、各自でセキュリティ実装を行い、自己責任でお願いします🤲
***

![image.GIF](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124955/e0f6f29e-1309-fe07-8835-aee023760a81.gif)


# TL;DR
- サーバ側(GAS)の[サンプルコード](https://github.com/karoot/Webhook2Gmail/blob/master/code.gs)
- クライアント側(ショートカットアプリ)の[サンプルレシピ](https://www.axfc.net/u/3988146)
-  サーバ側、クライアント側の環境変数設定を忘れずに


# 背景
サードパーティからのGmail送信が規制<a href="#1">\*1</a>されていく中で、簡易的にGmail送信をできる方法を考えてみました。以下では、iOSのショートカットアプリ(旧 workflowアプリ)とGoogleAppsScript (以下、GAS)を使ってGmailでの送信を実装しています。


# 試行手順
- GASとは
- GASアカウント取得
    - GASの導入を丁寧に解説していただいている[記事](https://qiita.com/riversun/items/c924cfe70e16ee3fe3ba)がございましたので、本記事では割愛させていただきます。
- プロジェクトの作成
    - GASコンソールから、新規にプロジェクトを作成してください。(プロジェクト名はお好きに)
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124955/a59476a3-33b0-6bfa-5a8a-9aeb812df8ee.png)

- コードコピー
    - [サンプルコード](https://github.com/karoot/Webhook2Gmail/blob/master/code.gs) を新規プロジェクトのコード.gsにコピーしてください。(コード名はお好きに)
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124955/ca7276b8-a693-ce24-6e62-b43b8ab662c1.png)

- 環境変数設定(スクリプトのプロパティ)
    -  コード表示部の上、[ファイル]→[プロジェクトのプロパティ]→[スクリプトのプロパティ]
     - _DEST_ADDRESS:送信先のメールアドレス(今回のサンプルコードだと固定の宛先に送る仕様です)
     - _TOKEN:クライアント側(本実装だとiOSショートカットアプリ)と共有するパスフレーズです(パスフレーズは英数字記号を混在をオススメします)
     - 上記2つのパラメタを設定します
 ![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124955/65c59493-a1c1-db48-bf3f-bc8b62baacc7.png)

- ウェブアプリケーションの公開
    - 公開範囲の設定を、リスク<a href="#3">\*3</a>をご理解の上、 "全員（匿名ユーザを含む）"で公開にするとショートカットアプリからのHTTP(S)リクエストを受けることができます。
    ![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124955/d59d18e9-e3cb-e506-181d-276bbef6290e.png)
        - 公開後、URLが表示されるので、コピーしてメモしておいてください。
        - 今回は実装までの最短手順を示しているため、全体公開にしてますが、本来であれば、[Restlet Client](https://chrome.google.com/webstore/detail/restlet-client-rest-api-t/aejoelaoggembcahagimdiliamlcdmfm?hl=ja)等のテストツール使用し、検証さることを推奨します。

    - 認証
        - 上記の公開範囲の設定の途中で以下のポップアップが表示される可能性があります。
        ![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124955/4d92249b-2e2c-8dce-5c4e-6949f7f0b71e.png) 
        - これは、コード内部で```MailApp.sendEmail```使用してメール送信を実装しているため表示されています。
        - 本スクリプトからGoogleアカウントへメール関連の認可の可否が尋ねられるので、確認してください。<a href="#2">\*2</a>
 ![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124955/a2add517-c887-0742-a45e-db336e8e21d1.png)

- ショートカットアプリのレシピ作成
    -  [サンプルレシピ](https://www.axfc.net/u/3988146)をiPhoneのショートカットアプリで読み込んでください。

-  iOS側の環境変数設定
    - リマインダー"環境変数"リストを作成
    - 以下、2つのタイトルでタスクを作成し、それぞれのメモ欄にパラメタを設定ください
        - タイトル「gas_webhook2gmail_apikey」
            -  メモ欄:GASの環境変数で定義した_TOKEN(パスフレーズ)と同様の値を設定します
        - タイトル「gas_webhook2gmail_url」
            -  メモ欄:GASの公開時に表示されたURLを設定します
         <img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124955/535d96a8-9be0-878e-f75e-5ca49e12ad6e.jpeg  width=50%>
    - <span style="color: #ff0000">この2つ環境変数が他者に流出しますと、ご自分のメールアドレスの送信を不特定多数の第三者に悪用されてしまう可能性がありますので、厳格に管理ください</span>
- 準備完了
    -   以上で、サーバ/クライアントの準備は終わりました。ショートカットアプリからレシピをタップし、結果でsuccesと出ればメールが飛んでいるはずです。


# 解説
![Webhook2Gmail.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124955/355ecd0c-8a1a-6969-3922-dd74ee4ef646.jpeg)

## 全体構成
- トリガーは、iPhoneのウィジェットのタップにより実行
- ショートカットアプリにて、メッセージの入力、JSONリクエストの組立を行い、 GAS側の公開URLへHTTP(S)のPOSTリクエストで実施。
- GAS側でJSONからパラメタ取得、ハッシュチェックを実施、Gmail送信apiをコール。
- Gmailからスクリプトのプロパティで設定した送信先へメールが飛ぶ

## コード
- PropertiesService.getScriptProperties().getProperty
    - プライベートキーをコードに書きたくなかったので、スクリプトのプロパティに変数として設定しておき、getすることでコードの公開時に消す等の煩雑な作業を無くしました。setコマンドもあるので、ちょっとしたパラメタはスプレッドシートでは、なくてもいいかもしれません。
- doPost(e)
    - 本コードのメイン関数。GASのお作法としてfunction名をdoPostにすることで、POSTメソッドを受け取った際にはこの関数が呼び出される。仮引数eは、クライアントから渡されたオブジェクトを指す。doGetと記載するとGETメソッド時の処理を書ける。
-  jsonParse(e,parseName)
    - GASではPOSTで受け取ったオブジェクトを`Content-Type`で判断せず、一律[FileUpload](https://developers.google.com/apps-script/reference/ui/file-upload)クラスとして扱っているため、一度まとめて`params`の箱に入れて、その後対象パラメタに絞り取得している。
- tokenCHK(auth)
    - JSONのauthパラメタを取得、現在日時とパスフレーズを足してハッシュ化。通信経路上で盗聴したリクエストを再送し、サービスダウンを狙うリプレイ攻撃対策として、現在時間をクライアント、サーバ双方で計算するようにしました。
- toGmail(mailBody)
    - JSONのmailbodyパラメタから取得した値を仮引数として受けて、`MailApp`クラスを使いメール送信を実施している。今回のサンプルでは、送信先メールアドレスやメールタイトルは、固定にしていますが、実装次第では可変にすることもできると思います。

## ショートカットレシピ
- レシピを眺めれば日本語で書いてあるので、基本説明不要かと思いますが、サンプルコード同様に公開することを前提に書いていたのでプライベートキーについてはリマインダーを読み込むことで実現しています。

# 残課題
- URLとパスフレーズの２つで認証としているが、URL自体は通信経路で盗聴されていれば、誰でも取得できるものなので、認証強度が低い。
- 不正攻撃への検知の仕組みがない。

# まとめ
サービスとしては車輪の再発明でしたが、個人的にJSON解析や残課題はあれど全体公開をする際の留意する点などを考えることができたという意味では、勉強にはなりました。その中で、WEBAPIで実装すべきセキュリティ観点って意外と日本語では、まとまってないなと感じました。広義ではAPIもwebサービスなので、参考にすべき資料はいっぱいあるのですがジャストでこれというものがないという印象。(ググり力不足かもしれません)


# 余談
- 今回クライアント側に使用した、iOSのショートカットアプリ、便利でいいのですがアプリ名が汎用的過ぎてググるのに苦労します。もっとユニークな名前を付けてほしかったです 笑
- コードを書いた時間<ショートカットのレシピ作成時間<この記事の執筆時間
- もっと記事をサクッと書けるようになりたい。。。


# コード実装時に参考にさせていただいた記事
[REST セキュリティに関するチートシート](https://jpcertcc.github.io/OWASPdocuments/CheatSheets/RESTSecurity.html)

[Qiita - スプレッドシートで覚えるブロックチェーン |「もしかして渡した値」「入れ替わってる！？」](https://qiita.com/benridane/items/2b7caa9df9445b6991bb)

[Google Apps ScriptのdoPostでJSONなパラメータのPOSTリクエストを受ける](https://qiita.com/shirakiya/items/db22de49f00710478cfc)

[Qiita - 【GoogleAppsScript】doPost のリクエストパラメータでHTTPヘッダを取得することはできない](https://qiita.com/kroot/items/d8a55d8f9cc1d0921917)

[GASへのPOSTリクエストの返り値の受け取り方](https://mtane0412.com/how-to-receive-return-value-of-post-request-to-gas/)

[Google Apps Scriptをウェブアプリケーションとして公開する手順](https://www.virment.com/how-to-deploy-google-apps-script-as-webapp/#URLURL)

[Qiita - GASでのメール送信についてまとめてみる](https://qiita.com/mistolteen/items/404c10657b1b27007a3c)

***

<span id="1" style="font-size:small">1:workflow標準のレシピでも以前はGmail連携はできていましたが、左記の事情により現状連携ができなくなっているみたいです[Google、個人情報へのサードパーティーアプリからのアクセス制限を強化](https://www.itmedia.co.jp/news/spv/1810/09/news070.html) </span>

<span id="2" style="font-size:small">2:認可時に表示された(認証した)Googleアカウントを GASの送信元としてメールは送信します</span>

<span id="3" style="font-size:small">3:ここでは、iOSのアプリからのアクセスを許容するため、公開範囲を全体にしています。多少のセキュリティ実装はあれど、ご自分のgmailを不特定多数がアクセスできるインターネット上に晒すことに繋がります。セキュリティリスク(不正送信、なりすまし等)のご理解の上、ご使用ください。 </span>