【入門編】【上級者向け】添付ファイルが「インライン画像」か「添付ファイル」かを判別する詳細判定ロジック – Outlook VBA解析バイブル

スポンサーリンク
スポンサーリンク

【極限の知見】Outlook VBAで「ゴミ画像」を排除せよ:インライン画像と添付ファイルを完璧に判別するプロの技

こんにちは。自動化の荒波を乗り越える準備はできていますか?

Outlook VBAを学び始めると、誰もが一度は「壁」にぶつかります。それは、「添付ファイルを保存するマクロを作ったのに、署名のアイコンや絵文字まで一緒に保存されてしまう問題」です。

「マクロの記録」から一歩踏み出し、実用的なツールを作ろうとした時に必ず遭遇するこの問題。実はこれ、単なるプログラミングのミスではなく、Outlookがメールをどう構造化しているかという「設計思想」を知らないことが原因なのです。

今日は、そんな初級者が陥る罠をスマートに回避し、プロフェッショナルな現場でも通用する「インライン画像(本文埋め込み画像)と、真の添付ファイルを判別するロジック」を伝授します。ここをクリアすれば、あなたのVBAスキルは一段上のステージへ昇格しますよ。

1. なぜ「全部保存」ではいけないのか?

まず、問題の構造を整理しましょう。

メールには大きく分けて2種類の「画像」が存在します。

1. 真の添付ファイル (Attachment): ユーザーが意図的に「ファイル」として添付したもの。
2. インライン画像 (Inline Image): メールの署名に含まれるロゴ、本文中の絵文字、あるいはHTML形式で直接埋め込まれた画像。

これらは、Outlookの `Attachments` コレクションという同じ箱の中に入っています。そのため、単純に `For Each att In MailItem.Attachments` とループを回して保存するだけでは、「署名の小さなアイコン」までが、大量のファイルとしてフォルダに溢れ出してしまうのです。

これでは、自動化の目的である「業務効率化」どころか、後始末に時間がかかる「自動化の失敗」になってしまいます。

2. 判別の鍵は「MAPIプロパティ」にある

では、どうやってこれを見分けるのか?

「マクロの記録」では決して教えてくれない、プロのテクニックがあります。それは、`PropertyAccessor` オブジェクトを使用して、添付ファイルの「隠れた属性(MAPIプロパティ)」を覗き見ることです。

インライン画像には、HTMLの本文から呼び出すための「ID(Content-ID)」が紐付けられています。このIDが存在するかどうかをチェックするのが、最も確実で美しい解決策です。

具体的には、以下のMAPIタグを確認します。
`http://schemas.microsoft.com/mapi/proptag/0x3712001E`
(これは `PR_ATTACH_CONTENT_ID` というプロパティを指します)

このプロパティに値が入っていれば、それは「本文から参照されているインライン画像」である可能性が極めて高い、というわけです。

3. 実戦投入:インライン画像を排除する究極のコード

さあ、準備はいいですか? 実際に現場でそのまま使える、堅牢な判定ロジックを実装しましょう。

以下のコードは、単なる判定関数だけでなく、それをどう活用してファイルを保存するかという一連の流れを網羅しています。

Option Explicit

''' <summary>
''' メールの添付ファイルを、インライン画像を除外して保存するメインルーチン
''' </summary>
Sub SaveRealAttachments(ByVal targetMail As Outlook.MailItem)
    Dim att As Outlook.Attachment
    Dim savePath As String
    Dim fileName As String
    
    ' 保存先フォルダを指定(例:デスクトップの「SavedAttachments」フォルダ)
    ' ※事前にフォルダが存在することを確認してください
    savePath = CreateObject("WScript.Shell").SpecialFolders("Desktop") & "\SavedAttachments\"
    
    ' フォルダが存在しない場合に備えて、エラーハンドリングを行うのがプロの作法
    If Dir(savePath, vbDirectory) = "" Then
        MsgBox "保存先フォルダが見つかりません: " & savePath, vbCritical
        Exit Sub
    End If

    Debug.Print "--- 処理開始: " & targetMail.Subject & " ---"

    ' 添付ファイルのループ処理
    For Each att In targetMail.Attachments
        
        ' 【ここが重要!】インライン画像かどうかを判定する
        If Not IsInlineAttachment(att) Then
            
            ' インライン画像でない場合のみ、保存処理を実行
            fileName = savePath & att.FileName
            
            ' 同名ファイルの上書き防止ロジック(簡易版)
            If Dir(fileName) <> "" Then
                fileName = savePath & Format(Now, "yyyymmddhhmmss_") & att.FileName
            End If
            
            ' ファイルの保存
            att.SaveAsFile fileName
            Debug.Print "保存成功: " & att.FileName
            
        Else
            ' インライン画像だった場合は、スルーして次のファイルへ
            Debug.Print "スキップ(インライン画像): " & att.FileName
        End If
        
    Next att
    
    Debug.Print "--- 処理終了 ---"
End Sub

''' <summary>
''' 添付ファイルがインライン画像(本文埋め込み)かどうかを判定する
''' </summary>
''' <param name="att">判定対象のAttachmentオブジェクト</param>
''' <returns>インライン画像ならTrue、そうでなければFalse</returns>
Function IsInlineAttachment(ByVal att As Outlook.Attachment) As Boolean
    On Error GoTo ErrorHandler
    
    Dim propAccessor As Outlook.PropertyAccessor
    Dim contentID As String
    
    ' PropertyAccessorを取得
    Set propAccessor = att.PropertyAccessor
    
    ' MAPIプロパティ PR_ATTACH_CONTENT_ID (0x3712001E) を取得
    ' このプロパティが存在し、値が入っている場合はインライン画像とみなす
    contentID = propAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x3712001E")
    
    ' Content-IDが空でなければインライン画像と判定
    If contentID <> "" Then
        IsInlineAttachment = True
    Else
        IsInlineAttachment = False
    End If
    
    Exit Function

ErrorHandler:
    ' プロパティが存在しない場合、エラーが発生する。
    ' その場合は「インライン画像ではない(=通常の添付ファイル)」と判断して安全に抜ける。
    IsInlineAttachment = False
End Function

4. コードの解説と「プロのこだわり」

このコードには、初心者が卒業すべき「3つのポイント」を詰め込みました。

① `PropertyAccessor` による深層へのアクセス

`att.Type` プロパティを使えば、それが画像かどうかまでは分かりますが、「インラインか否か」は判別できません。`PropertyAccessor` を使い、MAPIレベルの隠れたデータ(`Content-ID`)にアクセスすることで、初めて真実が見えてくるのです。

② 堅牢なエラーハンドリング (`On Error GoTo`)

ここが最も重要です。`GetProperty` メソッドは、指定したプロパティが存在しない場合にエラーを吐いて止まってしまいます。
インライン画像ではない(=普通のファイル)場合、そもそも `Content-ID` というプロパティ自体が存在しないことが多いのです。
エラーを「失敗」と捉えず、「このプロパティは存在しない(=普通のファイルである)」という判定材料として利用する。これが、止まらないプログラムを作るための極意です。

③ ライフサイクルとパフォーマンスへの配慮

ループの中で毎回 `PropertyAccessor` を呼び出すのは、若干のコストがかかります。しかし、メールの添付ファイル数は通常数十個程度ですので、この設計が最もバランスが良く、読みやすいコードになります。

5. まとめ:次のステップへ

お疲れ様でした! これであなたは、単に「ファイルを保存する」だけでなく、「データの性質を理解して、必要なものだけを選別する」という、エンジニアとして極めて重要な能力を手にしました。

今回学んだ `PropertyAccessor` と MAPIプロパティの概念は、Outlook VBAに限らず、他のOffice連携や高度なシステム開発でも応用できる知識です。

「なぜ動かないのか?」ではなく「オブジェクトはどうなっているのか?」

常にこの視点を持つことで、あなたの自動化スキルは飛躍的に向上します。もしエラーが出ても、それは新しい発見への入り口です。焦らず、一つひとつのプロパティを紐解いていきましょう。

応援していますよ。また次の技術解説でお会いしましょう!

タイトルとURLをコピーしました