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

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

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

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

Gmail

GmailとはGoogleによって提供されているウェブメールのサービスのことです。

Google Apps Script

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

Q&A

解決済

1回答

1055閲覧

GASでGmailに来た特定のメールアドレスをスプレッドシートに転記しているのですが、定時でトリガーが作動するたびに重複して追加されてしまいます。重複なくメールを転記したいです。

tomy224

総合スコア1

Google スプレッドシート

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

Gmail

GmailとはGoogleによって提供されているウェブメールのサービスのことです。

Google Apps Script

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

0グッド

2クリップ

投稿2023/08/02 11:00

実現したいこと

スプレッドシートに重複無くメールが転記されるようにしたいです。

前提

GASでGmailに来た特定のメールアドレスをスプレッドシートに転記しているのですが、定時でトリガーが作動するたびに重複してしまいます。重複なくメールを転記したいです。
※当方、GASのコードを記述できるわけではなく、ChatGPTに記述してもらった素人です。

発生している問題・エラーメッセージ

メールの転記部分に関しては問題なく出力されるのですが、トリガーが作動するたびに以前転記したメール内容も重複して転記してしまいます。

該当のソースコード

Gmailからスプレッドシートに出力される部分のコードです。
重複なく出力されるようコードを組んでもらったのですが、トリガーが起動するたびに以前転記したメールも重複してスプレッドシートに追加されてしまいます。

GAS

1var existingData = sheet.getDataRange().getValues().slice(1); 2var newData = []; 3 4for (var i = 0; i < threads.length; i++) { 5 var messages = threads[i].getMessages(); 6 for (var j = 0; j < messages.length; j++) { 7 var date = messages[j].getDate(); 8 var htmlBody = messages[j].getBody(); 9 var plainBody = extractPlainTextFromHTML(htmlBody); 10 var trimmedBody = removeUnnecessaryTextAndWhitespace(plainBody); 11 12 var isDuplicate = existingData.some(function (row) { 13 return row[0].getTime() === date.getTime() && row[1] === trimmedBody; 14 }); 15 16 if (!isDuplicate) { 17 newData.push([formatDate(date), trimmedBody]); 18 } 19 } 20} 21

全体のソースコード

GAS

1function myFunction() { 2 var subjectToSearch = "在庫数低下"; 3 var sheetName = "販売履歴メタ"; 4 5 var threads = GmailApp.search("subject:" + subjectToSearch); 6 var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName); 7 8 if (!sheet) { 9 sheet = SpreadsheetApp.getActiveSpreadsheet().insertSheet(sheetName); 10 sheet.appendRow(["販売日", "本文"]); 11 } 12 13 threads.sort(function (a, b) { 14 return a.getLastMessageDate() - b.getLastMessageDate(); 15 }); 16 17 var existingData = sheet.getDataRange().getValues().slice(1); 18 var newData = []; 19 20 for (var i = 0; i < threads.length; i++) { 21 var messages = threads[i].getMessages(); 22 for (var j = 0; j < messages.length; j++) { 23 var date = messages[j].getDate(); 24 var htmlBody = messages[j].getBody(); 25 var plainBody = extractPlainTextFromHTML(htmlBody); 26 var trimmedBody = removeUnnecessaryTextAndWhitespace(plainBody); 27 28 var isDuplicate = existingData.some(function (row) { 29 return row[0].getTime() === date.getTime() && row[1] === trimmedBody; 30 }); 31 32 if (!isDuplicate) { 33 newData.push([formatDate(date), trimmedBody]); 34 } 35 } 36 } 37 38 if (newData.length > 0) { 39 newData.sort(function(a, b) { 40 return new Date(a[0]) - new Date(b[0]); 41 }); 42 43 sheet.getRange(sheet.getLastRow() + 1, 1, newData.length, newData[0].length).setValues(newData); 44 } 45} 46 47function extractPlainTextFromHTML(html) { 48 var plainText = html.replace(/<[^>]+>/g, ''); 49 return plainText; 50} 51 52function removeUnnecessaryTextAndWhitespace(text) { 53 var productIndex = text.indexOf("商品情報"); 54 var recentIndex = text.indexOf("直近"); 55 56 if (productIndex !== -1 && recentIndex !== -1 && productIndex < recentIndex) { 57 return text.substring(productIndex + 4, recentIndex).replace(/\s+/g, ''); 58 } else if (productIndex !== -1) { 59 return text.substring(productIndex + 4).replace(/\s+/g, ''); 60 } else if (recentIndex !== -1) { 61 return text.substring(0, recentIndex).replace(/\s+/g, ''); 62 } else { 63 return text.replace(/\s+/g, ''); 64 } 65} 66 67function formatDate(date) { 68 var year = date.getFullYear(); 69 var month = ("0" + (date.getMonth() + 1)).slice(-2); 70 var day = ("0" + date.getDate()).slice(-2); 71 return year + "/" + month + "/" + day; 72}

補足情報(コードの説明)

  1. subjectToSearch変数に検索するメールの件名("在庫数低下")を指定します。
  2. sheetName変数にスプレッドシートのシート名("販売履歴メタ")を指定します。
  3. GmailApp.searchを使用して、指定された件名を持つメールをGmailから検索します。検索結果はthreadsに格納されます。
  4. SpreadsheetApp.getActiveSpreadsheet()を使用して、アクティブなスプレッドシートを取得します。
  5. SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName)を使用して、指定されたシート名のスプレッドシートを取得します。もし存在しない場合は、新しいシートを作成してsheetに格納します。その際、ヘッダー行(["販売日", "本文"])を追加します。
  6. threadsのメールを送信日時でソートします。
  7. sheet.getDataRange().getValues().slice(1)を使用して、既存のスプレッドシートのデータ("販売日"と"本文"のペア)を取得します。slice(1)はヘッダー行を除外するための処理です。
  8. 重複を避けるために、新しいメールのデータと既存のデータを比較します。重複しない場合、newDataに新しいデータ("販売日"と"本文"のペア)を追加します。
  9. もしnewDataにデータが存在する場合、newDataを日付でソートします。
  10. sheet.getRange(sheet.getLastRow() + 1, 1, newData.length, newData[0].length)を使用して、スプレッドシートの最後の行に新しいデータを追加します。

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

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

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

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

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

YellowGreen

2023/08/03 00:59 編集

スプレッドシートのデータは時刻部分がクリアされている日付なので メールから取得した日付も時刻部分をクリアして比較する必要があり、 このことが原因で同一メールの判定ができていない可能性があります。 var date = messages[j].getDate(); の後に date.setHours(0, 0, 0, 0); を追加してみるとどうなりますか?
attercop

2023/08/03 02:30

メッセージIDがメールごとにユニークですので、シートに保持して取得済かどうか判定されてはどうでしょうか。 messages[j].getHeader('Message-ID')
guest

回答1

0

ベストアンサー

メールを取得する際に日時指定してはどうですか?
そして、取得し終わったらその最終日時を覚えておいて、次回のメール取得時にその時間を開始日時とすれば、以前に取得したメールを再度取得しないと思いますが。

JavaScript

1 const date = new Date(); //現在時刻を取得(本当なら最終のメールの時間とする) 2 const now = Math.floor(date.getTime()/1000); //ミリ秒単位なので秒に変換 3 4 var threads = GmailApp.search(`after: ${now}` + " subject:" + subjectToSearch);

といった感じで指定の日時以降のメールを検索できます。

もしくは未読のメールのみ対象とするとか

JavaScript

1var threads = GmailApp.search("is:unread subject:" + subjectToSearch);

とすれば未読のメールが対象となります。
既読にするには

JavaScript

1 for (var i = 0; i < threads.length; i++) { 2 threads[i].markRead(); 3 var messages = threads[i].getMessages(); 4

とすればいいでしょう。

投稿2023/08/02 11:28

編集2023/08/03 01:46
YAmaGNZ

総合スコア10542

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

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

tomy224

2023/08/05 01:50

ご丁寧にありがとうございます。ご提案頂いたように読み込んだ最終メールをセルに入力しておき、そのセル以降のメールを取得すると指定したところ上手くゆきました。また何かありましたら、どうぞご指導よろしくお願いいたします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.31%

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

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

質問する

関連した質問