質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Google スプレッドシート

Google スプレッドシートは、フリーで利用できる表計算ソフト。Webアプリのためインターネットに接続することで利用できます。チャートやグラフの作成のほか、シートを他のユーザーと共有したり、同時に作業を進めることも可能です。

Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

メール

メールは、コンピュータネットワークを利用し、 情報等を交換する手段のことです。

Q&A

解決済

1回答

1013閲覧

GAS 送付エラーになったメールアドレスをスプレッドシートに出力したい。

kenta_kenta

総合スコア19

Google スプレッドシート

Google スプレッドシートは、フリーで利用できる表計算ソフト。Webアプリのためインターネットに接続することで利用できます。チャートやグラフの作成のほか、シートを他のユーザーと共有したり、同時に作業を進めることも可能です。

Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

メール

メールは、コンピュータネットワークを利用し、 情報等を交換する手段のことです。

0グッド

2クリップ

投稿2021/12/20 09:33

編集2021/12/21 05:09

実現したいこと

GAS 送付エラーになったメールの内容を重複なくスプレッドシートに出力したい。

前提

Googleフォームの回答をトリガーに、フォームに入力されたアドレスへメールが自動送信されるGASを作成しました。
その際に入力されたアドレスにメールが届かない(送付エラー)場合に、その内容(日時、件名、本文、メッセージID)をスプレッドシートに出力するGASを作成したいです。

仕組みとしては、
1,エラーメールを受信するとにGメール内で作成した「送付エラー」ラベルが付く
2,プログラムが実行されると、スプレッドシートに出力され、該当メールに「処理済み」ラベルが付く
4,次回実行時は「処理済み」ラベルが付いたメールを除いてプログラムを実行される。(重複して出力されない)
というようなものです。

発生している問題

プログラムを実行すると、「処理済み」のメールフォルダに入っているメールの内、本日送付エラーになった別のメールの内容もスプレッドシートに出力されてしまう。
(昨日以前に送付エラーになっているメールは出力されないので、プログラム上では当日についた処理済みラベルは検知されないのでしょうか…?)

該当のソースコード

//送付エラーのメール内容をスプレッドシートに吐き出すGAS function getGmailToSS() { const ss = SpreadsheetApp.getActiveSpreadsheet(); const sheet = ss.getSheetByName('errordata_gmail'); const searchlabel = '"送付エラー"'; const threads = GmailApp.search('label:(' + searchlabel + ') -label:処理済み'); let lastRow = sheet.getRange("A:A").getValues().filter(String).length + 1; for(const n in threads){ const thread = threads[n]; const msgs = thread.getMessages(); msgs for(m in msgs){ const msg = msgs[m]; const date = msg.getDate(); const subject = msg.getSubject(); const body = msg.getPlainBody(); const id = msg.getId(); if(msgs.length > 0){ sheet.getRange(lastRow,1).setValue(date); sheet.getRange(lastRow,2).setValue(subject); sheet.getRange(lastRow,3).setValue(body); sheet.getRange(lastRow,4).setValue(id); lastRow++ const label = GmailApp.getUserLabelByName('処理済み'); thread.addLabel(label); } } } }

補足

メールのラベルは問題なく作動しています。
スプレッドシートへの出力も重複する事以外は問題なく出力されています。

GAS プログラミング共に初心者のため、初歩的なミスも含まれるかもしれませんがよろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sawa

2021/12/21 05:51 編集

初歩的というわけじゃなくて、たぶんエラーメールが同じスレッドになってる為に発生している問題かと思います。 Gmailはスレッドという考え方が基本にあるようで手動だと個々のメッセージ単位で出来る 「未読」や「ラベル」の検索、絞り込み がGASから実行するとスレッド単位で扱われてしまうのです。 GAS上でGmailAPIを使わないと メッセージ単位でラベルを扱うのは無理っぽいです。 この点に触れてる日本語のサイトが少ないんですよねー。 https://teratail.com/questions/334825 https://developers.google.com/gmail/api/reference/rest/v1/users.messages/get
kenta_kenta

2021/12/21 08:34

sawaさん、ご回答ありがとうございます。 そうなんですね、スレッド単位で扱われてしまうという考えはなかったです。勉強になりました! ちなみに、他に実現する方法はなにかありそうでしょうか…??
sawa

2021/12/21 08:54 編集

GmailAPIを使わない方法だと、やり方を変えていくしかないです。 ラベルだと メール毎の判別ができないので、例えば 「処理済み」のメールに対して ・スターをつける ・ゴミ箱に入れる ・未読(または既読)にする といった処理をすることで、検索では それらもスレッド毎抽出されてしまいますが、 その後 メッセージ毎に 判別することが出来るので ifで処理を分ければ良いです。 https://developers.google.com/apps-script/reference/gmail/gmail-message ↑ isなんちゃらというメソッドが使えると思います。 処理の書き方はこの辺りが参考になるかと。 https://teratail.com/questions/292371
kenta_kenta

2021/12/22 07:41

ありがとうございます。 参考にさせていただきます。
guest

回答1

0

ベストアンサー

よくよく質問のコードを見たら、メッセージ毎のIDもスプレッドシートに書き出しているので、
そのIDをもとに重複排除すれば良いですね。回答を入れておきます。

setValue をまとめて setValues にしている部分と、「処理済み」ラベルはどうせスレッド単位でしか付与できないので、場所を移してますが、それ以外はなるべく元のコードをいかしてます。

既に書き込まれているメールが重複しないようにする為、
A列のデータから取得されていた 最終行を D列のデータに変更し、
D列データ(メッセージID)の配列を使いました。

GmailAPIを使わない方法

GAS

1function getGmailToSS2() { 2 const ss = SpreadsheetApp.getActiveSpreadsheet(); 3 const sheet = ss.getSheetByName('errordata_gmail'); 4 5 const searchlabel = "送付エラー"; 6 7 const threads = GmailApp.search('label:(' + searchlabel + ') -label:処理済み'); 8 9 const msgIdArray = sheet.getRange("D:D").getValues().filter(String).flat(); 10 let lastRow = msgIdArray.length + 1; 11 12 for(const n in threads){ 13 const thread = threads[n]; 14 const msgs = thread.getMessages(); 15 msgs 16 17 for(m in msgs){ 18 const msg = msgs[m]; 19 const id = msg.getId(); 20 21 if(msgIdArray.includes(id)) continue; //IDがD列に既に存在する場合はスルー 22 23 const msgData = [[msg.getDate(),msg.getSubject(),msg.getPlainBody(),id]]; 24 sheet.getRange(lastRow,1,1,4).setValues(msgData); //まとめて書き込み 25 26 lastRow++ 27 } 28 29 const label = GmailApp.getUserLabelByName('処理済み'); 30 thread.addLabel(label); 31 } 32} 33

GmailAPIを使う方法

ついでにGmailAPIを使ったメッセージ単位でラベルを扱う回答も入れておきます。
(検索した感じ、日本語での解説があまり見当たらなあったので)

ハードル高そうですが、GAS内で簡単な処理をする分にはそうでもないです。
ただ、事前準備が必要になります。

  1. プロジェクトにGmailAPIを追加(サービスのところから)
  2. 事前にGmailAPIを使って ラベルIDを取得しておく(以下のコードのログから確認)

GAS

1function listLabels() { 2 const labels = Gmail.Users.Labels.list('me'); 3 console.log(labels); 4}

↑ ラベル名で探し該当のオブジェクト内にある Label_**** というのが ラベルIDで、これを使います。
今回だと 「送付エラー」と「処理済み」のラベルIDを使う。

↓メッセージ(メール)単位で ラベルをチェックし処理するコード

GAS

1function getGmailToSS3() { 2 const ss = SpreadsheetApp.getActiveSpreadsheet(); 3 const sheet = ss.getSheetByName('errordata_gmail'); 4 5 const searchlabel = "送付エラー"; 6 7 const threads = GmailApp.search('label:(' + searchlabel + ') -label:処理済み'); 8 9 let lastRow = sheet.getRange("A:A").getValues().filter(String).length + 1; 10 11 const errorLabelId = "Label_****"; //送付エラーラベルのID 12 const doneLabelId = "Label_****"; //処理済みラベルのID 13 14 for(const n in threads){ 15 const thread = threads[n]; 16 const msgs = thread.getMessages(); 17 msgs 18 19 for(m in msgs){ 20 const msg = msgs[m]; 21 const id = msg.getId(); 22 const msgLabelIds = Gmail.Users.Messages.get('me',id).labelIds; //GmailAPIでメッセージ単位のラベルIDの配列を取得 23 24 if(msgLabelIds.includes(doneLavbelId)) continue; //取得したラベルIDに「処理済み」のIDが含まれていたら スルー 25 26 const msgData = [[msg.getDate(),msg.getSubject(),msg.getPlainBody(),id]]; 27 sheet.getRange(lastRow,1,1,4).setValues(msgData); //まとめて書き込み 28 29 lastRow++ 30 31 //メール単位で「処理済み」ラベルを設定 32 Gmail.Users.Messages.modify({ 33 'addLabelIds': [doneLabelId] 34 }, 'me', id); 35 36 } 37 } 38}

投稿2021/12/23 02:05

sawa

総合スコア3002

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kenta_kenta

2021/12/23 04:43

詳しく回答ありがとうございます。 GmailAPIを使わない方法で実装し、うまくできました。 回答を丸々いただく形となり大変恐縮ですが、しっかり内容理解して今後に活かしていきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問