【0からGASを学ぶ】GASの制限回数を意識しながら各種サービスにアクセスしてみよう

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

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

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

# GASの制限回数を意識しながらサービスを操作する
では早速始めていきましょう。【0からGASを学ぶ】シリーズの第3回は「GASの制限回数を意識しながら各種サービスにアクセスしてみよう」です。

## GASからアクセス
<a href="https://qiita.com/gas-suke/items/ee7dd986259837efb33e" target="_blank">前回</a>はGASからGoogleの代表的なサービスである`Googleスプレッドシート`、`Googleドキュメント`、`Googleスライド`、`Googleフォーム`それぞれにアクセスし、簡単な操作までやりました。今回はそれらに加えて、`Googleカレンダー`、`Googleドライブ`、`Gmail`にもアクセスしてみましょう。さらに<a href="https://qiita.com/gas-suke/items/5cf7bd4c6c3f15a25838#:~:text=%E3%81%9F%E3%81%A0%E3%81%97%E3%80%81%E7%84%A1%E5%84%9F%E3%82%86%E3%81%88%E3%81%AE" target="_blank">前々回</a>にちらっと話した**無償ゆえの制約事項**にも触れていきましょう。

### 事前準備
今回は、`Googleドライブ`上のファイル移動を行っていきますので、試しに以下のように移動前フォルダ「test001」と移動後フォルダ「test002」を作ってください。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3575702/3bfc6307-1e54-0cbe-0edf-35960b04fffd.png" width="600"/>

:::note warn
「Qiita003」は本記事で使用するGASファイルを同階層にいれているだけなので、この構成である必要はありません。
:::

### フォルダIDを取得
`Googleドライブ`上のフォルダにも、<a href="https://qiita.com/gas-suke/items/ee7dd986259837efb33e#%E5%90%84%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AEid%E3%82%92%E5%8F%96%E5%BE%97" target="_blank">前回</a>と同様に**一意なID（文字、数字、ハイフン、アンダースコアから成る一意の値）が割り振られています**。この一意のIDはフォルダにアクセスした際のURLから確認できますので、それを**取得（コピー）** しておいてください。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3575702/9fa08177-b254-76d2-a634-e1388e2ac261.png" width="600"/>
※この例でいうと、私が事前準備で作成した「test001」フォルダのIDは四角で囲った`1CpGZj_aGoWFBb-lRbw0rjmwjN59PxTYU`となります。

### GASエディタを開く
繰り返しになりますが、今回はスタンドアロン型で開きますので、<a href="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" target="_blank">こちら</a>を参考にGASエディタを起動してください。では、どんどんいきますよ、ついてきてください。

### Googleカレンダー編
```javascript:Calendar.gs
function Qiita003_Calendar() {
  // カレンダークラスを用いて、IDを指定してGoogleカレンダーにアクセスする
  let wCalendar = CalendarApp.getCalendarById('***************@gmail.com');

  // 試しに登録するイベントの日時を作成する
  let wStartDate = new Date(2023, 9, 23, 8, 30, 0); 
  // この場合は2023年10月23日の8時30分となる
  // Dateクラスは月だけは0始まりなので注意が必要となるため、文字列での指定でも可能
  // let wStartDate = new Date('2023/10/23 8:30:00');

  let wEndDate = new Date(2023, 9, 23, 18, 0, 0)

  // 上記の開始・終了日時を用いて、カレンダーに登録する
  wCalendar.createEvent('Qiita003_カレンダー登録テスト01', wStartDate, wEndDate);
  // 終日予定の場合は、開始日時（正確には開始日）のみで登録ができる
  wCalendar.createAllDayEvent('Qiita003_カレンダー登録テスト02',wStartDate);
}
```
上記のプログラムを実行すると、指定したカレンダーにプログラム内で登録した予定が追加されています。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3575702/45aae86d-d6b7-16fb-7bf6-02a8f1caee74.png" width="600"/>

:::note info
GoogleカレンダーのカレンダーIDの調べ方は以下を参考にしてください。ただし、**自身のGoogleカレンダーにアクセスする**だけならば、**IDはアカウント名（Gmailアドレス）と同一**なので、調べるまでもありません。

<table>
  <tr>
    <th>№</td>
    <th>手順</td>
    <th>イメージ</td>
  </tr>
  <tr>
    <td>1</td>
    <td>Googleカレンダーへアクセスします。</td>
    <td></td>
  </tr>
  <tr>
    <td>2</td>
    <td>左カラムの「マイカレンダー」から「カレンダーID」を確認したいカレンダーにマウスオーバーすると、「︙」が表示されるためクリックします。</td>
    <td><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3575702/300c9335-540d-8055-4ab8-2867011b6847.png" width="200"></td>
  </tr>
  <tr>
    <td>3</td>
    <td>「設定と共有」をクリックすると選択したカレンダーの設定ページに遷移します。</td>
    <td><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3575702/c1d31197-dcbe-8faf-6815-bb950e9283a2.png" width="200"></td>
  </tr>
  <tr>
    <td>4</td>
    <td>ページ下部にて「カレンダーID」を確認できます。</td>
    <td><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3575702/b36b1d4f-a4c0-ef2c-b25d-7238b9b5b6fb.png" width="400"></td>
  </tr>
</table>
:::

### Googleドライブ編
私の場合は、事前準備で作成した2つのフォルダに対するIDは
* test001：`1CpGZj_aGoWFBb-lRbw0rjmwjN59PxTYU`
* test002：`1ITFz8yhg4tBpFNRo-KidWRNtotb6oKRO`

となっております。
まずは「test001」に新規でスプレッドシートを作成してみましょう。といっても、**フォルダ指定で新規作成するのではなく**、**新規作成後にフォルダを指定して移動させる**のが、GASの定石となります。

```javascript:Drive.gs
function Qiita003_DriveTest001() {
  // ドライブクラスを用いて、IDを指定してドライブにアクセスする（test001）
  let wDrive = DriveApp.getFolderById('1CpGZj_aGoWFBb-lRbw0rjmwjN59PxTYU');

  // スプレッドシートを新規に作成する（マイドライブのルートフォルダに作成）
  let wSpread = SpreadsheetApp.create('Qiita003新規作成')
  // スプレッドシートのIDからドライブクラスで扱えるようファイルオブジェクトを取得する
  let wSpreadFile = DriveApp.getFileById(wSpread.getId());

  // 作成したスプレッドシートをtest001フォルダに移動する
  wSpreadFile.moveTo(wDrive);
}
```
上記のプログラムを実行すると、「test001」フォルダ内に`Qiita003新規作成`というスプレッドシートが作成されます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3575702/8cf64f74-f627-fcee-9326-703466c1e44a.png" width="400"/>

次にこのファイルを「test002」フォルダに移動させます。すでに上記プログラムでフォルダ移動までは実施済みなので、フォルダ内のファイルを取得して、移動するというのをやってみましょう。

```javascript:Drive.gs
function Qiita003_DriveTest002() {
  // ドライブクラスを用いて、IDを指定してドライブにアクセスする（test001, 002）
  let wDrive001 = DriveApp.getFolderById('1CpGZj_aGoWFBb-lRbw0rjmwjN59PxTYU');
  let wDrive002 = DriveApp.getFolderById('1ITFz8yhg4tBpFNRo-KidWRNtotb6oKRO');

  // test002フォルダ内の全ファイルを取得する
  let wFiles = wDrive001.getFiles();
  while (wFiles.hasNext()) {
    // ファイルリスト内のファイルを1件ずつ取得する
    let wFile = wFiles.next();
    // ファイル名が'Qiita003新規作成'の場合はtest002フォルダに移動する
    if (wFile.getName()=='Qiita003新規作成') {
      DriveApp.getFileById(wFile.getId()).moveTo(wDrive002)
    }
  }
}
```
上記のプログラムを実行すると、「test001」フォルダ内にあった`Qiita003新規作成`というスプレッドシートが「test002」フォルダに移動します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3575702/686fdaa6-dab6-910e-3f31-6b45e0cabd97.png" width="400"/>

:::note info
ドライブの操作は今回ご紹介した`DriveApp`だけでなく、拡張ドライブサービス（Drive API）を用いることで、より高度なことが可能になります。それはまた次回以降に！
:::


### Gmail編
```javascript:Gmail.gs
function Qiita003_Gmail() {
  let address = '***********@gmail.com'
      , subject = 'Qiita003'
      , body = `ここには本文を記述します`
      , options = {'bcc':'***********@gmail.com, ***********@gmail.com'};
  // GmailAppクラスを用いて、メールを送信する
  GmailApp.sendEmail(address, subject, body, options);

  // あえてMailAppクラスを用いて、メールを送信する
  MailApp.sendEmail(address, subject, body);
}
```
上記のプログラムを実行すると、addressに指定したメールアドレス宛に**GASを実行しているアカウントからメールが送信**されます。
あえて、GmailAppとMailAppをどちらも記載して、2通のメールを送信しています。メールの送信に関して**2つに違いはありません**。ただし、許容される**権限範囲**が異なります。この例を実行すると、
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3575702/95894a44-6239-92bd-f6e1-431bc26a1f9d.png" width="400"/>
といった画面が表示されます。このうち**上側がGmailApp**、**下側がMailApp**に関するアクセス権限となります。
つまり、**GmailAppではGmailに関するあらゆることがGASから可能**であり、**MailAppでは単にメールを送信することだけ**が可能です。

:::note info
メール送信しかしないのであれば、MailAppを推奨するようなページもありますが、**本シリーズではGmailAppを推奨**します。明確な理由がありますが、それは次回以降のお楽しみにしましょう！
:::

### 各クラスのリファレンス
今回アクセスした`Googleカレンダー`、`Googleドライブ`、`Gmail`について、簡単な操作方法を示しました。次回以降では各クラスの詳細な活用方法をどんどん記載していきますが、少しでも**予習しておきたい方**は以下から各クラスのリファレンスを学んでみてください。
#### CalendarApp
https://developers.google.com/apps-script/reference/calendar/calendar-app?hl=ja
#### DriveApp
https://developers.google.com/apps-script/reference/drive?hl=ja
#### GmailApp
https://developers.google.com/apps-script/reference/gmail?hl=ja
#### MailApp（念のため）
https://developers.google.com/apps-script/reference/mail/mail-app?hl=ja

:::note info
前回同様安心してください。こーゆーリファレンスが**苦手な人**でも本シリーズを読み続けていただければ、必ず**GASマスターに近づけます**。
:::

## 制限回数について
さて、ここまで[前回](https://qiita.com/gas-suke/items/ee7dd986259837efb33e)も通じて、`Googleスプレッドシート`、`Googleドキュメント`、`Googleスライド`、`Googleフォーム`、`Googleカレンダー`、`Googleドライブ`、`Gmail`と様々なサービスにアクセスしてきました。GASは非常に簡単に使えて、**無償で様々なことができる可能性**を感じていただけているかと思います。
そんな希望に満ち溢れているところを止めるようで申し訳ございませんが、ここでこれまで何度かお伝えしていた**無償ゆえの制約事項**について触れていきます。

:::note warn
**無償ゆえの制限事項**と述べていますが、有料の**Google Workspaceを契約**したとしても**制限事項が撤廃されるわけではありません**。一部が緩和されるのみで、無償で使えるGASには**常に制限事項がつきまとう**ことになります。
:::

### 代表的な制限事項
| 制限事項 | 無償アカウント | Google Workspace |
|:-----------|:-----------|:-----------|
| スクリプトの実行時間 | 6 分まで / 実行 | 6 分まで / 実行 |
| トリガーの合計実行時間 | 90 分まで / 日 | 6 時間まで / 日 |
| プロパティの読み取り/書き込み | 50,000 回 / 日 | 500,000 回 / 日 |
| メール送信者数 | 100 名 / 日 | 1,500 名 / 日 |
| URL Fetchのコール回数 | 20,000 回 / 日 | 100,000 回 / 日 |

上記以外にも多々ありますが、割と意識しなければならない**代表例として5点**を挙げました。それ以外は以下を参照してください。

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

### 実行制限とは例えば？
#### スクリプトの実行時間
```javascript:実行時間の確認.gs
function Qiita003_ScriptRuntime() {
  while(true) {
    console.log(Utilities.formatDate(new Date(), 'JST', 'yyyy-MM-dd HH:mm:ss'));
    Utilities.sleep(10000); // 10秒スリープさせる
  }
}
```

```javascript:実行結果
13:53:59	お知らせ	実行開始
13:53:59	情報	2023-10-23 13:53:59
13:54:09	情報	2023-10-23 13:54:09
…
13:59:39	情報	2023-10-23 13:59:39
13:59:49	情報	2023-10-23 13:59:49
13:59:59	エラー	
Exceeded maximum execution time
```
このようにスクリプトが開始されてから6分を超えると`Exceeded maximum execution time`が発生し、スクリプトは強制的に終了します。そのため、**長時間かからないような処理の工夫**がGASには必要となります。

#### プロパティの読み取り/書き込み
```javascript:プロパティの読み書き.gs
function Qiita003_PropertiesReadWrite01(){
  // スプレッドシートを取得する
  let wSpread = SpreadsheetApp.openById('1xjdjN2uJefWlyN87SScPsnahWJ_NEVEuHiDxxBElPdU');
  let wSheet = wSpread.getSheets()[0];

  // 各カラムを取得しながら、値をセットする
  let wColA1 = wSheet.getRange(1, 1);
  wColA1.setValue('Qiita001');

  let wColB1 = wSheet.getRange(1, 2);
  wColB1.setValue('Qiita002');
  
  let wColC1 = wSheet.getRange(1, 3);
  wColC1.setValue('Qiita003');
}


function Qiita003_PropertiesReadWrite02(){
  // スプレッドシートを取得する
  let wSpread = SpreadsheetApp.openById('1xjdjN2uJefWlyN87SScPsnahWJ_NEVEuHiDxxBElPdU');
  let wSheet = wSpread.getSheets()[0];

  // 設定変更を行うセルの範囲を取得する
  let wRange = wSheet.getRange(1, 1, 1, 3); // A1～C1の1行3列を取得している
   
  // 値のリストを配列に格納する
  let wArray = ['Qiita001', 'Qiita002', 'Qiita003'];  

  // セルの範囲に値を一括で設定する
  wRange.setValues([wArray]);
}
```
上記プログラムは最終的な結果は同じです。
しかしながら、`Qiita003_PropertiesReadWrite01`の場合は、A1セルへ**getRangeで読み取り**、**setValueで書き込み**、これをB1およびC1にも同様に行うため、**計6回**の読み書きが発生します。
対して、`Qiita003_PropertiesReadWrite02`の場合は、セルの範囲を指定して、**一括で読み込みおよび書き込み**を行っており、**計2回**となります。この例ではこの程度の差ではありますが、こういった工夫によって**制限回数の範囲内でやりくりをする**ことがGASには必要となります。

#### メール送信者数
```javascript:メール送信者数.gs
function Qiita003_EmailRecipients() {
  console.log(MailApp.getRemainingDailyQuota());
  // MailApp.getRemainingDailyQuota()は残送信回数を確認する関数
  GmailApp.sendEmail('*******@gmail.com', 'Gメール送信回数確認','');
  console.log(MailApp.getRemainingDailyQuota());
}
```
```javascript:実行結果
15:07:10	お知らせ	実行開始
15:07:11	情報	96
15:07:12	情報	95
15:07:12	お知らせ	実行完了
```

このように、メールが送信されるごとに残回数が減っていることがわかります。なお、sendMailの回数ではなく、あくまでも**sendMailによって送信された宛先の数に依存する**ため、宛先が2名であれば**1通のメールで2回分消費**されます。

:::note info
これは工夫のしようがないように見えますが、実は**回避策**があります。
:::

# おわりに
お疲れ様でした。
第3回は「GASの制限回数を意識しながら各種サービスにアクセスしてみよう」ということで、新たに`Googleカレンダー`、`Googleドライブ`、`Gmail`へのアクセスを体験しながら、**GASの制限回数**をお伝えいたしました。まだまだ序盤の域をでることはできていないため、業務での活用をイメージできないかもしれません。次回以降は、実際に実業務での活用に主眼を置きながら、データの**取得**や**編集**を行っていきましょう。
記事を読んで、「良いな」や「今後に期待できる！」と感じて頂けたら**いいね**や**フォロー**、**コメント**いただけると幸いです。それではまた次回をお楽しみに！

## ブログでより詳しく解説しています！
以下画像をクリックしてブログにアクセス！！
<a href="https://gas-4u.com/gas03/" target="_blank"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3575702/14c6323d-0de4-7d90-e9f6-2118affbad01.png" width="600"/></a>