GASでGmailからCSVをGoogleDriveに保存する

Gmailにある受信メールからCSVをGoogleDriveへ抽出するGoogleAppsScriptです。

対象のラベルを作成する

受信メールの特定のフォルダ(ラベル)にある未読メールを自動で処理したいため、対象のフォルダを作成します。「a自動振り分け」というラベルを作成し、そのサブラベルとして「1処理前」を作成しました。

CSVファイルを抽出後は「2処理後」のラベルに移動します。

自動でラベリングするように設定する

フィルタを利用して、Fromや件名などで自動で「1処理前」にフィルタリングします。

スプレッドシートに紐付いたコンテナバインド型のGoogle Apps Script(GAS)

スプレッドシートに紐づくGASを作成しました。スプレッドシートのカスタムメニューから実行するようにします。

メニュー表示とシート表示のGAS

前半部分のメニュー表示と対象のシートをActiveにするGASです。

'use strict'

// getUserLabelByNameの場合はサブラベルは/で区切る
const FROM_LABEL_NAME1 = 'a自動振り分け/1処理前';
const TO_LABEL_NAME1 = 'a自動振り分け/2処理後';
const GET_THREADS_MAX1 = 50;//最大数を設定
const CSV_FOLDER_ID = '198v9WpSKNoA1j6grRoQzt5x9lgfdIRgC';

// スプレッドシートが開かれたタイミングでカスタムメニューを追加
function onOpen(e) {
  SpreadsheetApp.getUi()  // UI を取得
    .createMenu('🍎追加したメニュー🍎')  // 🍎追加したメニュー🍎という名前のメニューを作成
    .addItem('受信メールの添付ファイルを抽出する', '受信メールの添付ファイルを抽出する')  // 項目名: 項目1 実行関数: function1 のメニュー項目を作成
    .addToUi();  // UI に追加
}

// 実行ユーザーの特定のフォルダにある受信メールの添付ファイルを抽出する
function 受信メールの添付ファイルを抽出する() {
  対象のシートをアクティブにする();
  メールからCSVを抽出する();
}

// 結果を実行時刻のyyyymmでシートに残すため、対象のシートをアクティブにする
function 対象のシートをアクティブにする() {
  const yyyyMM = Utilities.formatDate(new Date(), 'Asia/Tokyo', 'yyyyMM');
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  let sheet = ss.getSheetByName(yyyyMM);
  if (!sheet) {
    console.log('シートがないのでテンプレートをコピーして作成します。');
    sheet = ss.getSheetByName('テンプレート').copyTo(ss);
    sheet.setName(yyyyMM)
    sheet.getRange(2, 1, 20, 10).clearContent();
    SpreadsheetApp.setActiveSheet(sheet);
    ss.moveActiveSheet(1);
  } else {
    SpreadsheetApp.setActiveSheet(sheet);
  }
  // フィルターを解除する
  const fil1 = sheet.getFilter();
  if (fil1) {
    fil1.remove();
  }
}

メールからCSVファイルを抽出するGAS

後半部分のメールから添付ファイルをGoogleDriveのフォルダに抽出するGASです。

function メールからCSVを抽出する() {
  const fromlabel = GmailApp.getUserLabelByName(FROM_LABEL_NAME1);// ここで「Gmail に接続できません。」エラーがたまに発生する!
  const tolabel = GmailApp.getUserLabelByName(TO_LABEL_NAME1);
  const threads = fromlabel.getThreads(0, GET_THREADS_MAX1); // 読み込み数
  const myFolder = DriveApp.getFolderById(CSV_FOLDER_ID);
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();

  // 対象フォルダの全スレッドを処理する
  for (let i = 0; i < threads.length; i++) {
    let thread = threads[i];
    let messages = thread.getMessages();
    let message;
    try {
      // ひとつのスレッド
      for (let j = 0; j < messages.length; j++) { // message:null からプロパティ「length」を読み取れません。エラーあり。
        message = messages[j];
        if (!message.isUnread() || message.isInTrash()) {
          //既読メール、またはゴミ箱のメールは処理しない
          continue;
        }
        // 未読メールのみ処理する

        // メール情報取得
        let from = message.getFrom();
        let to = message.getTo();
        let date = message.getDate();
        let subject = message.getSubject();
        let body = message.getBody();
        let attachments = message.getAttachments(); //添付ファイルを取得

        if (!from.match(/sample@xxxxxxxx.jp/)) {
          //fromがsample@xxxxxxxx.jpのみ処理する
          continue;
        }

        if (subject.match(/Re:/)) {
          //件名がReのものは対象外
          continue;
        }

        // 2行目にログを追加
        sheet.insertRowBefore(2);
        sheet.getRange(2, 3).setValue(new Date());
        sheet.getRange(2, 4).setValue(date);
        sheet.getRange(2, 5).setValue(subject);

        let attachmentsCount = 0
        let hasNextError = 0;
        let csvFileError = 0;

        for (let k in attachments) {
          attachmentsCount++;
          let contents = myFolder.getFilesByName(attachments[k].getName());
          
          // 環境によってはGoogleDrive上でxlsファイルとして認識されたため、明示的に指定
          attachments[k].setContentType('text/csv');

          if (contents.hasNext()) {
            // すでに同名のファイルがあればエラー
            hasNextError = 1;
          } else if (attachments[k].getName().indexOf('.csv') == -1) {
            //csvファイルでない場合エラー
            csvFileError = 1;
          } else {
            sheet.getRange(2, attachmentsCount + 5).setValue(attachments[k].getName());
            myFolder.createFile(attachments[k]);
          }
        }

        if (attachmentsCount == 0) {
          sheet.getRange(2, 10).setValue("エラー!添付ファイル数=" + attachmentsCount);
        } else if (hasNextError == 1) {
          sheet.getRange(2, 10).setValue("エラー!添付ファイル名重複!");
        } else if (csvFileError == 1) {
          sheet.getRange(2, 10).setValue("エラー!添付ファイル拡張子!");
        } else {
          sheet.getRange(2, 10).setValue(attachmentsCount);
          sheet.getRange(2, 11).setValue('抽出しました!');
        }
      }
      // 既読 これはメール単位に行う。
      GmailApp.markMessageRead(message);
    } finally {
      // ラベリング処理 これはスレッド単位に行う。途中で予期せぬエラーが発生したときに、既読は付けずに、フォルダ移動する。
      thread.removeLabel(fromlabel);
      thread.addLabel(tolabel);
    }
  }
  SpreadsheetApp.flush();
}

実行しました

Gmailを確認すると、メールがフォルダを移動し、既読になりました。

スプレッドシートを確認すると、ログが記録されました。

GoogleDriveを確認すると、対象のフォルダにcsvファイルが保管されていました。

以上です。

GoogleAppsScriptgmail

Posted by zzz