開発記録

確定申告の自動化ツールで大量メールとAPI拒否に詰まった解決策

ノートPCにメールやPDFが自動で整理・回収されていくイメージ図

確定申告の自動化ツールが目指す全体像

個人事業主の事務作業を極限まで減らすため、メールの自動回収から仕訳データの作成までを一気通貫で行うシステムを構築しました。

収集層メール・PDFの自動回収 (IMAP)変換層為替レート換算・Stripeデータ連携判定層AIによる勘定科目の自動割り当て出力層仕訳日記帳CSV・未確認事項の書き出し
確定申告自動化ツールの構成

このシステムは、ローカル環境(C:\プロジェクト\確定申告\)に配置したバッチファイル(確定申告.bat)をダブルクリックするだけで、追加のインストールなしですべての処理が実行できるように設計しています。

具体的なフォルダ構成は以下の通りです。

  • 取込\カード明細\JCB\:クレジットカードのCSVを配置する場所
  • 請求書\YYYY-MM\:自動回収したPDFの保存先
  • 保管庫\keys.env:APIキーや認証情報を管理する環境変数ファイル
  • 設定.toml:契約中のサービスや収入源を定義する設定ファイル

この仕組みを実際に動かす中で、いくつかの致命的な壁にぶつかりました。

罠1:為替レートAPIが「403 Forbidden」で取得できない

海外サービス(AnthropicやOpenAIなど)の利用料はドル建てが多いため、外貨決済を円換算する必要があります。無料の為替レートAPI(api.frankfurter.app)をPythonの標準ライブラリ urllib で叩いたところ、403 Forbiddenエラーが発生しました。

読者
なぜブラウザでは見られるのに、Pythonからだとエラーになるのですか?
SK Forge
Pythonの既定の「User-Agent」が、APIサーバー側でセキュリティ対策のために弾かれていたことが原因です。

ヘッダーに独自のUser-Agentを指定することで、この問題を解決できます。

解決手順

  1. リクエストヘッダーに User-Agent: kaikei/1.0 などの独自の識別子を追加する。
  2. エンドポイントを api.frankfurter.dev に変更する。

Pythonで記述する場合の接続設定の抜粋です。

import urllib.request
import json

url = "https://api.frankfurter.dev/v1/2026-08-07?base=USD&symbols=JPY"
req = urllib.request.Request(
    url, 
    headers={'User-Agent': 'kaikei/1.0'}
)
# これで403エラーを回避して為替レートを取得可能

罠2:メールの取り込み処理が終わらない

当初は、メールサーバーから SINCE(特定の日付以降)の条件だけで全メールをローカルにダウンロードし、Python側でフィルタリングする設計にしていました。しかし、受信箱に何百通ものメールがある場合、処理が全く終わりません。

この問題を解決するには、サーバー側で検索を完結させてから、必要なメールだけをダウンロードするように設計を変更する必要があります。

1全メールをダウンロード (遅い)2差出人と件名でサーバー側検索 (高速)3必要な添付PDFのみを自動保存
メール取得処理の改善

メールサーバーから必要な請求メールだけを高速でフィルタリングするイメージ

解決手順

  1. IMAPの検索コマンドで、差出人ドメイン(FROM)や件名(SUBJECT)を指定する。
  2. 日本語の件名を検索する場合は、文字コード(CHARSET UTF-8)と imaplibliteral 形式を使用する。

Pythonの imaplib で日本語を含む検索を行う場合のコードの要点です。

# 日本語件名を検索するための literal 指定の例
import imaplib

mail = imaplib.IMAP4_SSL("mail.example.com")
mail.login("<ユーザー名>", "<パスワード>")
mail.select("INBOX")

# CHARSET UTF-8 を指定し、検索語を literal として渡す
mail.literal = '領収書'.encode('utf-8')
status, data = mail.search('UTF-8', 'SUBJECT')

この方法に書き換えたことで、459通あった候補メールから、必要な52件の仕訳対象メールを一瞬で絞り込み、添付されていた32件のPDFを年月別のフォルダ(例:請求書\2026-08\)に自動回収できるようになりました。

罠3:お知らせメールで帳簿が埋め尽くされる

メールの自動回収が動くようになったものの、今度はサービスからの「障害通知」や「仕様変更のお知らせ」といった不要なメールまで「請求メール」として判定されてしまいました。その結果、金額が空欄の不要な仕訳データが大量に作られてしまう問題が発生しました。

解決手順

  1. メール本文から金額が読み取れなかったものは、仕訳データ(CSV)への登録から除外する。
  2. 除外したメールは 出力\金額を読み取れなかったメール.md という別ファイルに一覧として書き出し、人間が後から確認できるようにする。

この「人間による確認用ファイルを分ける」という設計にしたことで、帳簿を汚さずに、漏れのない回収が可能になりました。

確定申告の自動化は「部分的な自作」が最も効率的

すべての処理を完全に自動化しようとすると、例外処理のコードが肥大化して開発が終わりません。「AIに判定させつつ、人間が最後に確認する」という境界線を引くことが、個人開発における最大のコツです。

今回のツール開発でも、AIエージェントを活用して効率的にコードを組み立てました。AIを開発の相棒として使う際の注意点は、次の記事にまとめています。

あわせて読みたいCursor・Windsurf・Claude Codeの課金でつまずく3つの注意点Cursor・Windsurf・Claude Codeの課金で迷っていませんか?本記事では、3大AIツールの料金プランや機能、Windows環境での注意点を比較…

まとめ

確定申告の自動化を始めるなら、まずは一番面倒な「メールやPDFの回収」から手をつけるのがおすすめです。

  1. 自分のメールボックスから、特定の差出人や件名でIMAP検索をかけるスクリプトを動かしてみましょう。
  2. 今回作成した、メールの自動回収から為替換算、仕訳CSVの作成までをまとめたツールを自力で一から実装するには、APIの仕様変更やセキュリティ対策への対応など、多くの時間と試行錯誤が必要になります。

確定申告を自動化するPythonスクリプト一式を、一から組まずに使いたいときは

詰まりどころを1つずつ潰していく時間は、どうしてもかかります。実際に作って動かしている確定申告を自動化するPythonスクリプト一式は、そのまま使える形に整えています。 新しく出したときと、記事にしていない小さな回避策は公式LINEで先に流しています。今あるものはAIクラフトに置いてあります。

よくある質問

IMAPの検索で日本語が文字化けしてうまくヒットしません。

imaplibで日本語を検索する際は、検索キーワードをUTF-8でエンコードし、サーバー側に『CHARSET UTF-8』を明示的に伝える必要があります。また、通常の引数ではなくliteralとして渡すようにしてください。

為替レートAPIで403エラーが出るのを防ぐには?

Pythonのurllibなどが送信するデフォルトのUser-Agent(Python-urllib/x.x)は、多くのAPIサーバーでアクセス拒否の対象になります。リクエストヘッダーに独自のUser-Agent文字列を設定して送信してください。

お知らせメールを誤判定して取り込んでしまいます。

メール本文から正規表現などを用いて「金額」が抽出できるかどうかを一次フィルターとして設定し、金額が読み取れなかったメールは仕訳データから除外してログファイルにのみ出力する設計が有効です。

SK Forgeのプロフィール画像
この記事を書いた人: SK Forge

AI開発にのめり込んでいる個人開発者です。ブログの全自動運営をはじめ、作業をAIに任せて時短する仕組みを作り、浮いた時間を副業に回しています。その開発記録や悪戦苦闘したところを、このブログとXでそのまま公開中。完成したツールやアプリは、AIツール専門のマーケット「AIクラフト」で販売しています。

関連記事