土・日曜日、特定日に受信した特定のメールをGmailで自動返信する(Google App Script)

注文メールの休日対応

土・日曜日、祝日にECサイトから注文があった際、休日である旨のメールを自動で返信するスクリプトです。Google Workspaceを使っているので、Google App Script(GAS)で実現できました。

行うこと

  1. 特定の送信元、件名のメールのうち、未読メールを抽出する。
  2. 土・日曜日、または特定日(祝日)だったら、メールを返信する。
  3. メールを既読にする。
  4. 上記の動作を1時間に1回実行する。

上みたいな文章を生成AIに投げると、Scriptを書いてくれます。ホント、SF映画で見たような音声で命令してくれると色々やってくれるようなコンシェルジュが1人に1つ付く時代も遠くないですね。

Googeleスプレッドシート

Gmailにログイン > メニューからドライブ、新規 > スプレッドシート > 拡張機能 > App Script

コードの部分にスクリプトを書いていきます。

スクリプトの作成

メールを抽出して、メールを送信する

GmailApp.searchで、Gmailの受信メールを検索して、threadsに入れます。検索条件はqueryで設定。今日受信したメールかつ、unread(未読メール)、送信元がxxx.jpかつ件名に注文ですを含むメールを取り出します。

検索条件に未読メールをつけているのは、メール送信後、既読扱いにして、二重送信を避けるためです。送信終了後、「送信済み」のラベルをつける動作の方が良かったかもしれない。

テストするため、replyToは自分のメールアドレスにしておきます。

想定通り動かなかった場合のチェックのため、queryconsole.logで出力します。動かなかったら、出力された内容でGmailを検索して、該当メールが検索結果に出力されているか確認します。もし、今日、該当のメールを受信していなかったら、searchTodayconst searchToday =’2023-11-4′;のように固定値にして試します。

Logger.logに残すため、時分秒まで含んだtodayLogを取っておきます。

function autoReplyToEmails() {
  const searchToday = Utilities.formatDate(new Date(), 'JST', 'yyyy-MM-dd');
  const todayLog = Utilities.formatDate(new Date(), 'JST', 'yyyy-MM-dd hh:mm:ss');
  const query = 'after:' + searchToday + ' is:unread from:xxx.jp subject:注文です';
  const threads = GmailApp.search(query);

  console.log(query);

  //自動返信対象のメールを読込む
  threads.forEach(thread => {
    let messages = thread.getMessages();
    messages.forEach(message => {
      let sentDate = message.getDate();
      let replyTo = 'テスト用の自分のメールアドレス'; // 返信先の取得
      let replySubject = 'Re: ' + message.getSubject(); // 件名の設定
      let replyBody = '今日はお休みです。'; //本文の設定

      GmailApp.sendEmail(replyTo, replySubject, replyBody, {  
        name: '自動返信時の送信元名';
        from: '自動返信時の送信元アドレス',
        replyTo: '自動返信時の送信元アドレス',
        bcc: '自動返信時のBCC',
      }); //メール送信
      message.markRead(); //メールを既読に変更
      Logger.log(todayLog + ' 送信完了 ' + replyTo);
    });
  });
}

土・日曜日の判定

date.getDay()で今日の日付の曜日を取得します。0が日曜日、1が月曜日と続き、6が土曜日です。今日が日曜日か土曜日だった場合、trueを返す関数にしておきます。

//土曜日、日曜日の判定
function isWeekend(date) {
  const dayOfWeek = date.getDay();
  if(dayOfWeek === 0 || dayOfWeek === 6){ // 0: 日曜日, 6: 土曜日
    return true ;
  }
  return false;
}

特定日(祝日)の判定

specificDatesに祝日を変数として入れておきます。specificDatesを展開しながら、今日の日付と比較。一致した場合、trueを返す関数にしておきます。


//特定の日付(祝日、連休)の判定
function isSpecificDate(date) {
  var specificDates = [
    ["2023/1/1"],
    ["2023/1/9"],
    ["2023/2/11"],
    ["2023/2/23"],
    ["2023/3/21"],
    ["2023/4/29"],
    ["2023/5/3"],
    ["2023/5/4"],
    ["2023/5/5"],
    ["2023/7/17"],
    ["2023/8/11"],
    ["2023/9/18"],
    ["2023/9/23"],
    ["2023/11/3"],
    ["2023/11/23"],
    // 追加の日付をここに続けて記入
  ];//祝日、連休日の設定

  let year = date.getFullYear();
  let month = date.getMonth();
  let day = date.getDate();

  for (let i = 0; i < specificDates.length; i++) {
    let specificYear = new Date(specificDates[i]).getFullYear();
    let specificMonth = new Date(specificDates[i]).getMonth();
    let specificDay = new Date(specificDates[i]).getDate();

    if (year === specificYear && month === specificMonth && day === specificDay) {
      return true;
    }
  }
  return false;
}

完成script

scriptの結合と調整

土・日曜日の判定、特定日の判定のいずれかが一致した時にだけメールを送信するように変更します。また、設定する変数関係をスクリプトの冒頭にまとめておきます。

テスト用として、自分のメールアドレスにしていたreplyTomessage.getFrom()で返信するメールの送信元を取得して設定するように変更します。

//設定
var searchMailfrom = '{自動返信対象の送信元アドレス}'; //自動返信対象の送信元
var searchSubject = '{自動返信対象の件名}'; //自動返信対象の件名
var mailFrom = '{自動返信時の送信元アドレス}'; //自動返信の送信元
var mailName = '{自動返信時の送信元名}'; //自動返信の送信元名
var mailBcc ='{チェック用BCCの宛先}'; //自動返信のBCC
var mailBody = 'お世話になります。\n'
              + '弊社土日祝日お休みのため、お問い合わせの回答は休み明け順次のご対応とさせていただきます。\n'
              + 'お急ぎのところご迷惑おかけしますが、何卒ご了承のほど宜しくお願い申し上げます。\n';//自動返信の本文。改行には\nをつける。
var specificDates = [
    ["2023/1/1"],
    ["2023/1/9"],
    ["2023/2/11"],
    ["2023/2/23"],
    ["2023/3/21"],
    ["2023/4/29"],
    ["2023/5/3"],
    ["2023/5/4"],
    ["2023/5/5"],
    ["2023/7/17"],
    ["2023/8/11"],
    ["2023/9/18"],
    ["2023/9/23"],
    ["2023/11/3"],
    ["2023/11/23"],
    // 追加の日付をここに続けて記入
  ];//祝日、連休日の設定

function autoReplyToEmails() {
  //自動返信対象の条件設定1(今日受信のメールのうち、未読、searchMailfromから届いたメール、searchSubjectを件名に含むメール)
  const searchToday = Utilities.formatDate(new Date(), 'JST', 'yyyy-MM-dd');
  const todayLog = Utilities.formatDate(new Date(), 'JST', 'yyyy-MM-dd hh:mm:ss');
  const query = 'after:' + searchToday + ' is:unread from:' + searchMailfrom + ' subject:' + searchSubject;
  const threads = GmailApp.search(query);
  console.log(query);

  //自動返信対象のメールを読込む
  threads.forEach(thread => {
    let messages = thread.getMessages();
    messages.forEach(message => {
      let sentDate = message.getDate();
     
      //自動返信対象の条件設定2(土・日曜日または祝日連休日)
      if (isWeekend(sentDate) || isSpecificDate(sentDate)) {
        let replyTo = message.getFrom(); // 返信先の取得
        let replySubject = 'Re: ' + message.getSubject(); // 件名の設定
        let replyBody = mailBody; //本文の設定

        GmailApp.sendEmail(replyTo, replySubject, replyBody, {  
          name: mailName,
          from: mailFrom,
          replyTo: mailFrom,
          bcc: mailBcc,
        }); //メール送信
        message.markRead(); //メールを既読に変更
        Logger.log(todayLog + ' 送信完了 ' + replyTo);
      }
    });
  });
}
//土曜日、日曜日の判定
function isWeekend(date) {
  const dayOfWeek = date.getDay();
  if(dayOfWeek === 0 || dayOfWeek === 6){ // 0: 日曜日, 6: 土曜日
    return true ;
  }
  return false;
}

//特定の日付(祝日、連休)の判定
function isSpecificDate(date) {
  let year = date.getFullYear();
  let month = date.getMonth();
  let day = date.getDate();

  for (let i = 0; i < specificDates.length; i++) {
    let specificYear = new Date(specificDates[i]).getFullYear();
    let specificMonth = new Date(specificDates[i]).getMonth();
    let specificDay = new Date(specificDates[i]).getDate();

    if (year === specificYear && month === specificMonth && day === specificDay) {
      return true;
    }
  }
  return false;
}

トリガーの設定

作成したGoogle App scriptを1時間に1回自動的に実行する設定をします。

トリガー > トリガーを追加

実行する関数を選択:autoReplyToEmails
実行するデプロイを選択:Head
イベントのソースを選択:時間主導型
時間ベースのトリガーのタイプを選択:時間ベースのタイマー
時間の間隔を選択(時間):1時間おき

GASがあるのが、Microsoft356の方がいい点だよな、と思っていたら365の方にもoffice Scriptなるものがあるらしい。やっぱりwindowsで仕事してると365の方がメリットが多そうだなー。とはいえ、Google Workspaceを365に入れかえるのはスイッチングコストが重すぎて、やる気になれない。