第2話 リマインダーメールを送りたい 〜依頼内容の全体像〜

Google Apps Script

こんにちは、ばばーるです。

スポンサーリンク

前回のおさらい

前回はキリン部長からの納期管理のリマインダーメール

  • スプレッドシート上の日付を読み込める。
  • 日付の出力形式は曜日 月 日 年 HH:MM:SS 標準時]で出力される。

今回は依頼内容の全体像をざっと説明します。

全体像をキリン部長と打ち合わせ

たぬきさん
たぬきさん

キリン部長。
もうちょっと具体的に依頼内容を教えてください。

キリン部長
キリン部長

こんな感じでお願いしたんだけど…。
1. 納期が迫る、3,2,1カ月、2週間、前日にリマインドメールを送る。
2. 納期遅れの書類は毎月10日にリマインドメールを送る。
3. メールは営業日に送信する。

たぬきさん
たぬきさん

提出期限の2週間前の日が営業日じゃない場合はどうします?

キリン部長
キリン部長

前倒しでお願いします。

たぬきさん
たぬきさん

かしこまりました!

最初に答えを載せちゃいましょう

たぬきさん
たぬきさん

ギブ。
助けてGASエモン

GAS
GAS

オイッ!

ということで、たぬきさんがとりあえずギブしましたが、全体像を把握してから理解を進めていく方が理解しやすいと思うので、最初にスクリプト全体を載せてから解説していきます。

スクリプトのシートは2枚書いていきます。
・reminderEmail.gsはメインのスクリプトです。
・subFunctionsはサブのスクリプトで、処理で使う関数がまとめられています。

reminderEmailのスクリプトを書いていきます。

function reminderEmail() {
  //Get Spreadsheet data
  const id = '提出書類管理シートのスプレッドシートID';
  const ss = SpreadsheetApp.openById(id);
  const sheet = ss.getSheetByName('納期');
  const submitData = sheet.getSheetValues(1, 1, sheet.getLastRow(), 5);
  
  //Send remind emails on business days 
  const submitDate = submitData.map(a => a[4]); 
  const varianceDay = [90, 60, 30, 14, 1];
  let today = new Date(new Date().setHours(0, 0, 0, 0));
  
  submitDate.forEach(function(day, i){
    if (i > 0){
      let date4email = convertDate(submitData[i][4]);
      if (day - today < 0) {
        let futureDay = new Date(today.getFullYear() + '/' + Number(today.getMonth() + 1) + '/10');
        futureDay = decideSendday(futureDay);
        if (futureDay - today == 0){
          delayEmail(submitData[i][3], submitData[i][2], submitData[i][0], submitData[i][1], date4email);
        } 
      } else if (day - today > 0) {
        varianceDay.forEach(b => {let date = new Date(day);
        let remindDay = new Date(date.setDate(date.getDate() - b));
        remindDay = decideSendday(remindDay);
        if(remindDay - today == 0){
          remindEmail(submitData[i][3], submitData[i][2], submitData[i][0], submitData[i][1], date4email);
        } 
    });
    }
  }});
}

subFunctionsのスクリプトはこちらです。

/*
Subfunctions  
1. Judge if the day is business day or not
2. Change the day as 1 day before
3. Convert date from GAS dat to yyyy/mm/dd(week) 
4. Send emails in case of delivery delay
5. Send emails in case of 90, 60, 30, 14, 1 day before
*/

//--------------------------------------------//
// 1. Judge if the day is business day or not //
//--------------------------------------------//
function isBusinessday(date) {
  //Identify Japanese holiday 
  const jpCalendarID = 'en.japanese#holiday@group.v.calendar.google.com';
  const jpCalendar = CalendarApp.getCalendarById(jpCalendarID);
  const jpCalendarEvent = jpCalendar.getEventsForDay(date).length
  
  //Identify Saturday (= 6) & Sunday (= 0)
  const week = date.getDay();
  
  //Identify company holiday
  const month = date.getMonth() + 1;
  const day = date.getDate();
  const companyHoliday = [[5, 1], [12, 29], [12, 30], [12, 31], [1, 2], [1, 3], [1, 4]];
  
  //Check hoidays
  let i = 0
  companyHoliday.forEach(function(ch){
    if (month == ch[0] && day == ch[1] || week == 6 || week == 0 || jpCalendarEvent == 1){
      i++;
      }
  });
  
  if (i > 0){
    return false;
  } else {
    return true;
  }
}


//--------------------------------------------//
// 2. Change the day as 1 day before        //
//--------------------------------------------//
function decideSendday(date) {
  while(isBusinessday(date) !== true){
    date = new Date(date.setDate(date.getDate() - 1));
  }
  return date;
}


//------------------------------------------------//
// 3. Convert date from GAS dat to yy/mm/dd(week) //
//------------------------------------------------//
function convertDate(submitDay){
  const Year = submitDay.getFullYear();
  const Month = submitDay.getMonth() + 1;
  const date = submitDay.getDate();
  const day = submitDay.getDay();
  
  const week = ['日', '月', '火', '水', '木', '金', '土'];
  const dateInemail = Year + '/' + Month + '/' + date + '(' + week[day] + ')';
  
  return dateInemail;
}


//--------------------------------------------//
// 4. Send an email in case of delivery delay //
//--------------------------------------------//
function delayEmail(to, name, no, docname, day){
  let subject = '提出書類について';
  let body = '';
  let html = name + '様<br><br>';
  html += '<strong>' + no + ': ' + docname + '</strong>'
  html += 'の提出期限は' + '<u>' + day + '</u>' + 'でした。<br>'
  html += '<a href="提出書類管理シートのスプレッドシートURL">提出書類管理シート</a>をご確認の上、';
  html += '書類の提出をお願いいたします。<br><br>';
  html += 'ご不明な点がございましたらご連絡いただければ幸いです。<br>';
  html += 'Zoo株式会社<br>';
  html += '書類管理グループ グループ長<br>';
  html += 'キリン部長<br>';
  
  const id = 'logoが保存されているドライブのID';
  const image = DriveApp.getFilesByName('logo.jpeg').next();
  html += "<img src='cid:logo'>"

  GmailApp.sendEmail(to, subject, body,
                     {htmlBody : html,
                      inlineImages : {logo: image.getBlob()},
                      name: 'キリン部長'});
}


//----------------------------------------------------------//
// 5. Send an email in case of 90, 60, 30, 14, 1 day before //
//----------------------------------------------------------//
function remindEmail(to, name, no, docname, day){
  let subject = '提出書類について';
  let body = '';
  let html = name + '様<br><br>';
  html += '<strong>' + no + ': ' + docname + '</strong>'
  html += 'の提出期限が' + '<u>' + day + '</u>' + 'となっております。<br>'
  html += '<a href="提出書類管理シートのスプレッドシートURL">提出書類管理シート</a>も送付いたします。<br>';
  html += '納期が送れそうな場合は必ずご一報ください。<br><br>';
  html += 'ご不明な点がございましたらご連絡いただければ幸いです。<br>';
  html += 'Zoo株式会社<br>';
  html += '書類管理グループ グループ長<br>';
  html += 'キリン部長<br>';
  
  const id = 'logoが保存されているドライブのID';
  const image = DriveApp.getFilesByName('logo.jpeg').next();
  html += "<img src='cid:logo'>"

  GmailApp.sendEmail(to, subject, body,
                     {htmlBody : html,
                      inlineImages : {logo: image.getBlob()},
                      name: 'キリン部長'});
}

これだけ見ると難解に見えますが、一つ一つ説明してくので安心してください。

reminderEmailの概説

reminderEmail の上から読んでいきましょう。スプレッドシートの内容を参照しながら読み解くと分かり易いと思います。

function reminderEmail() {
  //Get Spreadsheet data
  (1行目)const id = '提出書類管理シートのスプレッドシートID'; 
  (2行目)const ss = SpreadsheetApp.openById(id);
  (3行目)const sheet = ss.getSheetByName('納期');
  (4行目)const submitData = sheet.getSheetValues(1, 1, sheet.getLastRow(), 5);

1行目:スプレッドシートIDを変数idに代入
2行目:SpreadsheetApp.OpenByIdでスプレッドシートにアクセス
3行目:getSheetByNameでスプレッドシートの’納期’というシートにアクセス
4行目:getSheetValuesでセルA1からE5までのセルの値を取得

ここら辺の内容がよくわからない場合は以下の記事くらいから過去記事を辿ってみてください。

   //Send remind emails on business days 
  (5行目)const submitDate = submitData.map(a => a[4]); 
  (6行目)const varianceDay = [90, 60, 30, 14, 1];
  (7行目)let today = new Date(new Date().setHours(0, 0, 0, 0));

5行目:4行目で取得したA1からE5までのセルの値の内、E列だけをmap関数で取得
6行目:3、2、1カ月、2週間、1日前の日付を取得するための配列を設定
7行目:今日の日付をnew Date()を取得して、時間を00:00:00に設定

たぬきさん
たぬきさん

ちょっと待った。
もうこの時点でお腹いっぱいだ。

GAS
GAS

すごく分かる。
でもとりあえず全体の構成を理解するために一気に読んでいこう。

  (8行目)submitDate.forEach(function(day, i){
  (9行目)if (i > 0){
  (10行目)let date4email = convertDate(submitData[i][4]);
  (11行目)if (day - today < 0) {
  (12行目)let futureDay = new Date(today.getFullYear() + '/' + Number(today.getMonth() + 1) + '/10');
  (13行目)futureDay = decideSendday(futureDay);
  (14行目)if (futureDay - today == 0){
  (15行目) delayEmail(submitData[i][3], submitData[i][2], submitData[i][0], submitData[i][1], date4email);
  } 
  (16行目)} else if (day - today > 0) {
  (17行目)varianceDay.forEach(b => {let date = new Date(day);
  (18行目)let remindDay = new Date(date.setDate(date.getDate() - b));
  (19行目)remindDay = decideSendday(remindDay);
  (20行目)if(remindDay - today == 0){
  (21行目)remindEmail(submitData[i][3], submitData[i][2], submitData[i][0], submitData[i][1], date4email);
        } 
    });
    }
  (22行目)}});

8~22行目:forEach文で提出期限のデータを1行づつ読み込んで
9~22行目:if (i > 0)で1行目(i = 0)の”提出期限”以降の2行目から読み込む
10行目:convertDateというsubfunctionの関数を呼び出す
11~15行目:納期遅れの提出書類のリマインドメールを送信
16~21行目:3,2,1カ月、2週間、前日に提出書類のリマインドメールを送信

たぬきさん
たぬきさん

一番重要な11~21行目の説明雑だな。

GAS
GAS

ここらはsubfunctionが絡んでいるから、次回以降詳しく説明していくよ。

subFunctionsの概説

/*
Subfunctions  
1. Judge if the day is business day or not
2. Change the day as 1 day before
3. Convert date from GAS dat to yyyy/mm/dd(week) 
4. Send emails in case of delivery delay
5. Send emails in case of 90, 60, 30, 14, 1 day before
*/

subFunctionsのには5つの関数が収納されています。
1.はisBusinessdayという関数で、土日祝に加えて、会社の休日除いた営業日かどうかの判断を行えます。
2.は営業日でない場合に、日付を1日づつずらす関数です。
3.はリマインドメールを送る際に、日付を2020/12/28(月)の様なyyyy/mm/dd(week)という形式に変換する関数です。
4.と5.はGmailを決められた文章形式にして送信するための関数です。詳細は以下のリンクをご参照ください。

たぬきさん
たぬきさん

もう限界です。
詳しく教えてください。

GAS
GAS

りょ。

まとめ

今回はキリン部長からの依頼内容の全体像をざっと説明しました。キリン部長からの依頼は

  • 納期が迫る、3,2,1カ月、2週間、前日にリマインドメールを送る。
  • 納期遅れの書類は毎月10日にリマインドメールを送る。
  • メールは営業日に送信する。

それに対して、スクリプトは

  • スプレッドシートから提出期限を取得
  • 3,2,1カ月、2週間、前日の日付を計算
  • 営業日を認識
  • メールを送信

をしているらしいことがわかります。

今回だけで理解するのは難しいので次回から詳細を説明していきます。

タイトルとURLをコピーしました