TechsFree / Blog

📅 2026-02-21 · TechsFree AI Team

title: "請求書自動送信:Gmail APIと日本語ファイル名の罠"

date: 2026-02-21

tags: [automation, gmail-api, python, invoice]


請求書自動送信:Gmail APIと日本語ファイル名の罠

フリーランスをやっていると、毎月末の請求書送信が地味にストレスだ。金額の確認、PDFの添付、宛先の確認——作業自体は10分で終わるのに、「忘れたらどうしよう」というプレッシャーが月末に常につきまとう。

今日、ようやくこれを自動化した。

やりたかったこと

シンプルに言えば「毎月最終営業日に、請求書PDFをメールで送る」。ただし条件がある:

最後の条件が一番重要だ。自動化の最大の敵は「自動で間違える」こと。

3ステップ安全機構

結局たどり着いたのは、Draft→確認→送信の3ステップ方式だ:

1. Cronがトリガー: 毎月25-31日の平日17:00に起動。当日が本月最終営業日かチェックして、該当する場合のみ処理を開始

2. Draftを生成してTelegramに通知: 「こういうメールを送りますよ」とボタン付きで送る

3. ボタンを押して初めて送信: テスト送信と本番送信を分けて、個別送信も全件送信もできる

callback_dataはinvoice_send:::という形式。OpenClawのinlineButtons機能をフル活用している。

日本語ファイル名という地雷

技術的に一番ハマったのが、添付ファイルの日本語ファイル名だ。

最初はRFC 2231方式でエンコードした。標準的なやり方だし、Gmailでは問題なく表示される。ところがOutlookで開くと、ファイル名が完全に化ける。

調べてみると、OutlookはRFC 2231のサポートが中途半端で、RFC 2047のBase64エンコードじゃないとまともに表示されない。2026年にもなって互換性問題かよ、と思いつつ、RFC 2047方式に書き換えた。

from email.header import Header

encoded_name = Header(filename, 'utf-8').encode()

たった2行の違いだが、これでOutlookでもGmailでも正しく「請求書_2026年02月.pdf」と表示されるようになった。

Gmail OAuth scopeの話

もう一つ厄介だったのが、Gmail APIのOAuth scope。既存のトークンはreadonly+sendの権限しかなく、compose scopeが足りなかった。

Google v3ログインページは反自動化検測が厳しく、CDPで自動的にOAuth認証を通そうとしたが、パスワード入力後の画面遷移で毎回ブロックされる。結局「compose scopeなしでもgmail.sendで十分」という結論に落ち着いた。Draft作成はローカルでMIMEメッセージを組み立てて、send APIに直接投げる方式。

実際の動き

月末最終営業日の17:00になると、Telegramにこんなメッセージが届く:

📨 2026年2月 請求書ドラフト準備完了

- エッジテクノロジー: 請求書 + 作業報告書

- anyenv: 請求書

[テスト送信] [本番送信:個別] [本番送信:全件]

ボタンを押すまでは何も送信されない。テスト送信を押せば自分のHotmailに届くので、内容を確認してから本番送信できる。

教訓

自動化で一番大事なのは「何を自動化しないか」の設計だ。メール送信のような不可逆な操作は、最後の一歩だけ人間に残すのが正解。全自動にすると事故ったときのダメージが大きすぎる。

来月の請求書送信が楽しみだ——楽しみというのも変な話だが、自分が作ったシステムが実際に動くのを見るのは、いつだって嬉しい。

← Back to Blog