IFTTTからMake（旧Integromat）に完全移行。Google GASではじめる無料プッシュノティフィケーション

# まえがき

IFTTTが有料化されて久しいわけですが、初年度は無料、その後は言い値キャンペーンにのっかって \\$2/月で使えていたものが、いつの間にか勝手に\\$3、\\$4と値上げされ、円安も相まって結構なコスト負担になっていました。
最後にダメ元でIFTTTサポートに直談判してみましたが、バリューセリングをされるだけだったので解約を決意したわけです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206965/4a1e911a-f9b1-72fc-73ec-170be6dc8cfd.png)
相当数のIFTTT Appを作成してあったため、すき間時間を使って整理／移行仕切るのに3ヶ月を要しました。
この際、IFTTTに依存していたサービスを概ね次のように移行することにしました。

|対象|移行先|
|:-|:-|
|**JS/TS（スクリプト（ロジック全般））**|基本はGAS、doGet/doPostでWebSocketもカバー出来るので便利。どうしてもとなればLambdaを使えば良い。|
|**LaMetric**|GASからネイティブのAPIをコール。但し、別の記事に書いたとおりルーター越えが必要なので別途DMZなりポートフォワードの設定なり必要。|
|**SwitchBot**|GASからネイティブのAPIをコール。イベント受信もGASを利用。|
|**PushNotification**|Make（旧Integromat）により月1,000通知まで対応が可能。|

今回は最後まで移行先の策定に時間が掛かった、4番目のPushNotificationについて書いていきます。何故時間が掛かったのかといえば、前に調べたPushBulletも7Pushも動かない（通知が来ない、期待動作しないなど）状況で、他のサービスを色々と試さなくてはならなかったからです。
出来そうに見えてスマホ（iOS, Android）に通知出来ないものも多く、無駄足も多く踏みました。完全無料ならばありがたいのですが、通知を送るためのサーバー維持はする必要がある訳なので買いきり\\$5のPushoverも悪くない選択でしたが、1,000通/月送れれば問題ないのでMake（旧Integromat）で行くことにしました。

:::note info
Make（旧Integromat）なら無料で1,000通までPushNotificationを送れる。

但し、無料のステップ枠が1,000なので**Webhook**→**通知**という2ステップが最低必要になることから、実質的に無料で送れるPushNotificationは**500通/月**となります。アカウントを複数登録するという荒技はありますが……。
::::::



# 1. MakeとPushoverの概要

### 1-1．Make（旧Integromat）

サービス・管理ページ

https://www.make.com/en

言わずと知れた、IFTTTやZappierと並び様々なWebサービスを繋ぎコメルベンリサービスとして名を馳せたいちサービスです。有料コースでは1,000円/月とまぁまぁのコストが掛かります。

:::note alert
データベースなども使えて便利で、実際にプロダクションレベルで一回使ったことがありますが、障害が出て動かなかったり、フローがまるっと消えたりする事があったため、あまりプロダクションに利用することはお勧めできません。
:::

:::note alert
また、サーバーが日本にはないため国内サービスが必須になるようなサービスでは選択肢から外れます。
:::

今回のように個人のレベルで折り合いが付く用途であれば、無料で使えてとてもありがたいサービスです。

### 1-2．PushOver（予備情報）

Pushover, LLCが2012年から運用しているサービスで、個人運用では無いのかもしれませんが実態が不明な点が気になるものの、10年以上運用されているのでひとまず一定の実績はありそうです。

https://support.pushover.net/i45-who-runs-pushover

# 2. 準備

### 2-1. 登録
先ずはMakeに無料アカウント登録をします。Googleアカウントなどでも利用できますし、メアドを登録して利用も出来ます。昔はエイリアスを使って複数アカウントを取れたりもしましたが、今は出来ません。

### 2-2. スマホ側設定
iOSでもAndroidでも先にアプリをインストールして登録済みのMakeユーザーIDで端末紐付けを行っておく必要があります。私は主にiOSを使うので前者を選択し、iPhone 12という名前を付けて端末を紐付けしました。
通知はこのMakeアプリを通じてポップアップしてきます。その際に通知タイトル、本文を見る事が出来ますが、本文が長い場合はURLを含む場合はタップして全文を表示したり、URLに飛んだりするように作り込んでいきます。

# 3. GASでサイトを準備

Makeアプリは通知を受けてタップした時の動きとして、ブラウザーを開くか、Makeアプリ自体を開くどちらかしか選択出来ません。後者は通知内容を見ることも出来ず意味がありませんので、ブラウザー（Web）頼みとなります。

そこで、あらかじめ本文を表示するための簡単なWebアプリをGASを使って構築しておきます。いい加減なバリデーションチェックをしてますが、自分しか使わないのでこの辺りのこだわりは個々人でさじ加減を考えてください。

```javascript:通知内容表示用Webアプリ.gs

const IS_DEBUG = false;

function doGet(e) {
  if (IS_DEBUG) console.log(JSON.stringify(e, null, 2));
  var title = ("title" in e.parameter ? e.parameter.title : null);
  var message = ("message" in e.parameter ? e.parameter.message : null);

  var html = HtmlService.createTemplateFromFile("index");
  html.title = (title ? title : "");
  html.message = (message ? message :"");

  if (IS_DEBUG) console.log(`${title} ${message} ${html}`);

  // index.htmlを読み込んで返す
  return html.evaluate().addMetaTag("viewport", "width=device-width, initial-scale=1").setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}
```

スマホで表示する前提なので
***addMetaTag("viewport", "width=device-width, initial-scale=1")***
を追加しておきます。これはGAS独自のメタタグ追加方法なので注意が必要です。
inde.htmlも用意しておきます。

```html:index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <title>メッセージ内容</title>
    <style>
      body {
        font-family: Arial, sans-serif;
        margin: 0;
        padding: 20px;
        box-sizing: border-box;
        line-height: 1.5;
      }

      h1 {
        font-size: 2em;
        text-align: center;
      }

      p {
        font-size: 1.2em;
        text-align: center;
      }

      button {
        display: block;
        margin: 20px auto;
        padding: 10px 20px;
        font-size: 1.2em;
        background-color: #007BFF;
        color: white;
        border: none;
        border-radius: 5px;
        cursor: pointer;
      }

      button:hover {
        background-color: #0056b3;
      }
    </style>
  </head>
  <body>
    <h1><?=title?></h1>
    <p><?=message?></p>
    <button onClick="window.top.close()">ウィンドウを閉じる</button>
  </body>
</html>
```
言わずもがな、以下の二つのプレースホルダーにタイトルとメッセージ本文が入る形になります。
* \<?=title?>
* \<?=body?>

最後に、こちらをウェブアプリとして一般に公開しておきます。自分しか使わず、Googleログインしていない場合はログインが必要になることを前提とするならば、自分が自分のアカウントで利用するようにしておけばセキュアになります（元々、セキュアなデータを持つようなサイトではないのであまり関係ないと思いますがお好みで）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206965/5c5f6bb7-99c1-ebfc-2aa9-0564c6c3d425.png)

# 4. Make設定
Webhookへのアクセスを受けて、Notificationを送る2コマだけのフローを作成します。この時、起動はWebhookでGetパラメーターにて以下のようなURLを受け取るようにします。
* title
* body
* url

実際のURLはこんなイメージで構成されます。
```javascript:URLイメージ
https://hook.us1.make.com/xxxxx/?title=title&body=body&url=url
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206965/fa974745-476d-f6b1-334c-81be2d77025c.png)

PushNotification送信用のコマはiOSが対象の場合はApple iOSを、Android OSの場合はAndroidを選択します。私は主にiOSを使うので前者を選択しましたので、あらかじめ登録済みの端末名iPhone 12を選択しつつ、送信する通知の内容はGetパラメーターを利用して次のようにしました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206965/bb9ca6f2-4e24-fd15-e8c8-c3f34ab2d624.png)

各パラメーターのポイントは以下の通りです。

| キー | 内容 |
|:-----------|:------------|
|**Title**|Getパラメーターで受け取ったtitleを引き渡します。|
|**Body**|Getパラメーターで受け取ったbodyを引き渡します。|
|**Action**|ブラウザーを立ち上げたいのでOpen browserを指定します。Makeアプリはブラウザーを開くか、Makeアプリ自体を開くことしか出来ません。後者は通知内容を見ることも出来ず意味がありませんので、ブラウザー（Web）頼みとなります。|
|**URL address**|実際にブラウザーで開くURLです。ここでは既にデプロイして公開済みのGASサイトのURLを指定しますが、以下のようにurlが渡された場合と、渡されなかった場合で条件分岐し、必要なURLエンコードを施したような文字列とします。|

```diff_javascript:URL address
{{if(length(1.url) + "=0"; "https://script.google.com/macros/s/xxxxx/exec?title=" + encodeURL(1.title) + "&message=" + encodeURL(1.body); 1.url)}}
```
* encodeURL関数を使います。

# 5. 実行例（特定通知ラベルのメールを通知する）

### 5-1. 実装

元々、Gmailは重要そうなメールをGmailアプリとして通知してきますが、自分が決めたルールで必要なものだけMake経由で通知してみることにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206965/524da534-286d-5d5b-64db-08391fc7451b.png)
まず、Gmail（Web）のフィルター設定で、例えば特定のタイトルに反応するよう設定を作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206965/b01a0458-9594-e3e8-5539-71d770ceb550.png)
次に、アクションとして適当なラベルを付加するようにします。これで通知対象となるメールに印を付けることが出来ました。

次にやはりGASでWebhookをフックするようにコードを書いていきます。通知をしたいというマークが付いたメールスレッドを取得して、順番にMakeのWebhookに送る動作を実装します。この時、メール本文にURLが含まれている場合には、GetパラメーターのURLキーに指定することで、通知タップ＆即リンク先表示といった動作をさせています。

```javascript:メール通知送信.gas
var URL_MAKE = `https://hook.us1.make.com/xxxxx`;
var LABEL_SHOULD_NOTIFY = 'shouldNotification';
var IS_DEBUG = true;

function action() {
  logStart(arguments);

  // ラベルのIDを取得
  var objLabel = GmailApp.getUserLabelByName(LABEL_SHOULD_NOTIFY);

  // 通知すべきラベルがついた未読のメールスレッドを一括取得
  var threads = GmailApp.search(`label:${LABEL_SHOULD_NOTIFY} is:unread`);

  log(threads + ' mails ' + threads.length);
  // 各スレッドについて処理
  for (var n in threads) {
    var thread = threads[n];
    var messages = thread.getMessages();

    // 各メールについて通知を実施
    for (m in messages) {
      var message = messages[m];
      log(`message ${message}`);

      var date = message.getDate();
      log(`date ${date}`);

      var body = message.getPlainBody().slice(0, 200);
      log(`body ${body.split('\n')[0]}`);

      const urlRegex = /https?:\/\/[^\s/$.?#].[^\s]*/g;
      var url = body.match(urlRegex);

      var id = message.getId();
      log(`id ${id}`);

      var subject = message.getSubject();
      log(`subject ${subject}`);

      sendNotificationMake(('[' + subject + ']'),body ,url);
    }
    // スレッドからラベルを削除
    thread.removeLabel(objLabel);
  }

  logEnd(arguments);
}

// プッシュ通知を送信
function sendNotificationMake(title, message, url) {
  logStart(arguments);

  if (title == null) {
    log(`use tset title`);
    title = 'testTitle';
  }
  if (message == null) {
    log(`use tset message`);
    message = 'testMessage';
  }
  if (url == null) {
    log(`use tset url`);
    url = 'https://google.com/';
  }

  var payload =
  {
    "title": (title),
    "body": (message),
  }
  log(`payload: ${JSON.stringify(payload, null, 2)}`);

  var headers = {
    "Content-Type": "application/json"
  }
  var options =
  {
    "method": "post",
    "payload": payload,
    "headers": headers,
    "muteHttpExceptions": true
  };

  log(`payload: ${JSON.stringify(options, null, 2)}`);
  log(`make url: ${URL_MAKE}`);
  UrlFetchApp.fetch(`${URL_MAKE}?title=${encodeURI(title)}&body=${encodeURI(message)}&url=${url ? url : ""}`);

  logEnd(arguments);
}

///// sub routine

function logStart(caleeArgs) {
  log(`${caleeArgs.callee.name} start`);
}

function logEnd(caleeArgs) {
  log(`${caleeArgs.callee.name} end`);
}

function log(message) {
  if (IS_DEBUG) Logger.log(message);
}
```

### 5-2. 結果例

![IMG_1556.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206965/5d7c4871-8de8-e3d8-da24-1735e09e478b.jpeg)

サーバー起動時のタイトルをフィルターに指定して、Macサーバー起動時の通知が届きました。

![Screen.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206965/d6b90e38-8add-86cf-4cee-4ec6bc17a64c.jpeg)

通知をタップするとタイトル（本文があれば本文も表示されます）が表示されました。GASで公開したサイトは生で表示するとヘッダーが必ず表示されます。これがいやだと言う場合は独自ドメインなどにiframeとしてGASサイトをはめ込みます。
後はカスタマイズしていけばWebを起点に色々なアプリにカスタムスキーム経由でデータを渡して起動するなんて事も出来るはずです。

[EOF]