【極限の自動化】画像メールを「読めるテキスト」へ。Outlook VBA × OCR 連携の設計思想
「マクロの記録」から一歩踏み出し、自分だけの自動化ツールを作りたい。そう願うあなたへ。
こんにちは。今日は、Outlook VBAの領域における「中級者への登竜門」とも言える、非常にエキサイティングなテーマについてお話ししましょう。
テーマは「添付ファイルが画像のみの場合、OCR(光学文字認識)を実行して、その内容をメール本文に自動追記する」という高度なワークフローです。
「画像の中に重要な情報があるのに、検索もできないし、本文も空っぽ……」
そんな、実務でよくある「情報の断絶」を、コードの力で解決する設計図を一緒に描いていきましょう。
1. アーキテクチャの設計思想:VBAは「司令塔」であれ
まず、最初に伝えておきたい大切な考え方があります。それは、「VBAに重い処理をさせすぎない」ということです。
OCR(画像から文字を読み取る処理)は、計算リソースを大量に消費する重いタスクです。VBA自体には高度な画像解析エンジンは備わっていません。そこで、私たちは「オーケストレーター(指揮者)」としてのVBAを設計します。
本フローの全体像
1. 監視(Event): `NewMailEx` イベントで、新しいメールの到着を検知。
2. 判定(Logic): 添付ファイルが「画像のみ」かどうかを厳密に判定。
3. 委譲(Delegation): 画像を一時保存し、外部のOCRエンジン(Windows APIやPython、Web APIなど)へ処理を依頼。
4. 統合(Integration): 返ってきたテキストを、メールの `HTMLBody` に書き戻す。
このように、「判断はVBA」「実行は外部」と役割を分けることで、Outlookの動作を重くすることなく、堅牢なシステムを構築できるのです。
2. 実装の核心:コード・レシピ
それでは、具体的な実装を見ていきましょう。今回は、最も拡張性が高い「外部コマンド(またはAPI)を呼び出す」という構造を前提としたコード例を紹介します。
準備するもの
- OutlookのVBAエディタ(Alt + F11)
- (概念として)OCR処理を行う外部プログラム(ここでは関数として抽象化します)
' --- Outlook フォーム クラス (ThisOutlookSession) に記述 ---
Option Explicit
''' <summary>
''' 新しいメールを受信した際に自動的に実行されるイベント
''' </summary>
Private Sub Application_NewMailEx(ByVal EntryIDCollection As String)
Dim entryID As Variant
Dim objItem As Object
Dim mailItem As Outlook.MailItem
' NewMailExは複数のEntryIDをカンマ区切りで返すことがあるため、分割して処理
For Each entryID In Split(EntryIDCollection, ",")
On Error Resume Next
Set objItem = Application.GetNamespace("MAPI").GetItemFromID(entryID)
On Error GoTo 0
' 受信したアイテムがメールであることを確認
If Not objItem Is Nothing Then
If TypeOf objItem Is Outlook.MailItem Then
Set mailItem = objItem
' メインの自動化ロジックを呼び出し
ProcessImageMail mailItem
End If
End If
Next entryID
End Sub
''' <summary>
''' 画像のみの添付ファイルを持つメールを解析し、本文に追記する
''' </summary>
Private Sub ProcessImageMail(ByRef mail As Outlook.MailItem)
Dim att As Outlook.Attachment
Dim imgCount As Integer
Dim totalAttCount As Integer
Dim tempPath As String
Dim extractedText As String
Dim folderPath As String
totalAttCount = mail.Attachments.Count
imgCount = 0
' 1. 添付ファイルが「画像のみ」かどうかをチェック
' ※ここに「画像のみ」の判定ロジックを入れる
For Each att In mail.Attachments
If IsImageExtension(att.FileName) Then
imgCount = imgCount + 1
End If
Next att
' 「添付ファイルがあり」かつ「すべてが画像」の場合のみ実行
If totalAttCount > 0 And imgCount = totalAttCount Then
' 一時保存フォルダの準備
folderPath = Environ("TEMP") & "\OutlookOCR\"
If Dir(folderPath, vbDirectory) = "" Then MkDir folderPath
' 2. 画像をローカルに保存
For Each att In mail.Attachments
tempPath = folderPath & att.FileName
att.SaveAsFile tempPath
' 3. OCR処理の呼び出し(外部エンジンへ委譲)
' ここでは擬似的な関数として実装
extractedText = CallExternalOCR(tempPath)
' 4. 本文への追記
' HTML形式を維持するため、HTMLBodyを操作するのがプロの作法
If extractedText <> "" Then
mail.HTMLBody = "<div style='background-color:#f0f0f0; padding:10px; border:1px solid #ccc;'>" & _
"<strong>【OCR解析結果】</strong><br>" & _
Replace(extractedText, vbCrLf, "<br>") & _
"</div><br>" & mail.HTMLBody
' 変更を保存
mail.Save
End If
' 後片付け(一時ファイルの削除)
Kill tempPath
Next att
End If
End Sub
''' <summary>
''' 拡張子が画像かどうかを判定するヘルパー関数
''' </summary>
Private Function IsImageExtension(ByVal fileName As String) As Boolean
Dim ext As String
ext = LCase(Right(fileName, Len(fileName) - InStrRev(fileName, ".")))
Select Case ext
Case "jpg", "jpeg", "png", "bmp", "gif"
IsImageExtension = True
Case Else
IsImageExtension = False
End Select
End Function
''' <summary>
''' 外部OCRエンジンを呼び出す関数(設計の肝)
''' </summary>
Private Function CallExternalOCR(ByVal filePath As String) As String
' 【エンジニアの知恵】
' 実際にはここで Shell 関数を使って Python スクリプトを叩いたり、
' WinHTTP を使って Google Vision API 等に画像を送信したりします。
' 今回はロジックの流れを示すため、ダミーのテキストを返します。
' 例: Shell "python c:\scripts\ocr_tool.py " & filePath, vbHide
CallExternalOCR = "(ここに画像から読み取ったテキストが入ります)"
End Function
3. プロが教える「陥りやすい罠」と回避術
このコードを実装する際、初心者が必ずと言っていいほど躓くポイントが3つあります。ここをクリアすれば、あなたはもう「ただのマクロ使い」ではありません。
① `Body` ではなく `HTMLBody` を使え
VBAで `mail.Body = “テキスト”` と書き換えると、メール内の書式(太字、色、リンク)がすべて剥ぎ取られ、ただのプレーンテキストになってしまいます。
受け取ったメールの美しさを保ったまま情報を追加するには、必ず `HTMLBody` プロパティを操作し、HTMLタグ(`
`)を組み合わせて構築しましょう。
② `NewMail` ではなく `NewMailEx` を選べ
`NewMail` イベントは、複数のメールが同時に届いた際に、すべてのメールを正しく処理できないリスクがあります。
`NewMailEx` は、届いたメールの `EntryID` を引数として渡してくれるため、「どのメールに対して処理を行うか」を確実に特定できます。これは、不具合を防ぐための極めて重要な選択です。
③ オブジェクトのライフサイクルとエラーハンドリング
外部のOCRエンジンを呼び出す際、ファイルがロックされていたり、ネットワークが切断されていたりすることがあります。
`On Error Resume Next` を乱用するのは禁物ですが、外部連携の部分には適切なエラーハンドリングを施し、「OCRに失敗しても、メール自体が消えたりOutlookがフリーズしたりしない」堅牢な作りを目指してください。
4. 次のステップへ:さらなる高みを目指すなら
今回のコードは、いわば「基礎的な自動化の骨組み」です。ここから先、あなたが目指すべき進化の方向性を提示しておきましょう。
- AIとの融合: OCRで得たテキストを、そのまま ChatGPT (OpenAI API) に投げ、「この画像の内容を要約して」と命令する。これだけで、メールの要約自動化が完成します。
- セキュリティの強化: 外部APIを使う場合、APIキーの管理や、機密情報の取り扱いに細心の注意を払ってください。
- 非同期処理の検討: 非常に重い処理を行う場合は、VBAから直接実行するのではなく、一度ファイルを特定のフォルダに保存し、それを監視している別プロセス(Python等)に処理を任せる「キュー方式」を検討しましょう。
最後に
プログラミングは、単にコードを書く作業ではありません。「不便を、仕組みで解決する」という設計思想の構築です。
今回の「画像メールのテキスト化」は、その設計思想を学ぶための素晴らしい教材です。まずはコピペから始めて構いません。動いた時の感動を味わったら、少しずつ自分なりのカスタマイズを加えていってください。
その積み重ねが、あなたを「伝説のエンジニア」へと近づけてくれるはずですよ。応援しています!
