【神回】【0からGASを学ぶ】GASの制限を超える小技集 -その１-

# はじめに
本シリーズでは、GASの始め方や便利な使い方、ビジネス活用まで幅広く解説します。シリーズをひと通り読んでいただければ、あなたもきっとGASマスターになれるはずです。

# シリーズの対象者
* そもそもGASってなんだか**わからない**方
* GASを学びたいけど**何から始めればいいか**わからない方
* GASはわかり始めたけど、**もっと活用ができないか**と模索している方
* とにかく**Googleが好き！** という方

# 前回記事
https://qiita.com/gas-suke/items/a04b78d450eb2e3c7572

# 小技集
では早速始めていきましょう。【0からGASを学ぶ】シリーズの第9回は「GASの制限を超える小技集」です。**その1**では、これまで紹介してきたGASの中で「**制限があるので注意！**」とお伝えしたいくつかを**突破**します。

## 今回やること
1. GASの自動メール送信回数を突破！
1. トリガーを指定した任意の時間に実行！

今回は**スタンドアロン型**でGASを記述していきます。[こちら](https://qiita.com/gas-suke/items/5cf7bd4c6c3f15a25838#%E3%82%B9%E3%82%BF%E3%83%B3%E3%83%89%E3%82%A2%E3%83%AD%E3%83%B3%E5%9E%8B)を参考にGASエディタを起動してください。では、どんどんいきますよ、ついてきてください。

## GASの自動メール送信回数を突破！
### まずは事象を確認
<a href="https://qiita.com/gas-suke/items/e6ef3c771a68c9ed96b2#%E3%83%A1%E3%83%BC%E3%83%AB%E9%80%81%E4%BF%A1%E8%80%85%E6%95%B0" target="_blank">第3回：GASの制限回数を意識しながら各種サービスにアクセスしてみよう</a>において、GASの**GmailApp（またはMailApp）を通したメール送信**には制限回数があるとお伝えしました。これに偽りはなく、以下のプログラムでもわかる通り、メール送信するたびに残回数は減っていきます。
```javascript:Qiita009.gs
function Qiita009_SendEmail() {
  console.log(MailApp.getRemainingDailyQuota());
  // MailApp.getRemainingDailyQuota()は残送信回数を確認する関数
  for (let mIdx=0; mIdx<10; mIdx++) {
    GmailApp.sendEmail('*******@gmail.com', 'Gメール送信回数確認','');
    console.log(MailApp.getRemainingDailyQuota());
  }
}
```
```:実行結果
11:24:16	お知らせ	実行開始
11:24:17	情報	100
11:24:18	情報	99
11:24:19	情報	98
11:24:20	情報	97
11:24:21	情報	96
11:24:24	情報	95
11:24:25	情報	94
11:24:25	情報	93
11:24:26	情報	92
11:24:29	情報	91
11:24:30	情報	90
11:24:29	お知らせ	実行完了
```
そして、このメール送信による制限回数は、たとえ**有償のWorkspaceユーザでも撤廃されることはありません**。
* 無償ユーザ：100名/日
* 有償ユーザ：1,500名/日

https://developers.google.com/apps-script/guides/services/quotas?hl=ja

### よし、突破するぞ！！！！
では突破していきましょう。この制限事項のポイントは、**GmailAppを通したメール送信**という点です。つまり、GmailAppを用いて直接**sendMailを実行**することを**カウント**しているわけです。
**とんち**のように聞こえますが、ここがポイントです。そのためメール送信箇所を以下のように変えましょう。
* 変更前
  1. メールを送信する
* 変更後
  1. メールを作成して、下書きに保存する
  1. 下書きの送信**依頼**をする

```javascript:Qiita009.gs
function Qiita009_SendEmailEx() {
  console.log(MailApp.getRemainingDailyQuota());
  // MailApp.getRemainingDailyQuota()は残送信回数を確認する関数
  for (let mIdx=0; mIdx<10; mIdx++) {
    sendEmailEx('*******@gmail.com', 'Gメール送信回数確認','');
    console.log(MailApp.getRemainingDailyQuota());
  }
}

function sendEmailEx(_recipient, _subject, _body, _option) {
  // 引数の内容でメールを下書き保存する
  const mailDraft = GmailApp.createDraft(_recipient, _subject, _body, _option);
  // 下書き保存したメールIDから下書きを取得し、メール送信を依頼する
  GmailApp.getDraft(mailDraft.getId()).send();
}
```
```:実行結果
11:26:12	お知らせ	実行開始
11:26:13	情報	90
11:26:14	情報	90
11:26:16	情報	90
11:26:17	情報	90
11:26:18	情報	90
11:26:19	情報	90
11:26:21	情報	90
11:26:22	情報	90
11:26:24	情報	90
11:26:25	情報	90
11:26:26	情報	90
11:26:26	お知らせ	実行完了
```

いかがでしょうか。今回はsendEmailの拡張メソッドとして、sendEmailExを作成し、**下書き保存**、**下書きの送信依頼**を記述しました。これを使うことでGASの**実行制限を突破**できます！！！

### ただし！！！
**GASの実行制限に関しては突破**できますが、そもそもの**Gmailの制限**も併せてご確認ください。こればっかりはどうしようもないので、GASを実運用に適用する場合は、**必ずご一読を**。

https://support.google.com/a/answer/166852?hl=ja

## トリガーを指定した任意の時間に実行！
### まずは事象を確認
<a href="https://qiita.com/gas-suke/items/a04b78d450eb2e3c7572#step5%E6%AF%8E%E6%97%A5%E7%BF%8C%E6%97%A5%E3%81%AE%E4%BA%88%E5%AE%9A%E4%B8%80%E8%A6%A7%E3%81%8C%E5%B1%8A%E3%81%8F%E3%82%88%E3%81%86%E3%81%AB%E3%83%88%E3%83%AA%E3%82%AC%E3%83%BC%E7%99%BB%E9%8C%B2%E3%81%99%E3%82%8B" target="_blank">第8回：【0からGASを学ぶ】GASを用いてスプレッドシートで遊んでみよう -その４-</a>において、GASのトリガー実行では「日付ベースのタイマー」を設定できるか、**実行時刻に幅がある（0:00～1:00といった具合）** ことをお伝えしました。もちろんこれでも許容範囲な場合もあるかもしれませんが、可能な限り、想定通りの時刻に実行したいですよね。

### 特定日時の設定もある
GASのトリガー実行には、以下画像で示す通り、**「特定の日時」とすることで、作成者の意図した時間に実行することは可能**です。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3575702/c111c4e4-50c5-c308-926e-a2030c49cd24.png" width="600">
が、見てわかる通り、特定の日時を**一度だけ**です。
毎日8:30に実行されるようにしたいならば、その**数だけトリガーを作成する必要があり**ます。しかし、ここでもGASの制限事項がついてまわります。
* トリガーの作成個数：ユーザーあたり **20** 個/スクリプト

そのため、毎日実行されるようにしたくても、20個分作って、日々メンテをする必要があります。こんなのやってられないですよね。

### よし、突破するぞ！！！！
では、どうするか。これの答えは非常に簡単です。
トリガーにより実行されるメソッドの中で、**次のトリガーを作ればいい**わけです。
これまた**とんち**のように聞こえますが、ここがポイントです。ではプログラムで書いていきましょう。

```javascript:Qiita009.gs
function Qiita009_Trigger() {
  // トリガーに設定されている自分自身を削除する
  ScriptApp.getProjectTriggers().forEach(function(trigger){
    // トリガー名が一致するときのみ削除
    if(trigger.getHandlerFunction() == "Qiita009_Trigger"){
      ScriptApp.deleteTrigger(trigger);
    }
  });
  // 5分後に自分自身のトリガーをセットする
  let setTime = new Date();
  setTime.setMinutes(setTime.getMinutes()+5);
  ScriptApp.newTrigger('Qiita009_Trigger').timeBased().at(setTime).create();

  // 処理を実行する
  Qiita009_SendMailTrigger();
}

function Qiita009_SendMailTrigger() {
  sendEmailEx(
    '*******@gmail.com'
    , 'トリガーによるメール送信'
    , Utilities.formatDate(new Date(), 'JST', 'yyyy/MM/dd HH:mm:ss')
  );
}
```
上述のプログラムの`Qiita009_Trigger`を実行すると、自分自身のnextトリガーが作成されたうえで、`Qiita009_SendMailTrigger`メソッドが実行されます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3575702/852e5493-da41-5cbd-4eef-0d8383517291.png" width="600">
これにより、次は5分後自分自身（`Qiita009_Trigger`）が呼び出され、またその5分後に自分自身の呼び出しトリガーを作成するというのを繰り返します。
つまり、このやり方を応用すれば`setTime.setMinutes(setTime.getMinutes()+5);`の箇所を書き換えることで、`setTime.setDate(setTime.getDate()+1);`とすれば日時で、`setTime.setHours(setTime.getHours()+1);`とすれば毎時で処理を実行することができます。
ぜひ、ご自身の処理したいサイクルで設定を記述してみてください。

:::note info 
私がよく使うのは、0:00の日時処理で、
```javascript
  setTime.setDate(setTime.getDate()+1)
  setTime.setHours(0);
  setTime.setMinutes(0);
  setTime.setSeconds(0);
```
で設定しています。
:::

と、記事を書いてる間にも先ほどのトリガーが実行され続けています。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3575702/09b579b1-0ea1-0e1a-ffec-7f6d56f3ffc6.png" width="800">

### 
# おわりに
お疲れ様でした。
第9回は「GASの制限を超える小技集」その1ということで、これまでお伝えしたGASの基本的（すこし実践的）な使い方の中で発生していた**実行制限を突破する方法**をいくつか紹介しました。GASは非常に便利で強力なツールです。しかし、運用を開始しようとするとその**制限に阻まれる**ことがあります。そんなときは、この記事を読んで制限突破を試みてください。今後も、たまにこういった**小技も盛り込みながらGASの楽しさをお伝え**していきます。
記事を読んで、「良いな」や「今後に期待できる！」と感じて頂けたら**いいね**や**フォロー**、**コメント**いただけると幸いです。それではまた次回をお楽しみに！

## ブログでより詳しく解説しています！
以下画像をクリックしてブログにアクセス！！
<a href="https://gas-4u.com/gas08/" target="_blank"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3575702/bbf42881-a736-2c5f-908f-721b27c6b4e7.png" width="600"/></a>