narita-lab’s blog

成田ラボ 〜テクノロジーと雑学の観察日記〜

AIと共同で“詐欺メールを潰すプログラム”を設計してみる Day3 本文取得編

前回のDay2では、PythonからYahooメールへIMAP接続し、受信箱のメール一覧を取得するところまで成功した。

途中、

「ログイン情報は合ってるのに接続できない」

という問題にぶつかりつつも、原因はYahoo側の“海外アクセス遮断”設定だったというオチまで含めて、かなり“開発してる感”のある回だったと思う。

そして今回のDay3。

次はいよいよ本文解析…と言いたいところなのだが、その前に問題があった。

コンソール表示、見づらい。

件名や送信者を print() でズラーっと流しているだけなので、メールが増えてくると普通に管理しづらい。

しかも今後やりたい事は、

  • HTMLメール解析
  • 本文取得
  • URL抽出
  • 正規化処理
  • 「楽 天 カ ー ド」対策
  • スコア判定

など、“中身を見ながら調整する作業”が中心になる。

となると、先にGUIを作っておいた方が絶対楽だ。

という訳で今回は、Tkinterを使ってGUIを導入し、

  • メール一覧表示
  • ログ表示
  • 本文表示

この辺まで実装してみることにした。

ついでに、メール界に潜む“文字コードの闇”とも早速遭遇することになる。

 

TkinterでGUI化することにした

Day2までは、受信したメール情報をコンソールに表示していた。

これはこれで、接続テストとしては十分だった。

実際、

  • Yahooメールへ接続
  • ログイン
  • INBOXを選択
  • 最新メールを取得
  • 件名と送信者を表示

という目的は達成できていた。

ただ、この先の開発を考えると、コンソールだけでは厳しい。

特にメール本文を扱い始めると、表示される情報量が一気に増える。

本文、HTML、URL、エラー、ログ。
それらが全部コンソールに流れていくと、かなり見づらい。

そこで今回は、Tkinterを使って簡単なGUIを作ることにした。

最初に作った画面はかなりシンプルだ。

  • メールアドレス入力欄
  • パスワード入力欄
  • 接続して受信ボタン
  • 最新メール一覧
  • 本文表示欄
  • ログ欄

まずはこれで十分。

凝ったデザインよりも、今は開発しやすさ優先である。

メール一覧をGUIで見られるだけでも、コンソール表示よりかなり分かりやすくなった。

 

GUIでメール一覧を表示する

今回のGUIでは、まず最新メールを一覧表示できるようにした。

表示する内容はシンプルに、

  • 件名
  • 送信者

この2つだけ。

メールソフトとして見れば最低限だが、今回の目的は“詐欺メール対策ツールの開発”なので、最初はこれで十分だ。

重要なのは、メールを見ながら次の処理を考えられること。

例えば、一覧を見るだけでも、

「この件名、明らかに怪しいな」

とか、

「送信者名はそれっぽいけど、ドメインが胡散臭いな」

みたいな情報が見えてくる。

コンソールにズラーっと流れていた時より、かなり把握しやすい。

さらに今回は、本文表示のためにIMAP接続を維持するようにした。

Day2のコードでは、受信後にすぐログアウトしていた。

しかし、本文を後から表示するには、メールを選択したタイミングでもう一度サーバーから情報を取る必要がある。

そのため今回は、

  • 接続する
  • メール一覧を取得する
  • 接続は維持する
  • 選択したメールの本文を取得する
  • アプリ終了時にログアウトする

という流れに変更した。

この辺りで、ただの接続テストから少しずつ“ツール”っぽくなってきた。

 

本文取得にも挑戦してみた

GUI化したついでに、今回は本文取得にも挑戦してみた。

一覧でメールを選択して、

「本文表示」

ボタンを押すと、そのメール本文が表示される仕組みである。

さらに、メールをダブルクリックしても本文を表示できるようにした。

この辺りは地味だが、実際に使うとなるとかなり便利だ。

ただ、メール本文の取得は思ったより単純ではない。

メールには、

  • text/plain
  • text/html
  • multipart
  • 添付ファイル

など、いろいろな形式が混ざっている。

なので今回は、

  • text/plain があれば優先して表示
  • なければ text/html を表示
  • 添付ファイルは無視

というシンプルな処理にした。

まだHTMLタグの除去まではしていない。

つまり、HTMLメールの場合はタグ付きで表示されることもある。

ただ、今回の目的はあくまで、

「本文を取得できるか」

の確認だ。

その意味では、本文表示まで成功した時点でDay3としてはかなり進んだと思う。

 

早速“メール界の闇”に触れる

本文取得まで進めたことで、いよいよメール処理の面倒な部分が見えてきた。

まず出てきたのが、件名の表示問題である。

一部のメールで、件名が普通の日本語ではなく、

 
=?iso-2022-jp?B?...
 

のような形式で表示されてしまった。

これは文字化けというより、メールの件名がMIMEエンコードされた状態のまま残っているようなものだ。

普通のメールならある程度デコードできるのだが、迷惑メールや詐欺メールはヘッダの作りが雑なこともある。

その結果、こちらの処理でうまく日本語に戻せないケースが出てきた。

正直、今回の目的からすれば大きな問題ではない。

なぜなら、そういうメールはだいたい消したい側のメールだからだ。

ただ、

「メール処理って思ったより面倒なんだな」

というのは、この段階でかなり実感した。

さらに今後はHTMLメールも相手にすることになる。

詐欺メールの多くはHTML形式なので、本文を取っただけではタグだらけになる可能性が高い。

つまり、Day3の時点で早くも、

  • MIMEヘッダ
  • 文字コード
  • HTMLメール
  • multipart

という、メール処理の面倒な要素が顔を出してきた。

やはりメールは魔境である。

 

それでもGUI化はかなり正解だった

細かい問題は出てきたが、それでも今回GUI化したのは正解だったと思う。

コンソール表示のままだと、件名、送信者、本文、ログが全部同じ場所に流れていく。

それに対してGUIでは、

  • メール一覧
  • 本文表示欄
  • ログ欄

を分けて確認できる。

これだけで、開発中の見通しがかなり良くなった。

特に今後やりたい正規化処理では、

「元の本文」
「正規化後の本文」
「検出されたキーワード」

を見比べる必要がある。

例えば、

 
楽 天 カ ー ド
 

を、

 
楽天カード
 

として認識できているか確認するには、GUI上で結果を見られた方が圧倒的に楽だ。

さらに、本文表示までできるようになったことで、次回以降の開発がかなり進めやすくなった。

ここからようやく、

“メールを読むツール”

から、

“迷惑メールを判定するツール”

へ進めそうである。

 

Day3時点でできたこと

Day3でできたことを整理すると、かなり進んだ。

まず、Tkinterを使ってGUIを導入した。

これにより、コンソールに流していたメール情報を、画面上で一覧表示できるようになった。

次に、IMAP接続を維持する形に変更した。

Day2ではメール一覧を取ったらログアウトしていたが、今回は本文取得のために接続を維持するようにした。

さらに、選択したメールの本文表示にも対応した。

本文表示ボタンを押すか、メール一覧をダブルクリックすると、本文表示欄に内容が出る。

ここまで来ると、単なる実験コードではなく、かなり“ツールの原型”になってきた。

もちろん、まだ課題はある。

  • 件名の一部がMIMEエンコードされたまま表示される
  • HTMLメールはタグ付きで表示される
  • 本文の整形はまだしていない
  • 怪しいメール判定もまだない

ただ、Day3の目的としては十分だ。

メール一覧を見られる。
本文も見られる。
ログも確認できる。

これで、次の開発に進む土台は整った。

 

次回やること

Day3では、GUI化と本文取得まで到達できた。

次にやるべきことは、いよいよ本文の整形である。

現時点では、本文をそのまま表示しているだけなので、HTMLメールの場合はタグが混ざる。

これだと人間が読むにも微妙だし、プログラムで判定するにも扱いづらい。

なので次回は、

  • HTMLタグの除去
  • 本文の改行整理
  • 全角半角の正規化
  • 空白除去
  • URL抽出

この辺りに進みたい。

特に重要なのが、Day1からずっと言っている、

 
楽 天 カ ー ド
 

みたいな表記ゆれ対策だ。

この手のフィルタ回避表現を、

 
楽天カード
 

として認識できるようにしないと、迷惑メール判定には使いづらい。

つまり次回は、

“本文を表示するツール”

から、

“本文を解析するツール”

へ進む回になる。

ここまで来れば、いよいよ詐欺メール判定の土台ができてくるはずだ。