確定申告の自動化ツールで大量メールとAPI拒否に詰まった解決策
確定申告の自動化ツールが目指す全体像
個人事業主の事務作業を極限まで減らすため、メールの自動回収から仕訳データの作成までを一気通貫で行うシステムを構築しました。
このシステムは、ローカル環境(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エラーが発生しました。


ヘッダーに独自のUser-Agentを指定することで、この問題を解決できます。
解決手順
- リクエストヘッダーに
User-Agent: kaikei/1.0などの独自の識別子を追加する。 - エンドポイントを
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側でフィルタリングする設計にしていました。しかし、受信箱に何百通ものメールがある場合、処理が全く終わりません。
この問題を解決するには、サーバー側で検索を完結させてから、必要なメールだけをダウンロードするように設計を変更する必要があります。

解決手順
- IMAPの検索コマンドで、差出人ドメイン(FROM)や件名(SUBJECT)を指定する。
- 日本語の件名を検索する場合は、文字コード(CHARSET UTF-8)と
imaplibのliteral形式を使用する。
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:お知らせメールで帳簿が埋め尽くされる
メールの自動回収が動くようになったものの、今度はサービスからの「障害通知」や「仕様変更のお知らせ」といった不要なメールまで「請求メール」として判定されてしまいました。その結果、金額が空欄の不要な仕訳データが大量に作られてしまう問題が発生しました。
解決手順
- メール本文から金額が読み取れなかったものは、仕訳データ(CSV)への登録から除外する。
- 除外したメールは
出力\金額を読み取れなかったメール.mdという別ファイルに一覧として書き出し、人間が後から確認できるようにする。
この「人間による確認用ファイルを分ける」という設計にしたことで、帳簿を汚さずに、漏れのない回収が可能になりました。
確定申告の自動化は「部分的な自作」が最も効率的
すべての処理を完全に自動化しようとすると、例外処理のコードが肥大化して開発が終わりません。「AIに判定させつつ、人間が最後に確認する」という境界線を引くことが、個人開発における最大のコツです。
今回のツール開発でも、AIエージェントを活用して効率的にコードを組み立てました。AIを開発の相棒として使う際の注意点は、次の記事にまとめています。
あわせて読みたいCursor・Windsurf・Claude Codeの課金でつまずく3つの注意点Cursor・Windsurf・Claude Codeの課金で迷っていませんか?本記事では、3大AIツールの料金プランや機能、Windows環境での注意点を比較…
まとめ
確定申告の自動化を始めるなら、まずは一番面倒な「メールやPDFの回収」から手をつけるのがおすすめです。
- 自分のメールボックスから、特定の差出人や件名でIMAP検索をかけるスクリプトを動かしてみましょう。
- 今回作成した、メールの自動回収から為替換算、仕訳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文字列を設定して送信してください。
お知らせメールを誤判定して取り込んでしまいます。
メール本文から正規表現などを用いて「金額」が抽出できるかどうかを一次フィルターとして設定し、金額が読み取れなかったメールは仕訳データから除外してログファイルにのみ出力する設計が有効です。
関連記事
動画のマスキングを自動化するツール開発で、Windowsで詰まった3つの罠
動画のマスキング処理を自動化するローカルAIツールを開発する中で、Windows環境特有の仕様により発生した3つのエラーと解決策を解説。PythonやFFmpeg、Streamlitの連携でつまずきやすいポイントを実体験から紹介します。
WiMAX L13のWi-Fiが切れる問題を解決し、ワンタップで再起動するツール
WiMAX L13の通信速度低下やDNSの詰まりをワンタップで解消するPowerShellツールを開発。DNS変更時のWi-Fi切断や、管理画面のログイン自動化など、開発中に直面した3つの技術的な壁と解決策を解説します。
外出先のスマホから自宅PCの作業を続ける方法。30秒で切れる問題も解決
iPhoneとPCの連携を極め、外出先から自宅PCのAI開発環境を操作するSSH接続手順を解説。Tailscaleとtmuxを組み合わせ、接続切れを防ぎながら快適にターミナルを操作する設定方法を公開します。