だって楽したいじゃんか!

大学院(機械工学科)を首席で卒業した男がこれまでの経験を生かさず殺さず発信していく

【GAS】定期的に特定条件のメールを抽出し転送する方法

f:id:makimakimakino:20190114224927p:plain
こんにちは、まきのです。

クライアントからの問い合わせメールに返信できてなかった!orz
メールが埋もれててどれに返信したかわからなくなってきた!orz

なんてことあると思います。

そこで今回は定期的に特定条件(未返信)のメールを取得し、リマインドメールを送信してくれる方法をGASを使って実現してみたいと思います。

プロジェクト作成

まずはGASのプロジェクトを作ります。作り方は下記を参照ください。
makimakimakino.hatenablog.com


コード作成

コードの紹介から。
大きな流れとしては次の通りのことをしています。

  • 検索条件を指定し関連スレッドを取得
  • 取得したスレッドからメールを絞り込み
  • メールをサマって転送


コード.gs

function mailForward() {
  //検索条件に合致するメールを抽出
  var query = 'subject:"[GAS][MAIL][TEST]テストメール" newer_than:1d'; //検索条件
  var threads = GmailApp.search(query, 0, 10); //条件に合致するメールのスレッドを取得
  var messages = GmailApp.getMessagesForThreads(threads); //スレッド内のメールを取得。[スレッド番号][メッセージ番号]の2次元配列になる
  
  var myMailAddress = 'sample@xxxx.com'; //最後の送信者がこのアドレス(自分)に合致していないものは未返信
  
  var forwardTo = 'sample@yyyy.com'; //抽出した結果を転送する転送先アドレス
  var forwardSubject = '[GAS][MAIL][TEST][FORWARD]テストメール'; //抽出した結果を転送する転送メールの件名
  var forwardBody =''; //抽出した結果を転送する転送メールの本文
  
  //1スレッドずつ未返信か確認
  for(var i=0; i < messages.length; i++) {
    var lastNum = messages[i].length-1; //スレッドの最後のメールのインデックスを取得(indexは0から始まるから-1する)
    //Logger.log('やり取り数:'+ lastNum);

    var lastSender = messages[i][lastNum].getFrom(); //最後のメールの送信者を取得
    //Logger.log('最後の送信者:'+ lastSender);
    
    //未返信メール判定
    if(lastSender.indexOf(myMailAddress) == -1){ //indexOfは文字列に指定した文字が含まれていない場合は戻り値が-1となる
      var messageId = messages[i][lastNum].getId(); //メッセージIdを取得
      var messageDate = messages[i][lastNum].getDate(); //メッセージの受信日時を取得
      var messageSubject = messages[i][lastNum].getSubject(); //メッセージの件名を取得
      var messageBody = messages[i][lastNum].getPlainBody(); //メッセージの本文を取得
      forwardBody = forwardBody +
        'メッセージID : ' + messageId + '\r\n' +
          '送信者 : ' + lastSender + '\r\n' +
            '送信日 : ' + messageDate + '\r\n' +
              '件名 : ' + messageSubject + '\r\n' +
                '内容 : \r\n' + messageBody + '\r\n' +
                  '+++++++++++++++++++++++++++++++++++++++++++++++\r\n\r\n'; //転送用のメッセージ本文を作成
    }
  }
  //Logger.log(forwardBody);
  
  //未返信メールの情報を転送
  GmailApp.sendEmail(forwardTo, forwardSubject, forwardBody);
}

解説と注意点

検索条件の指定の仕方はGmailでメールを検索するときと同じ指定の仕方になります。
support.google.com

検索条件はお好みで設定してください。

条件をあれこれ変えながら試してみたいという場合は、Gmailの画面を開き、条件を入力して、目的のメールスレッドが引っかかるか試してみるといいと思います。

今回使った条件(subject:"[GAS][MAIL][TEST]テストメール" newer_than:1d)の意味は、件名が完全一致かつ前日以降に送信されたメールを対象とするです。

subjectが件名で検索、"文字列"で文字列完全一致、半角スペースでキーワードをつなぐことで&条件になり、newer_than:1dで1日前より新しいメールという指定をしています。

他にも自分で作ったGmailのラベルやスター付き、重要など、Gmail標準に備わっている条件も使えるようなので、あまりにも条件が複雑になるようであれば、あらかじめラベルやフィルタを自分で作っておくというのも簡素化するうえで重要かと思います。
qiita.com


また、GmailApp.searchでメールを取得できる時間には上限があるようです。

1回の取得あたり最大5分らしいので、本当に必要な検索条件に絞らないと、メールを取りに行っている間にタイムアウトしてしまい、欲しいメールが取りきれないいうことが起きてしまいます。

検索条件をうまいこと作る必要があるみたいですね。


未返信かどうかの判定をしているロジックについても、今回は最後のメッセージの送信者を取得して特定のアドレス(myAddress)でないものを未返信のメールと判断していますが、GmailMessageクラスはほかに様々な条件を持っているみたいなので、本文の内容を目的のメール抽出の判断条件にするなど、状況に応じて試してみるといいでしょう。
developers.google.com

また、今回は特定の条件のメールをサマリメールとして最後に一括送信していますが、GmailMessageクラスはreply(返信)やforward(転送)メソッドも用意されているので、取得したメールに「確認します。」などの自動応答をつけることや、一通ごとに別メールアドレスに転送するといったことも可能です。

定期実行の設定

さて、作ったプロジェクト(関数)を定期的に実行できるようにしたいです。

そこで、トリガーを設定しましょう。(トリガーのやり方変わったんですね。知らなかった。。。)

GASのエディタの時計?のようなマークをクリックします。
f:id:makimakimakino:20190727130952p:plain

別窓でこのプロジェクトのトリガー設定画面が表示されます。
トリガーを追加を押下します。
f:id:makimakimakino:20190727131111p:plain

実行する関数、デプロイ、イベントのソース、トリガータイプ、時刻、エラーを受け取る設定などを指定します。

今回は日次の決まった時間に実行してもらうので、画像のような設定になります。
f:id:makimakimakino:20190727131229p:plain

保存を押下します。
f:id:makimakimakino:20190727131331p:plain

ちなみに、時刻を設定した場合、分以下については保存を押したときの時刻が自動で設定されるようです。

指定した時刻の00分に飛ばしたいときは、保存ボタンをn時00分に押すといいでしょう。(分以下も自由に指定できるようにならないんですかね?)

まとめ

特定の条件に合致するメールを取得し、定期的に転送してくれる機能をGASを使って実装しました。

今回は日次で未返信のメールを抽出し、サマリ情報をリマインドしてくれるような作りになっています。

肝になるのはたぶんメールの検索条件を作るところかなと思います。

Gmailの場合スレッドが取得できるのですが、同スレッド内の不要なメールも取得されていたり、割とシビアに検索条件をしていしないと、Gmailのあいまい検索で引っかかるのかなんでも取れてきてしまうなんてことがあります。