AX・AI活用 / 制作・開発記録

社長のメールからこっそり領収書を拾う仕組みを作った話

経理に必要な領収書や請求書を集めるため、対象のメールを自動で転送する仕組みをつくった記録。導入の背景と実装の考え方を紹介します。

この記事は2025/04/17に公開した記録です。記載の価格・製品・サービスの情報は当時のものです。最新の提供内容は事業ページでご確認ください。

こんにちは、YOSHINANIのえーちゃんです。
今回は、社長に届くメールの中から「領収書」や「請求書」などの言葉が含まれるメールだけを自動で転送する仕組みを作ったお話です。


背景

自分は会社の経理を担当しています。
経理作業には、領収書や請求書の回収は欠かせません。

ただ、チームではいろんな月額サービス(特にAI系のサブスクなど)を使っていて、その多くが個人アドレスで契約されています。
共用アドレスに届くものは確認できますが、個人アドレスに届くものは毎回「領収書きた?」と聞くしかない状況でした。

とはいえ、社長にいちいち確認するのも気が引けますし、そもそも雑務に時間を割けるわけもなく、領収書の回収漏れが発生しがち…。

「いっそ、自動で必要なメールだけ転送されればいいのに」と思ったのが、今回の仕組みを作ったきっかけです。


メールを自動で監視・転送する仕組みを作った

・Gmailを使っているので「Google Apps Script」を使って実装
・処理対象は「実行時刻の1時間前以降に届いたメール」
・GASのトリガーを1時間おきに設定することで、転送漏れがないように
・件名または本文に「領収書/請求書/receipt/invoice」のいずれかのキーワードが含まれていたら、自分のメールアドレスに自動で転送
・転送が完了したメールは、自動で既読

「おまけ」
社内ではDiscordを連絡ツールとして使っているので、
転送処理が行われたらDiscordにも通知が飛ぶようにしています


コードの紹介

以下が、今回実際に使っているGASのコードです。
SlackやNotionなど他の連携してる方は、必要に応じて「Discord通知なし」版を使ってください。

function forwardEmails() {
  const threads = GmailApp.search('newer_than:1h');
  const keywordRegex = /領収書|請求書|receipt|invoice/i;
  const discordWebhookUrl = 'discordのwebhookURLを入力';

  const now = new Date();
  const oneHourAgo = new Date(now.getTime() - 60 * 60 * 1000);

  for (const thread of threads) {
    const messages = thread.getMessages();
    const firstMessage = messages[0]; // 最初の1通だけ処理

    const subject = firstMessage.getSubject();
    const body = firstMessage.getPlainBody();
    const messageDate = firstMessage.getDate();

      if (messageDate < oneHourAgo) continue;

    if (keywordRegex.test(subject) || keywordRegex.test(body)) {
      firstMessage.forward('転送先のアドレスを入力');
      firstMessage.markRead();
      const sender = firstMessage.getFrom();
      sendDiscordNotification(subject, sender, discordWebhookUrl);
    }
  }
}

function sendDiscordNotification(subject, sender, webhookUrl) {
  const payload = {
    content: `📩 メールを転送しました\n件名: ${subject}\n送信者: ${sender}`
  };

  const options = {
    method: 'post',
    contentType: 'application/json',
    payload: JSON.stringify(payload)
  };

  UrlFetchApp.fetch(webhookUrl, options);
}


Discord通知なしバージョン

function forwardEmails() {
  const threads = GmailApp.search('newer_than:1h');
  const keywordRegex = /領収書|請求書|receipt|invoice/i;

  const now = new Date();
  const oneHourAgo = new Date(now.getTime() - 60 * 60 * 1000);

  for (const thread of threads) {
    const messages = thread.getMessages();
    const firstMessage = messages[0]; // 最初の1通だけ処理

    const subject = firstMessage.getSubject();
    const body = firstMessage.getPlainBody();
    const messageDate = firstMessage.getDate();

      if (messageDate < oneHourAgo) continue;

    if (keywordRegex.test(subject) || keywordRegex.test(body)) {
      firstMessage.forward('転送先のアドレスを入力');
      firstMessage.markRead();
    }
  }
}

トリガー設定はこちら

トリガー設定
トリガー設定

作ってみた・使ってみた感想

ちょっとしたことでも、日々の雑務で「これ面倒だな」と感じていたことが自動化されると、思った以上に気持ちがラクになるなぁと実感しました。
こういうのって、できたとき地味に嬉しいんですよね。

今後も使いながら、必要に応じて改善していけたらと思っています。

普段はコードを書く機会のない自分でも、
思っていたより簡単に組めたので、
同じような悩みを持っている方はぜひ試してみてもらえると嬉しいです。


初出:YOSHINANI公式note

← AX・AI活用コラムの一覧へ

検討を進めるために

お役立ちガイド一覧 →

LET’S MAKE IT

まだ決まっていないことも、
一緒に整理します。

実現したいこと、希望時期、ご予算を分かる範囲でお聞かせください。

LINE開発・LEGO制作の資料をご請求いただけます。