見出し画像

[GAS] Gmailのメール本文をPDFとして保存する2 : GASを実装する

はじめに

前回は、GASでGmailで受信したメールをPDFとして保存するスクリプトを実装するための事前準備についてお伝えしました。

今回は、GASの実装についてお伝えします。

実装

全体の処理は、下記です。

function GmailToPDF() {
  // ラベルが「領収書」でかつ、「PDF済」ではないものを検索
  const query = 'label:領収書 -label:PDF済';
  const threads = GmailApp.search(query);

  const label = GmailApp.getUserLabelByName('PDF済');

  for (const thread of threads) {
    const messages = thread.getMessages();
    for (const message of messages) {
      const date = message.getDate();
      const subject = message.getSubject();
      const body = message.getPlainBody();
      const toAdd = message.getTo();
      const fromAdd = message.getFrom();

      // メールの内容をGoogleドキュメントに出力する
      const [copyFile, document] = createGoogleDocument_(date, subject, body, toAdd, fromAdd);

      // GoogleドキュメントをPDFに変換し、年、月のフォルダに保存する
      const docTitle = `${Utilities.formatDate(date, 'JST', 'yyyyMMdd')}_${fromAdd}`;
      if (createPDF_(COPY_TO_FOLDER_ID, document, docTitle, date) === null) {
        console.log(`フォルダID:${COPY_TO_FOLDER_ID} メール受信日:${Utilities.formatDate(date, 'JST', 'yyyy/MM/dd')} pdf保存できません。`)
      }

      // Googleドキュメントを削除
      deleteDoc_(copyFile);

    }

    thread.addLabel(label);
  }
}

function createGoogleDocument_(date, subject, body, toAdd, fromAdd) {
  // Googleドキュメントのテンプレートをコピー
  const copyFile = DriveApp.getFileById(TEMPLATE_DOC_ID).makeCopy(DOC_FOLDER_ID);
  const document = DocumentApp.openById(copyFile.getId());

  const docBody = document.getBody();

  // Googleドキュメントの文字列置き換え
  docBody.replaceText('件名', subject).
    replaceText('送信元', fromAdd).
    replaceText('受取人', toAdd).
    replaceText('本文', body).
    replaceText('日付', Utilities.formatDate(date, 'JST', 'yyyy/MM/dd HH:mm'));

  document.saveAndClose();

  return [copyFile, document];
}

function createPDF_(folderId, document, docTitle, date) {
  const blob = document.getAs('application/pdf');
  blob.setName(docTitle + '.pdf');

  const folder = DriveApp.getFolderById(folderId);

  // 年フォルダ取得
  const yearFolderName = Utilities.formatDate(date, 'JST', 'yyyy');
  const yFolder = findFolder_(folder, yearFolderName);
  if (yFolder === null) {
    console.log(`NoFound. folderName:${yearFolderName}`)
    return null;
  }

  // 月フォルダ取得
  const monthFolderName = Utilities.formatDate(date, 'JST', 'yyyyMM');
  const mFolder = findFolder_(yFolder, monthFolderName);
  if (mFolder === null) {
    console.log(`NoFound. folderName:${monthFolderName}`)
    return null;
  }

  mFolder.createFile(blob);
}

function findFolder_(parentFolder, searchFolderName) {
  const folders = parentFolder.getFolders();
  while (folders.hasNext()) {
    const folder = folders.next();
    const folderName = folder.getName();

    if (folderName === searchFolderName) {
      return folder;
    }
  }
  return null;
}

function deleteDoc_(copyFile) {
  //コピーしたファイルを削除
  const file = DriveApp.getFileById(copyFile.getId());
  file.setTrashed(true);
}

順番に処理の内容を説明します。

1.ラベル指定でスレッド検索する

今回は、ラベルに「領収書」が設定されている、かつラベルに「PDF済」がついていないメールを取得しています。

const query = 'label:領収書 -label:PDF済';
const threads = GmailApp.search(query);

指定できる検索クエリは、下記サイトを参照してください。

2.スレッドからメッセージを取得する

Gmailには、スレッドメッセージという概念があります。

まず、一通ごとに送る「メール」を、Gmailではメッセージと言います。Gmailでは、メッセージに対する返信など、メッセージの一連のやり取りが自動でまとめられます。この、一連のメッセージをまとめたものをスレッドと言います。つまり、スレッドは複数のメッセージの集まりになります。

詳解!GoogleAppsScript完全入門

一通ごとに送る「メール」であるメッセージを取得するには、下記のように実装しています。

for (const thread of threads) {
    const messages = thread.getMessages();
	  for (const message of messages) {

3.メールの内容をGoogleドキュメントに出力する

メールより、下記の情報を取得して、前回作成したGoogleドキュメントのテンプレートに対して、出力していきます。

  • メッセージの日時

  • メッセージの件名

  • メッセージの本文のプレーンテキスト

  • メッセージの送信先

  • メッセージの送信者

// メールの内容をGoogleドキュメントに出力する
const [copyFile, document] = createGoogleDocument_(date, subject, body, toAdd, fromAdd);

createGoogleDocument_関数の実装は、下記になります。

function createGoogleDocument_(date, subject, body, toAdd, fromAdd) {
  // Googleドキュメントのテンプレートをコピー
  const copyFile = DriveApp.getFileById(TEMPLATE_DOC_ID).makeCopy(DOC_FOLDER_ID);
  const document = DocumentApp.openById(copyFile.getId());

  const docBody = document.getBody();

  // Googleドキュメントの文字列置き換え
  docBody.replaceText('件名', subject).
    replaceText('送信元', fromAdd).
    replaceText('受取人', toAdd).
    replaceText('本文', body).
    replaceText('日付', Utilities.formatDate(date, 'JST', 'yyyy/MM/dd HH:mm'));

  document.saveAndClose();

  return [copyFile, document];
}

createGoogleDocument_関数では、下記の処理を行っています。

  • Googleドキュメントのテンプレートファイルを、コピー

  • コピーしたGoogleドキュメント内の文字列を検索し、メッセージから取得した各種情報で置き換え

4.作成したGoogleドキュメントをPDFに変換して保存

保存するPDFのファイル名を、「メールの受信日_送信元.pdf」とするため、ファイル名を作成し、PDFファイルに変換をしています。

      // GoogleドキュメントをPDFに変換し、年、月のフォルダに保存する
      const docTitle = `${Utilities.formatDate(date, 'JST', 'yyyyMMdd')}_${fromAdd}`;
      if (createPDF_(COPY_TO_FOLDER_ID, document, docTitle, date) === null) {
        console.log(`フォルダID:${COPY_TO_FOLDER_ID} メール受信日:${Utilities.formatDate(date, 'JST', 'yyyy/MM/dd')} pdf保存できません。`)
      }

createPDF_関数の実装は、下記になります。

function createPDF_(folderId, document, docTitle, date) {
  const blob = document.getAs('application/pdf');
  blob.setName(docTitle + '.pdf');

  const folder = DriveApp.getFolderById(folderId);

  // 年フォルダ取得
  const yearFolderName = Utilities.formatDate(date, 'JST', 'yyyy');
  const yFolder = findFolder_(folder, yearFolderName);
  if (yFolder === null) {
    console.log(`NoFound. folderName:${yearFolderName}`)
    return null;
  }

  // 月フォルダ取得
  const monthFolderName = Utilities.formatDate(date, 'JST', 'yyyyMM');
  const mFolder = findFolder_(yFolder, monthFolderName);
  if (mFolder === null) {
    console.log(`NoFound. folderName:${monthFolderName}`)
    return null;
  }

  mFolder.createFile(blob);
}

function findFolder_(parentFolder, searchFolderName) {
  const folders = parentFolder.getFolders();
  while (folders.hasNext()) {
    const folder = folders.next();
    const folderName = folder.getName();

    if (folderName === searchFolderName) {
      return folder;
    }
  }
  return null;
}

createPDF_関数では、下記の処理を行っています。

  • 作成したGoogleドキュメントを、”PDF”タイプのBlobクラスを取得し、名前を設定

  • 保存先のフォルダを取得
    (今回は、年→月というフォルダ構成なので、その順番で探しています。)

  • 指定フォルダに、ファイルを保存

5.作成したGoogleドキュメントを削除

PDFに変換したGoogleドキュメントは不要なので、ファイルを削除します。

deleteDoc_(copyFile);

6.メールにラベルを設定

1度PDFに変換したメールを何度も処理しないよう、「PDF済」というラベルを設定します。

const label = GmailApp.getUserLabelByName('PDF済');

トリガー設定

自動でスクリプトを実行させるたえに、トリガーの設定を行います。
スクリプトエディタの左にある「トリガー」をクリックします。

画面右下の「トリガーを追加」をクリックします。

トリガー設定画面にて、実行したい頻度に合わせて設定を行います。
今回は、毎月1日、午前0~1時に実行と設定しました。

以上で、設定完了です。

まとめ

今回は、GASでGmailで受信したメールをPDFとして保存するスクリプトを実装するについて、お伝えしました。

今回のツールで、GmailをPDFに変換したファイルは、下記のようになります。

この記事が気に入ったらサポートをしてみませんか?