【GAS】本日のメンバーの全ての予定をカレンダーから自動取得しGmailで通知する

## この記事はなにか

チームメンバーの当日のスケジュールくらいメールでまとめて自動で配信されないかな…
そんなこと思ったことありませんか？

**その夢、叶えられます。`Goole Apps Script`ならね。**

この記事は以下のような点を意識して作成したGASのプログラムです。

- スクリプトなどは基本コピペでOK！
- メール送信先、カレンダー取得先の追加や削除はスプレッドシート上でカンタン管理！
- 定刻に送付、土日祝日は送らない！（←他の方の記事を参考にしました）

■メール本文イメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224314/bb7ddb3a-ab45-e63a-7479-50403a0d7106.png)

## 作成・準備

①準備するもの

- Googleアカウント
- Gmail
- Googleカレンダー（「他のカレンダー」に取得したいメンバーを登録しておく必要あり）
- スプレッドシート

②導入までの流れ

1. [スプレッドシート準備](#1スプレッドシート準備)
2. [スクリプト記述](#2スクリプト記述)
3. [カレンダー登録](#3カレンダー登録)
4. [稼働確認](#4稼働確認)
5. [トリガー作成](#5トリガー作成)
6. [運用](#6運用)

### 1.スプレッドシート準備

コードにも出てきていますが、今回は2つのシートを準備します。

1. メール送信先
- カレンダー取得先


※コードで上記の名称を使用しているので、シート名はその通りにしてください。

■「メール送信先」シート
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224314/7ea5726d-8685-ee95-4ba4-c49fa1255502.png)

■「カレンダー取得先」シート
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224314/f989815d-1fb9-6ca5-8ab5-a98ee5167262.png)

それぞれのシートの`A列に名前、B列にアドレスもしくはカレンダーID（基本は同じ）`を入力します。
この時、最終行までは自動で取得しますが、その間に空欄や打ち間違いがあるとエラーとなります。

### 2.スクリプト記述

`スプレッドシート`→`ツール`→`スクリプトエディタ`の順にクリックし、
スクリプトエディタに下記ソースを記述します。

```js
//メインで実行する関数
function notifyGmail() {

  let holiday = isHoliday();

  if (isHoliday() == false) {
    const recipients = getRecipients();
    let mailBody = '■■このメールはシステムからの自動配信です■■<br><br>【本日のメンバーのスケジュール】<br>';
    mailBody += getCalendar();
    mailBody += '<br>From メンバーのスケジュール教えちゃうbot (・∀・)'

    GmailApp.sendEmail(recipients, '【送付】本日のメンバーのスケジュール', '', { htmlBody: '<p>' + mailBody + '</p>' });

  }
}

function getCalendar() {

  //カレンダーのID（メールアドレス）を取得する
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const calendarMembersSheet = ss.getSheetByName("カレンダー取得先");
  const memberIds = calendarMembersSheet.getRange(2, 2, calendarMembersSheet.getLastRow() - 1).getValues();
  const memberNames = calendarMembersSheet.getRange(2, 1, calendarMembersSheet.getLastRow() - 1).getValues();

  //カレンダーのデータを取得する
  let i, j;
  let memberId;
  const startDate = new Date();
  let myCalendar;
  let title, startTime, endTime; //メール本文に使う部品
  let myEvents = [];
  let eachSchedules = '';

  for (let i = 0; i < memberIds.length; i++) {
    memberId = memberIds[i];
    myCalendar = CalendarApp.getCalendarById(memberId);
    myEvents = myCalendar.getEventsForDay(startDate)
    eachSchedules += ('<br>' + '■' + memberNames[i].toString() + 'さんの予定' + '<a href= "https://calendar.google.com/calendar/embed?src=' + memberId.toString().replace('@', '%40') + '&ctz=Asia%2FTokyo">&#x1f4c5;</a><br>');
    if (myEvents.length == 0) {
      eachSchedules += ('・記載なし<br>');
    } else {
      for (let j = 0; j < myEvents.length; j++) {
        title = myEvents[j].getTitle();
        startTime = Utilities.formatDate(myEvents[j].getStartTime(), 'JST', 'HH:mm');
        endTime = Utilities.formatDate(myEvents[j].getEndTime(), 'JST', 'HH:mm');
        if (startTime == '00:00' || endTime == '00:00') {
          eachSchedules += ('・　終　日　: ' + title + '<br>');
        } else {
          eachSchedules += ('・' + startTime + "〜" + endTime + " : " + title + '<br>');
        }
      }
    }
  }

  return eachSchedules;

}

//送付先メンバーリストを取得
function getRecipients() {

  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const recipientsSheet = ss.getSheetByName("メール送信先");
  recipientsSheet.activate();
  const recipients = recipientsSheet.getRange(2, 2, recipientsSheet.getLastRow() - 1).getValues();
  return recipients;

}

//土日祝日を判定するスクリプト
//参考URL...https://qiita.com/jz4o/items/d4e978f9085129155ca6
function isHoliday() {

  const today = new Date();

  //土日か判定
  const weekInt = today.getDay();
  if (weekInt <= 0 || 6 <= weekInt) {
    return true;
  }

  //祝日か判定
  const calendarId = "ja.japanese#holiday@group.v.calendar.google.com";
  const calendar = CalendarApp.getCalendarById(calendarId);
  const todayEvents = calendar.getEventsForDay(today);
  if (todayEvents.length > 0) {
    return true;
  }

  return false;

}
```

### 3.カレンダー登録

**ここは忘れがちですが非常に重要なポイントです!**
カレンダーIDをスプレッドシートに記述するだけではエラーになってしまうと思うので、
`取得先のカレンダーは「他のカレンダー」に追加`しておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224314/3c12eef5-c4ad-0951-4e9c-dfcd954ef71b.png)

### 4.稼働確認

ここまでくれば稼働確認です。
関数で`notifyGmail`を選択し、実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224314/6717a53e-b5e0-f288-bd8c-e321623c9b11.png)

特にエラーが起きず、以下のようなメールが受信できればOKです！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224314/d191c4b6-cfed-3472-c8d8-d8f206427078.png)

### 5.トリガー作成

今回、トリガーは毎朝出勤前に来てればいいかなと思ったので以下のように設定しました。
ちなみに、[時間ぴったりに実行できる方法](https://qiita.com/sumi-engraphia/items/465dd027e17f44da4d6a)もあるみたいです。
土日祝日のメール送信回避はスクリプト上で設定してあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224314/907b4a2c-b35b-96f8-de5e-e2c3b8814978.png)

### 6.運用

以上で設定は完了です。
まずは1週間くらい自ら運用してみて、大丈夫そうだったら仲間にも送ってあげましょう！

## 所感
最近スケジュールを確認することが多く、手間を省きたくて作りました。
尚、[以前作った記事](https://qiita.com/takachan_coding/items/7234781ac56a4734e62b)と構成はほぼ同じです…

できなかったり、不明点あればコメントかメッセージをお願いします！

## 参考
[Apps Script | Google Developers](https://developers.google.com/apps-script)
[【GAS】休日・祝日を判定する関数｜Qiita](https://qiita.com/jz4o/items/d4e978f9085129155ca6)