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

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

新規登録して質問してみよう
ただいま回答率
86.12%
Gmail

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

Google Apps Script

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

解決済

【GAS】代理アクセスしているメールBOXからのメール抽出がしたい

donguriko
donguriko

総合スコア26

Gmail

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

Google Apps Script

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

1回答

0グッド

0クリップ

209閲覧

投稿2022/11/02 09:43

前提

GASでメールBOX内を検索し、
一定の条件に合致したメールをスプレッドシート上に
一覧表示させたいです。

【スプレッドシートイメージ】
転記シート
ひながた。
このシートをコピーし、抽出結果を転記するシートを作成
イメージ説明

検索シート
検索条件のうち、検索対象の開始日、終了日と抽出結果を転記する
シートのシート名指定用
イメージ説明

GASを作成するメールアカウントは次の2つのメールBOXへの
アクセス権があります。
a)個人アドレス(アカウント)のメールBOX
b)代理アクセス権が付与されているチームアドレスのメールBOX

実現したいこと

今回 a)のアカウントでGASを作成し、
b)のメールBOX内のメールを抽出したいと思っています。

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

3点困っています。

①query条件を変数? で可変にできない
検索条件の開始日、終了日を可変にしたいので、
検索シートからgetValue()で取得し、
GmailApp.search(query, start, max); のqueryで使いたいのですが
うまくできません。
HITしないようで、新たに結果転記用の2022年10月分のシート上に何も
抽出されてきません。

const query = 'subject:お支払金額のお知らせ after:2022/6/1 before:2022/10/1';
とコード内に日付を直接記載すると、抽出されます。
どのようにコードを修正すればよいか、ご教示ください。

②b)のメールBOX内のメール抽出ができない
b)のメールBOX内にしか存在しない件名で抽出を試みると、HIT
しないようで、何も抽出されてきません。

GASを作成するメールアカウント!=の時は代理アクセス権が付与
されているメールBOX内からの抽出はNGでしょうか?
それとも、コード修正で抽出可能でしょうか?
抽出可能な場合、どこをどのように修正すればよいか、アドバイス
が欲しいです。

③以下のコードの意味がよく分からない
const ids = targetSheet.getRange(4, 7, lastRow).getValues().flat();
// 一次元配列化するためにflat???

 下リンク先に解説はあるのですが、なぜ一次元化が必要なのか、
「深さ」の部分の記載の意味がよく分かりません。
本来はこちらで照会すべき内容ではないかとは思いますが、
可能であればこちらも補足解説をいただけると助かります。
参照元

該当のソースコード

以下全文記載します。

GAS

1function searchMail() { 2 3 //参照:隣IT https://tonari-it.com/gas-gmail-spreadsheet/ 4 //参照:https://tetsuooo.net/gas/1267/ 5 // 6 //<<GAS処理概要>> ************************************************************ 7 //(処理①)Gmail 件名に「お支払金額のお知らせ」が含まれる 8 //     かつ「2022/6/1より後に受信」 9 //     かつ「2021/10/1より前に受信」』に該当するメール 10 //(処理②)日付、FROM、件名、本文(Max200文字)、リンク、メッセージidの6つを取得 11 //(処理③)スプシの「メール書出し練習」シートの最終行のB列~G列に転記し、H列に転記日を追記 12 //(処理③-1)すでに転記済のメッセージは転記処理しない 13 // *************************************************************************** 14 15 const ss = SpreadsheetApp.getActiveSpreadsheet(); 16 const searchSheet = ss.getSheetByName('検索シート'); 17 const orgSheet = ss.getSheetByName('転記シート'); 18 const sheetName1 = searchSheet.getRange(4,3,1,1).getValue(); //検索シートセルC4 19 const sheetName2 = sheetName1+"年" 20 const sheetName3 = searchSheet.getRange(4,5,1,1).getValue(); //検索シートセルE4 21 const sheetName4 = sheetName3+"月作業分" 22 const newSheetName = sheetName2 + sheetName4 23 console.log("newSheetName " + newSheetName); // yyyy年m月作業分 が正解 24 const writeSheet = ss.getSheetByName(newSheetName); 25 26//ファイル内に転記シートのコピーを作成し、シート名変更、一番左に移動 27 const newSheet = orgSheet.copyTo(ss); //転記シートをコピー 28 newSheet.setName(newSheetName); //シート名変更 29 30 const targetSheet = ss.getSheetByName(newSheetName); 31 32 //(処理①) 33 // 抽出条件指定 34 //条件①:件名に「お支払金額のお知らせ」が含まれる 35 //条件②:指定日以降に受信 36 //条件③:指定日以前に受信 37 38 const startDate1 = searchSheet.getRange(6, 3).getValue(); //検索シートセルC6 39 const startDate2 = Utilities.formatDate(startDate1, 'JST','yyyy/M/d') 40 const endDate1 = searchSheet.getRange(7, 3).getValue(); //検索シートセルC7 41 const endDate2 = Utilities.formatDate(endDate1, 'JST','yyyy/M/d') 42 console.log("startDate1 " + startDate1); //2022/6/1が正解 43 console.log("endDate " + endDate1); //2022/10/1が正解 44 console.log("startDate2 " + startDate2); 45 console.log("endDate2 " + endDate2); 46 47 //const query = 'subject:お支払金額のお知らせ after:startDate2 before:endDate2'; //★うまくできない 48 const query = 'subject:お支払金額のお知らせ after:2022/6/1 before:2022/10/1'; 49 50 //GmailApp.search(検索条件, 開始スレッドのインデックス, 最大取得数) 51 //スレッドは0スタートの二次元配列(values)として取得 52 //messagesForThreads[0][0] 1スレの1つ目Msg 53 //messagesForThreads[0][1] 1スレの2つ目Msg(1回目の返信) 54 //messagesForThreads[1][0] 2スレの1つ目Msg 55 56 const start = 0; 57 const max = 20; 58 const threads = GmailApp.search(query, start, max); 59 const messagesForThreads = GmailApp.getMessagesForThreads(threads); 60 61 //(処理②) 62 //配列valuesの要素(record)は日付、FROM、件名、本文(Max200文字)、リンク、メッセージidの6つ 63 const values = []; 64 const lastRow = targetSheet.getRange(targetSheet.getMaxRows(),3).getNextDataCell(SpreadsheetApp.Direction.UP).getRow(); //B列最終行から上方向検索でデータあり最終行取得 65 console.log("lastRow " + lastRow); // 3が正解 66 67 // getRange(●行番号, ▲列番号, □行分, ■列分) >>4行目、C列 68 const ids = targetSheet.getRange(4, 7, lastRow).getValues().flat(); //一次元配列化するためにflat??? 69 70 //for文でループ処理 71 //メッセージIDをループ処理で取得 72 for (const messages of messagesForThreads) { 73 const message = messages[0]; 74 const id = message.getId(); 75 76 //(処理③-1) 77 //配列の中に同じメッセージidが含まれているか否かで条件分岐 78 //!はnot演算子。真偽値が逆になる 79 // 含まれない>>true、含まれる>>false 80 //trueの場合のみif文処理実行 81 if (!ids.includes(id)) { 82 const record = [ 83 message.getDate(),   //受信日 84 message.getReplyTo(), //返信先アドレス 85 message.getSubject(), //件名 86 message.getPlainBody().slice(0, 200), //メール本文(MAX200文字) 87 message.getThread().getPermalink(), //メールへのリンク 88 message.getId() //メッセージID 89 ]; 90 values.push(record); 91 console.log("values " + values); 92 } 93 } 94 95 //(処理③) 96 // getRange(●行番号, ▲列番号, □行分, ■列分) + setValues(で配列データを吐き出し) 97 //該当データありの時、転記シート(mySheet)の最終行のC列~H列にデータ吐出しし、 98 const timeStamp = Utilities.formatDate(new Date(), 'Asia/Tokyo', 'yyyy/MM/dd HH:mm'); 99 if (values.length > 0) { 100 targetSheet.getRange(lastRow + 1, 3, values.length, values[0].length).setValues(values); 101 targetSheet.getRange(lastRow + 1, 9, values.length, 1).setValue(timeStamp); 102 } 103targetSheet.activate(); 104 105 106ソースコード

試したこと

②に対して試したこと
a)のメールBOX内にしか存在しない件名で抽出を試みると想定通りの
抽出がされます。

検索条件queryに 現コードで記載した条件に加え、
to: 代理アクセス権が付与されているチームアドレスを追加。
⇒HITしないようで、何も抽出されてきません。

※a)b)双方のメールBOXで存在する条件での抽出は投稿時点で該当が
なかったためトライしていないです。

補足情報(FW/ツールのバージョンなど)

回答は急ぎません。
お忙しい中、お手を煩わせてしまい申し訳ありませんが、
非エンジニアビギナーでも分かるレベルでの解説、アドバイスを
いただけると助かります。

以下のような質問にはグッドを送りましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

グッドが多くついた質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

下記のような質問は推奨されていません。

  • 間違っている
  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

回答1

0

ベストアンサー

①query条件を変数? で可変にできない

const query = 'subject:お支払金額のお知らせ after:startDate2 before:endDate2';
このように書いてしまうと、startDate2endDate2もただの文字として認識されます。
変数を変数として使用するための方法は下記の2つあります。

1.結合する

js

1const query = 'subject:お支払金額のお知らせ after:' + startDate2 + ' before:' + endDate2;

2.テンプレートリテラルを使用する

js

1const query = `subject:お支払金額のお知らせ after:${startDate2} before:${endDate2}`;

②b)のメールBOX内のメール抽出ができない

GmailAppでは、代理権限をもったアカウントのメールボックスにはアクセスできないようです。
GmailのAPIを使うとアクセスできるかもしれませんが、実施したことはないので回答は控えます。

③以下のコードの意味がよく分からない
const ids = targetSheet.getRange(4, 7, lastRow).getValues().flat();

参照元のURLが不正だったので見れていませんが、getValues()で値を取得したときは行×列の2次元配列で取得されます。
今回の場合だと下記の感じ。(あえてインデントしています。そしてこのインデントの量が"深さ"と思っていただければ。)

js

1[ 2 [ 3 'A' 4 ], 5 [ 6 'B' 7 ], 8 [ 9 'C' 10 ] 11]

配列から全ての要素を取り出すときには多くの場合でループを使用しますが、深さが増えるとループの数が増えます。
今回のように下層の要素の数がわかっている場合や、その順序などに意味がない場合には深さを減らすとループの数が減ります。(ループの"量"は変わりませんが、必要なforの数が減ります。)
そのため、flat()して、深さを減らしています。
減らすと下記になります。

js

1[ 2 'A', 3 'B', 4 'C' 5]

投稿2022/11/04 00:04

macaron_xxx

総合スコア3140

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

回答へのコメント

donguriko

2022/11/06 09:08

macaron_xxxさま お忙しい中、回答ありがとうございます。 そして、リアクションが遅くなり申し訳ありません。 ①結合または、テンプレートリテラルを使用することで解消可能なのですね。  結合の場合は、「startDate2、endDate2の手前までを ' ' で囲み、+でつなぐ」、  覚えたいと思います。   ②今の私の知識と技術レベルではGmailのAPIを使うのはハードルが高そうなので、  残念ですが今回は断念しようと思います。アドバイスありがとうございます。 ③どのような場合に使用するか、flat()にすると~メリットについての  解説ありがとうございます。少しイメージがつかめました。    お忙しい中、回答ありがとうございました。

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

ただいまの回答率
86.12%

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

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

質問する

関連した質問

同じタグがついた質問を見る

Gmail

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

Google Apps Script

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