Gmail

【GAS】Gmailを既読にする メール添付の請求書PDFを保存してチャットに通知⑪

前回のおさらい

前回はメールやPDFから読み取った情報をスプレッドシートに転記しました。

GASでスプレッドシートをひらいて、シートを指定して、範囲(セル)を指定して請求月、税抜請求額、税込請求額を転記しました。


メールやPDFをから読み取った情報をスプレッドシートに転記するためにreplaceメソッドを使って修正しました。

const date = invoiceDate.replace('分', '')
const taxNotIncludedInt = taxNotIncluded.replace('税抜請求額 ', '').replace('円', '')
const taxIncludedInt = taxIncluded.replace('税込請求額 ', '').replace('円', '')
console.log(date, taxNotIncludedInt, taxIncludedInt)


スプレッドシート→シート→範囲(セル)という流れでオブジェクトをつくりました。

  const spreadSheetApp = SpreadsheetApp // スプレッドシートアプリ
  const spreadSheet = spreadSheetApp.openById('スプレッドシートIDが入ります') // スプレッドシート
  const sheet = spreadSheet.getSheetByName('請求額') // シート
  const row = sheet.getLastRow() + 1 // セルの行を指定
  const dateRange = sheet.getRange(row, 1) // 日付を記入するセルを指定
  const notIncludedRange = sheet.getRange(row, 2) // 税抜請求額を記入するセルを指定
  const includedRange = sheet.getRange(row, 3) // 税込請求額を記入するセルを指定


範囲(セル)に情報を転記しました。

// 日付を記入する
dateRange.setValue(date)

// 税抜請求額を記入する
notIncludedRange.setValue(taxNotIncludedInt)

// 税込請求額を記入する
includedRange.setValue(taxIncludedInt)


今回は請求書メールをGoogle Apps Scriptから既読にします。

請求書メールの条件のひとつに「未読」があるからです。

赤字が検索条件

const searchedMail = gmail.search('from:株式会社 インボイス送信元 subject: 【請求書】送付のご案内 is:unread')


もし「未読」のままですとプログラムを実行するたびにチャットツールに通知がとんだり、スプレッドシートへの転記が発生します。

ですので既読にするんです。

メールを既読にする

searchGmail関数全体

const searchGmail = () => {
  const gmail = GmailApp
  const searchedMail = gmail.search('from:株式会社 インボイス送信元 subject: 【請求書】送付のご案内 is:unread')
  const messages = searchedMail.map(thread => {
    return thread.getMessages()
  })
  const message = messages[0][0]

  // 本文から税抜請求額と税込請求額を取得
  const messageBody = message.getPlainBody()
  const taxNotIncluded = messageBody.match(/税抜請求額.*$/m)[0]
  const taxIncluded = messageBody.match(/税込請求額.*$/m)[0]

  // 添付ファイルの取得とドライブへの保存
  const attachments = message.getAttachments()
  const drive = DriveApp
  const folder = drive.getFolderById('フォルダIDが入ります')
  const invoiceFile = folder.createFile(attachments[0])
  
  // チャット通知用メッセージの材料を集める
  const fromName = message.getFrom()
  const companyName = fromName.match(/"([^"]*)"/)[1]
  const invoiceUrl = invoiceFile.getDownloadUrl()
  
  // PDFからOCRでテキストを取り出す
  const document = Drive.Files.copy({ title: 'テスト' }, invoiceFile.getId(), { ocr: true })
  const documentApp = DocumentApp
  const documentFile = documentApp.openById(document.id)
  const documentBody = documentFile.getBody()
  const text = documentBody.getText()
  const invoiceDate = text.match(/(\d{4}年\d{1,2}月分)/)[1]
  invoiceFile.setName(`${invoiceDate} ${companyName} 請求書`)

  // 通知用のメッセージをつくる ※位置を上から移動
  const chatMessage = `${companyName}の${invoiceDate}請求書が届きました。\n${taxNotIncluded} ${taxIncluded}\n以下のURLからダウンロードしてください。\n${invoiceUrl}`
  
  // 不要なGoogleドキュメントファイルを削除する
  const removingFile = drive.getFileById(document.id)
  removingFile.setTrashed(true)

  sendChatwork(chatMessage)
  sendSlack(chatMessage)

  // スプレッドシートに転記する
  insertBillingAcount(invoiceDate, taxNotIncluded, taxIncluded)
}


メールを既読にするにはmarkReadメソッドを使います。スレッドまたはメッセージオブジェクトのメソッドです。

今回はメッセージオブジェクトに適用します。


コードの7行目にメッセージオブジェクトがありますので、

const message = messages[0][0]


この行の下に書きます。

const message = messages[0][0]
message.markRead()

markReadメソッド ー メッセージを既読にするメソッド

構文:メッセージオブジェクト.markRead()

戻り値:メッセージオブジェクト

参照)Google Apps Scriptのマニュアル メッセージクラス


実行すると既読になります。

本当に既読になったのか確かめるためにもう一度実行してみます。既読になっていればsearchメソッドで検索ができず、エラーが発生するはずです。

実行結果


成功ですね、と言いたいところですが、毎度プログラムでエラーが起きて強制終了すると困ってしまいます。たとえば、このプログラムをGASのトリガー機能を使って毎日自動実行すると30日のうちの29日はエラーが起きて強制終了することになります。ほぼ地獄です。


なので、検索条件にひっかかるメールがなければ以降の処理をしないようにしてしまいましょう。

検索条件にかかるメールがなければ処理を抜ける

3行目のコードの下にこのように書きます。

const searchedMail = gmail.search('from:株式会社 インボイス送信元 subject: 【請求書】送付のご案内 is:unread')
if (searchedMail.length === 0) return // 追加したコード


これでもう一度実行してみましょう。

実行結果


さっきはエラーが出て強制終了しましたが、今回はエラーではなくログに何も出力されていません。

if文の意味

if (searchedMail.length === 0) return

このコードはsearchメソッドの返り値の入った変数searchedMail(配列)に入っている要素が0だったときにreturnで処理を抜けるという意味です。

searchedMail変数に入っている要素が0というのは、searchメソッドで何も取得できなかった、ということです。


さて、ここで考えたいのが、他にもエラーになるような処理はありませんか?ということです。

他にもエラーになりそうな処理があるのでは?

実際のところ、ここまで書いてきたコードはだいぶ都合の良い条件のもとで成立しています。

つまり、

  • 検索条件に合致するメールがある ← これはif文で解決しました
  • メールの本文に税抜請求額、税込請求額が記載されている
  • メールには添付ファイルがある
  • Fromの名称は会社名である
  • 請求書PDFには請求月が記載されている
  • slackAPI、chatworkAPIへのリクエストはつねに通る

といったような条件のもとで成立しているんですね。

クレーマー
クレーマー

そんなに都合いいわけないでしょ!

訴えてやる!


その通り。そんなに都合がいいわけがありません。

ですので、それぞれどんな例外が発生するのかを考えて、回避する処理を書いたほうがいいんですよ。


が、それはGASとは別の話になってしまうのでここでは書きません。頭の片隅に入れておいていただくといいです。


次回はGoogle Apps Scriptのトリガー機能を利用して、このプログラムが一日一回実行されるようにします。


来週もまた見てくれよな!?

Copied title and URL