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

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

ただいまの
回答率

90.10%

【GAS】複数キーワードの検索ができない

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 938

yours

score 7

Gmailを複数ある検索条件に該当するメールを抽出したいのですが、うまく抽出されません。

検索条件はセルB2からB6に5個入力(文字)でき、その文字に該当する物だけを抽出したいのです。

例えば、検索条件としてある時は「B2に【申込書】、B3に【請求書】、B4に【完了】」と入力し、
その入力した文字がSubjectに含まれている物を抽出したいのです。
また、ある時は、「B2に【申請中】、B3に【承認待ち】」と入力して
その入力した文字がSubjectに含まれている物を抽出したいのです。

抽出先は、10行目から下で、A列は受信日、B列は件名、C列は受信者IDになります。

コード
function 複数検索メール取得() {
  /* Gmailから特定条件のスレッドを検索しメールを取り出す */
  //1. 現在のスプレッドシートを取得
  var sh = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('メール');
  //2. 指定するセルの範囲(B2,B3,B4,B5,B6)を取得
  var kw1 = sh.getRange('B2');//keyword1
  var kw2 = sh.getRange('B3');//keyword2
  var kw3 = sh.getRange('B4');//keyword3
  var kw4 = sh.getRange('B5');//keyword4
  var kw5 = sh.getRange('B6');//keyword5

  var strTerms = ('Subject:(kw1 kw2 kw3 kw4 kw5 To:(ABC@gmail.com) after:2019/3/1');
  var myThreads = GmailApp.search(strTerms, 0, 100); 
  var myMsgs = GmailApp.getMessagesForThreads(myThreads);//二次元配列 GmailApp.getInboxThreads
  var valMsgs = [];
  /* 各メールから日時、送信元、件名、内容を取り出す */
  for(var i=0;i<myMsgs.length;i++){
  for(var j=0;j<myMsgs[i].length;j++){
   var msid = myMsgs[i][j].getId();//メッセージIDを取得
   //もしメッセージIDがスプレッドシートに存在しなければ
   if(!hasId(msid)){
    var date = myMsgs[i][j].getDate();
    var subj = myMsgs[i][j].getSubject();
    valMsgs.push([date,subj,msid]);
   }
  }
 }

 /* スプレッドシートに出力 */
 if(valMsgs.length>0){//新規メールがある場合、末尾に追加する
  var lastRow = sh.getDataRange().getLastRow();
  sh.getRange(lastRow+1, 1, valMsgs.length, 3).setValues(valMsgs);

  var sheet = SpreadsheetApp.getActiveSheet();
  var lastRow = sheet.getLastRow();
  var lastCol = sheet.getLastColumn();
  sheet.getRange(10, 1, lastRow, lastCol).sort(1);
 }
}

function hasId(id){
  var data = sh.getRange(1, 3, sh.getLastRow(),1).getValues();//C列(メッセージID)を検索範囲とする
  var hasId = data.some(function(value,index,data){//コールバック関数
    return (value[0] === id);
  });
  return hasId;
}

参考にしたスクリプトは下記のものです。

https://tonari-it.com/gas-gmail-messageid/

どなたか、ご教授を宜しくお願いいたします。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

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

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

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • yours

    2019/04/15 16:38

    jinbe様
    ご迷惑おかけいたしました。
    ありがとうございます。

    キャンセル

  • macaron_xxx

    2019/04/16 09:05

    >うまく抽出されません。
    とありますが、何が抽出されていますか?なにがうまくいっていないのでしょうか。
    それがわからないです。

    キャンセル

  • yours

    2019/04/16 10:29

    macaron_xxx様
    スクリプトを起動させても、何も抽出されず、件数は0(ゼロ)件でした。
    ご説明が足りず、大変申し訳ございませんでした。m(__)m

    キャンセル

回答 2

checkベストアンサー

+1

次のような修正はいかがでしょうか。

1. 関数名について

今、関数名に2バイト文字(function 複数検索メール取得() {})を使用しておられますが、できれば、function getSrarchedMails() {}など、1バイト文字にしてください。確か2バイト文字で関数名を指定した場合、GASでは動作しなかったように思われます。

2. 検索クエリについて

修正ポイントは次の通りです。

  1. OR検索は、{}を使います。AND検索は()です。
  • 今の場合、"B2:B6"の値をOR検索し、toとafterはAND検索しますので、次のように設定します。
  • 'Subject:{kw1 kw2 kw3 kw4 kw5} To:(ABC@gmail.com) after:2019/3/1'
  • ここで、kw1 kw2 kw3 kw4 kw5はそのまま文字列として扱われてしまいますので、これを変数として使用するように修正します。
  1. "B2:B6"の値を一度に取得するとコストが低くなります。

これらをスクリプトへ反映させるために次のような修正を行ってください。

From

var kw1 = sh.getRange('B2');//keyword1
var kw2 = sh.getRange('B3');//keyword2
var kw3 = sh.getRange('B4');//keyword3
var kw4 = sh.getRange('B5');//keyword4
var kw5 = sh.getRange('B6');//keyword5

var strTerms = ('Subject:(kw1 kw2 kw3 kw4 kw5 To:(ABC@gmail.com) after:2019/3/1');

To

var kws = sh.getRange("B2:B6").getValues().map(function(e) {return e[0]}).join(" ");
var strTerms = 'subject:{' + kws + '} to:ABC@gmail.com after:2019/3/1';

3. 他のエラーについて

おそらく上記の変更を行うと、次はhasId(id)内でエラーが発生すると思われます。原因は、sh.getRange(1, 3, sh.getLastRow(),1).getValues()shが与えられていないためです。そこで、次のような修正をお願いします。

From

if(!hasId(msid)){

To

if(!hasId(msid, sh)){

これと下記の修正もお願いします。

From

function hasId(id){

To

function hasId(id, sh){

参考

編集

一番初めにスクリプトの修正をして下さった時に抽出したデータにメッセージに紐づくRe(レス)も抽出されていた為、出来ればファーストメッセージだけを抽出したかっただけです。

上記のコメントにより修正するポイントは下記の通りです。「ファーストメッセージだけを抽出」については、メッセージのインデックス0番目がトップのメッセージを意味します。

From

  for(var i=0;i<myMsgs.length;i++){
  for(var j=0;j<myMsgs[i].length;j++){
   var msid = myMsgs[i][j].getId();//メッセージIDを取得
   //もしメッセージIDがスプレッドシートに存在しなければ
   if(!hasId(msid)){
    var date = myMsgs[i][j].getDate();
    var subj = myMsgs[i][j].getSubject();
    valMsgs.push([date,subj,msid]);
   }
  }
 }

To:

for(var i=0;i<myMsgs.length;i++){
  var msid = myMsgs[i][0].getId();
  if(!hasId(msid, sh)){
    var date = myMsgs[i][0].getDate();
    var subj = myMsgs[i][0].getSubject();
    valMsgs.push([date,subj,msid]);
  }
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

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

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

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/04/17 09:17

    kosojin様

    おはようございます。

    検証の結果、文字列の中にスペースがあると、関係ないものまで抽出されてしまうことが分かりました。

    お手数お掛けして、大変申し訳ございませんでした。

    良い物になったので、感謝しております。

    誠に、ありがとうございました。

    キャンセル

  • 2019/04/18 11:07

    無事に解決したとのこと、ご連絡有難うございます。安心しました。私自身、この質問から勉強をさせていただきました。こちらこそありがとうございました。

    キャンセル

  • 2019/04/18 14:43 編集

    kosojin様

    先日はありがとうございました。

    またまた、お力をお借りしたいのですが・・・。

    検索条件を入力するセルは、出力するシートと同じシートでしたが、
    出来れば、同じシートではなく、追加で別シートを作成し、シート名が「検索キーワード」としたいのです。

    検索キーワードを入力するセルは、「B2:B101」の100件を予定しております。

    どのように変更すればよいのか、ご教授を宜しくお願いいたします。

    現在のスクリプトを貼り付けます。

    function getSrarchedMails() { //Gmailから特定条件のスレッドを検索しメールを取り出す */
    var sh = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('メール'); //現在のスプレッドシートを取得
    var kws = sh.getRange("B2:B6").getValues().map(function(e) {return e[0]}).join(" "); //指定するセルの範囲(B2:B6)の検索値を取得
    var strTerms = 'subject:{' + kws + '} to:ABC@Gmail.com after:2019/3/1'; //検索値、To、2019/3/1以降のデータを検索
    var myThreads = GmailApp.search(strTerms, 0, 100);
    var myMsgs = GmailApp.getMessagesForThreads(myThreads);//二次元配列 
    var valMsgs = [];

    for(var i=0;i<myMsgs.length;i++){ // 各メールから日時、件名、IDを取り出す
    var msid = myMsgs[i][0].getId();
    if(!hasId(msid, sh)){
    var date = myMsgs[i][0].getDate();
    var subj = myMsgs[i][0].getSubject();
    valMsgs.push([date,subj,msid]);
    }
    }

     /* スプレッドシートに出力 */
     if(valMsgs.length>0){//新規メールがある場合、末尾に追加する
      var lastRow = sh.getDataRange().getLastRow();
      sh.getRange(lastRow+1, 1, valMsgs.length, 3).setValues(valMsgs);

    var sheet = SpreadsheetApp.getActiveSheet();
    var lastRow = sheet.getLastRow();
    var lastCol = sheet.getLastColumn();
    sheet.getRange(10, 1, lastRow, lastCol).sort(1);
     }
    }

    function hasId(id, sh){
    var sh = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('メール');
    var data = sh.getRange(1, 3, sh.getLastRow(),1).getValues();//C列(メッセージID)を検索範囲とする
    var hasId = data.some(function(value,index,data){//コールバック関数
    return (value[0] === id);
    });
    return hasId;
    }

    お騒がせ致しました。

    色々とやってみたところ、下記のスクリプトで完成いたしました。

    変更点:「sh」を分けました。メール出力シートを「sh1」検索キーワードを「sh2」
    スプレッドシートの出力する際、シートの指定

    ありがとうございました。

    function getSrarchedMails() { //Gmailから特定条件のスレッドを検索しメールを取り出す */
    var sh2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('検索キーワード'); //現在のスプレッドシートを取得
    var kws = sh2.getRange("B2:B101").getValues().map(function(e) {return e[0]}).join(" "); //指定するセルの範囲(B2:B101)の検索値を取得
    var strTerms = 'subject:{' + kws + '} to:ABC@Gmail.com after:2019/3/1'; //検索値、To、2019/3/1以降のデータを検索
    var myThreads = GmailApp.search(strTerms, 0, 100);
    var myMsgs = GmailApp.getMessagesForThreads(myThreads);//二次元配列 
    var valMsgs = [];

    for(var i=0;i<myMsgs.length;i++){ // 各メールから日時、件名、IDを取り出す
    var msid = myMsgs[i][0].getId();
    if(!hasId(msid, sh1)){
    var date = myMsgs[i][0].getDate();
    var subj = myMsgs[i][0].getSubject();
    valMsgs.push([date,subj,msid]);
    }
    }

     /* スプレッドシートに出力 */
    var sh1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('メール');
    if(valMsgs.length>0){//新規メールがある場合、末尾に追加する
      var lastRow = sh1.getDataRange().getLastRow();
      sh1.getRange(lastRow+1, 1, valMsgs.length, 3).setValues(valMsgs);

    var sheet = SpreadsheetApp.getActiveSheet();
    var lastRow = sheet.getLastRow();
    var lastCol = sheet.getLastColumn();
    sheet.getRange(5, 1, lastRow, lastCol).sort(1);
     }
    }

    function hasId(id, sh1){
    var sh1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('メール');
    var data = sh1.getRange(1, 3, sh1.getLastRow(),1).getValues();//C列(メッセージID)を検索範囲とする
    var hasId = data.some(function(value,index,data){//コールバック関数
    return (value[0] === id);
    });
    return hasId;
    }

    キャンセル

0

'Subject:(kw1 kw2 kw3 kw4 kw5 To:(ABC@gmail.com) after:2019/3/1'


この部分が変数になっていないですね。

'Subject:('+kw1+' '+kw2+' '+kw3+' '+kw4+' '+kw5+') To:(ABC@gmail.com) after:2019/3/1'


こんな感じかな?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

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

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

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/04/16 10:23

    macaron_xxx様

    ご教授ありがとうございます。

    検索条件での抽出はできませんでした。

    お忙しい中、ご教授頂き、誠にありがとうございます。

    キャンセル

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

  • ただいまの回答率 90.10%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる