Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

はじめに

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を使う場合は、受信したアカウントから別のアカウントに転送してから処理しています。そうすればラベルを気にしなくて良いですし、件名でフィルタリングすればメールの件数も減りますので。

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

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした