LoginSignup
2

More than 3 years have passed since last update.

posted at

updated at

GASでMailの内容を読み取って処理したい時

はじめに

Gmailに届いたメールをパースしてPDFに整形するサービスを作ったのですが、処理済みのメールを無視するのに少し手間取りました。ここでは現時点でベストと思う結論についてシェアしたいと思います。ちなみに、もちろんDBと連携するのが一番簡単ですが、外部との連携無しで検討した結果です。

メールの取得方法

メールの取得は次のように行います。

var threads = GmailApp.getInboxThreads(0,100);
var tlen = threads.length;

for (var i = 0; i < tlen; i++) {
  /* Do Something */
}

ここで取得出来るのはthreadであってmailでは無いのがポイントです。これが色々とややこしい事態を生み出しています。困った事に短期間で受信された同じタイトルのメールはthreadとしてバンドルされてしまうのです。例えば別のメールでも同じタイトルだと、まとめちゃうおじさんがどこからともなくやってきて、一つのthreadにまとめられてしまいます。
image.png

さて、これを前提に色々と検討してみます。

Archiveを使う

ArchiveするとgetInboxThreadsで取得されません。次は公式から持ってきたArchiveの例です。

var firstThread = GmailApp.getInboxThreads(0,1)[0];
firstThread.moveToArchive();

プログラムを見れば分かりますが、Archiveはthreadに対して実行します。従って、threadのメールを全て処理した後にArchiveする必要があります。この処理中に新しいメールがバンドルされたら、、、firstThread.refresh()が使えそうです。ややこしいですが。

ただ、やはりArchiveは使えません。何故かと言うと、Archiveしたthreadに新しいメールがバンドルすると受信箱に戻ってきてしまうからです(未練がましいですね)。そうするとまたgetInboxThreadsで取得出来てしまいます。従って、処理したいメールのタイトルが毎回違って、同じタイトルでメール受信する事がほとんどない場合は使えると思います。ただリフレッシュしないと問題は結構面倒だと思います(試してないですが)。

削除する

削除すればgetInboxThreadsで取得されません。次のように行います。

function deleteById(id) {
  const m = GmailApp.getMessageById(id);
  m.moveToTrash();
}

Archiveと違ってファイルに適用されるので、使いやすいです。ただし、moveToTrashしか出来ず、完全に削除するメソッドはありません。その為か新しいメールでバンドルされた場合はゾンビのように蘇ってきます。従って、同じ件名のメールがバンバン飛んでくる環境では使えません。また当然、メールを削除出来ない案件では使えません。

ラベルを使う

これも案件によっては使えない可能性がありますが、今の所ベストな方法です。ここでは処理済みのメールに特定のラベルを付けます。ラベルはThreadに付けるので、メールが個別に持つメールIDをラベルに入れます。こうする事で、同じスレッド無いで処理ずみと未処理のメールを分ける事が出来ます。

var threads = GmailApp.getInboxThreads(0,100);
var tlen = threads.length;

for (var i = 0; i < tlen; i++) {
  const messages = threads[i].getMessages();
  const mlen = messages.length;
  for (var j = 0; j < mlen; j++) {
    var m = messages[i];
    if (isValid(m)) {
       /* Do Something*/
       var label = GmailApp.getUserLabelByName("HOGE_" + m.getId());
       threads[i].addLabel(label);    
    }
  }
}

ただし、labelの名前は2000までという制限があるようです。前述した通り、受信する時間に間隔がある場合はbundleされませんので、ラベル付けから一日たったメールは"HOGE"という名前にしています。今の所はこれでうまくいっています。

まとめ

要件が許せば削除が一番簡単です。私も別の個人プログラムでは採用しています。ただしthread bundle問題を回避するのはlabelしか思いつきませんでした。なお、labelを使う場合は、受信したアカウントから別のアカウントに転送してから処理しています。そうすればラベルを気にしなくて良いですし、件名でフィルタリングすればメールの件数も減りますので。

もしもっと良い方法があったらコメント頂けると嬉しいです。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
2