【入門編】【中級者向け】パスワード付きZIPファイル添付メールを検知してログに記録するエラーハンドリング – Outlook VBA解析バイブル

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

「止まらない自動化」の極意:パスワード付きZIPをスマートに回避するエラーハンドリング術

こんにちは。現場で数々の自動化システムを設計・運用してきた、あなたの「設計の先輩」です。

マクロの記録機能を使って、ようやく「自分の思い通りにOutlookを動かせるようになった!」という段階。それは素晴らしい一歩です。でも、もしあなたが「実務で使える、プロのツール」を作りたいと考えているなら、今こそ踏み越えなければならない壁があります。

それが、「例外(エラー)への対処」です。

多くの初心者が作るマクロは、「すべてが順調に進むこと(ハッピーパス)」だけを前提に書かれています。しかし、現実のビジネス現場はそんなに甘くありません。
「パスワード付きのZIPファイルが送られてきた」「ファイルが壊れていた」「ネットワークが一時的に切れた」……。

こうした「想定外」が起きた瞬間、マクロは無慈悲に停止し、それまで処理していた他のメールの処理もすべて止まってしまいます。これは、業務自動化において「致命的な欠陥」です。

今日は、そんなプロの現場で必須となる「パスワード付きZIPファイルを検知し、処理を止めずにログに記録する」という、一歩進んだエラーハンドリングの技術を伝授しましょう。

1. なぜ「エラーで止まる」ことが問題なのか?

想像してみてください。あなたは毎日100通のメールから添付ファイルを自動保存するマクロを動かしています。

  • 初心者のコード: 5通目のメールにパスワード付きZIPがあった瞬間、エラーで停止。残り95通の処理は行われず、あなたは手動でやり直す羽目に。
  • プロのコード: 5通目のメールで「パスワード付きZIPを検知」し、ログに「5通目:パスワード付きのためスキップ」と記録。そのまま6通目の処理へ進む。

この差は、「システムの信頼性」の差です。
自動化の目的は「人間の手間を減らすこと」であって、「エラーが起きた時に人間が介在して修正する手間を増やすこと」ではありません。

2. 戦略:エラーを「検知」するのではなく「利用」する

「パスワードがかかっているかどうか」を事前に判定するプロパティは、残念ながらOutlook VBAの標準機能には存在しません。

では、どうするか?
プロのエンジニアは、「あえて開こうとしてみて、エラーが出たらそれを検知する」というアプローチを取ります。これを「Try-Catch」的な考え方と呼びます。

1. 添付ファイルを解凍(またはアクセス)しようと試みる。
2. もしパスワード保護などでエラーが出たら、そのエラーをキャッチする。
3. エラーの内容をログファイルに書き出し、次のメールへ処理を移す。

この「エラーを、次のアクションへのトリガーにする」という考え方が、極限の堅牢性を生むのです。

3. 実装:堅牢な添付ファイル処理コード

それでは、実際に動くコードを見ていきましょう。
このコードでは、`Microsoft Scripting Runtime`(FileSystemObjectを使うため)への参照設定が必要ですが、まずはコードの構造とその意味を深く理解してください。

' 【重要】VBAエディタの [ツール] -> [参照設定] から
' 「Microsoft Scripting Runtime」にチェックを入れてください。

Option Explicit

' --- 設定領域 ---
Private Const LOG_FILE_PATH As String = "C:\Temp\Automation_Log.txt" ' ログの保存先
Private Const SAVE_FOLDER As String = "C:\Temp\SavedAttachments\"    ' 保存先フォルダ

''' <summary>
''' メインルーチン:受信トレイのメールをスキャンし、添付ファイルを処理する
''' </summary>
Public Sub ProcessIncomingEmails()
    Dim outlookApp As Outlook.Application
    Dim ns As Outlook.NameSpace
    Dim inbox As Outlook.Folder
    Dim mailItem As Object
    Dim attachment As Outlook.Attachment
    Dim fso As New FileSystemObject
    
    Set outlookApp = New Outlook.Application
    Set ns = outlookApp.GetNamespace("MAPI")
    Set inbox = ns.GetDefaultFolder(olFolderInbox)
    
    ' 保存先フォルダがなければ作成
    If Not fso.FolderExists(SAVE_FOLDER) Then
        fso.CreateFolder (SAVE_FOLDER)
    End If

    Debug.Print "--- 処理開始: " & Now & " ---"

    ' 受信トレイのアイテムをループ
    ' ※本来は未読のみに絞るなどの条件を加えるとより効率的です
    For Each mailItem In inbox.Items
        ' メールアイテム(MailItem)である場合のみ処理
        If TypeName(mailItem) = "MailItem" Then
            
            ' 添付ファイルがあるか確認
            If mailItem.Attachments.Count > 0 Then
                
                ' 各添付ファイルに対して処理を実行
                For Each attachment In mailItem.Attachments
                    Call HandleAttachment(mailItem, attachment)
                Next attachment
                
            End If
        End If
    Next mailItem

    Debug.Print "--- 処理終了: " & Now & " ---"
    MsgBox "全ての処理が完了しました。詳細はログを確認してください。", vbInformation
End Sub

''' <summary>
''' 個別の添付ファイルを処理するサブ関数
''' </summary>
Private Sub HandleAttachment(ByRef mail As Outlook.MailItem, ByRef att As Outlook.Attachment)
    Dim savePath As String
    Dim fso As New FileSystemObject
    
    ' 保存パスの構築
    savePath = SAVE_FOLDER & att.FileName
    
    ' エラーハンドリングの開始
    On Error GoTo ErrorHandler
    
    ' --- 1. 添付ファイルの保存 ---
    att.SaveAsFile savePath
    
    ' --- 2. パスワード付きZIPの検知テスト ---
    ' ここでは、ZIPファイルの場合のみ「中身を覗こうとする」動作をシミュレートします。
    ' 実際に解凍ライブラリを使う場合はここを書き換えます。
    If LCase(fso.GetExtensionName(att.FileName)) = "zip" Then
        ' ここで解凍処理を試みる(仮にShell.Applicationなどを使用)
        ' パスワードがかかっていると、ここでエラーが発生します。
        Call TestZipAccess(savePath)
    End If
    
    ' 成功した場合のログ(デバッグ用)
    Debug.Print "成功: " & att.FileName
    
    ' エラーハンドリングの解除(正常終了時)
    On Error GoTo 0
    Exit Sub

ErrorHandler:
    ' --- ここがプロの仕事場です ---
    ' エラー番号が「パスワードエラー」に相当する、あるいは
    ' ファイルアクセス拒否などの場合を想定してログに記録
    Dim errorMsg As String
    errorMsg = "【エラー】ファイル: " & att.FileName & _
               " | 内容: " & Err.Description & _
               " | メール件名: " & mail.Subject
    
    ' 1. ログファイルへ記録
    Call WriteToLog(errorMsg)
    
    ' 2. 管理者への通知(本来はメール送信やTeams通知などを行う)
    ' 今回は簡易的にデバッグ出力のみ
    Debug.Print "【警告】" & errorMsg
    
    ' 3. 失敗したファイルを削除(ゴミを残さない)
    If fso.FileExists(savePath) Then fso.DeleteFile savePath
    
    ' エラーを握りつぶして、次の添付ファイル/メールへ進める
    On Error GoTo 0
End Sub

''' <summary>
''' ZIPファイルの中身にアクセスできるか試行する(擬似的な検知)
''' </summary>
Private Sub TestZipAccess(ByVal filePath As String)
    Dim shellApp As Object
    Dim zipFolder As Object
    
    Set shellApp = CreateObject("Shell.Application")
    ' ZIPファイルをフォルダとして開こうとする
    Set zipFolder = shellApp.Namespace(CVar(filePath))
    
    ' Namespaceが取得できない、あるいは中身のアイテムにアクセスできない場合にエラーを投げる
    ' ※実際の環境では、ここでの挙動はOSやライブラリに依存します
    If zipFolder Is Nothing Then
        Err.Raise vbObjectError + 513, "TestZipAccess", "パスワード保護されているか、破損しています。"
    End If
End Sub

''' <summary>
''' ログファイルに追記する
''' </summary>
Private Sub WriteToLog(ByVal message As String)
    Dim fso As New FileSystemObject
    Dim ts As TextStream
    
    ' Appendモードでファイルを開く(なければ作成)
    Set ts = fso.OpenTextFile(LOG_FILE_PATH, ForAppending, True)
    ts.WriteLine "[" & Now & "] " & message
    ts.Close
End Sub

4. コードの解説:ここが「設計のキモ」です

このコードには、単なる「動くコード」を超えた、3つの重要な設計思想が組み込まれています。

① `On Error GoTo ErrorHandler` の適切な配置

初心者は、コードの冒頭に `On Error Resume Next` を書いてしまいがちです。これは「エラーを無視して突き進め」という命令ですが、これでは「何が起きたか」が一切分からなくなります。
プロは、「エラーが起きそうな箇所(今回ならファイル操作)」の直前でエラーハンドリングを開始し、エラーが起きたら専用の `ErrorHandler` へジャンプさせます。 これにより、エラーの発生場所を特定しつつ、プログラムの崩壊を防ぐことができます。

② オブジェクトのライフサイクルとクリーンアップ

エラーが起きたとき、中途半端に保存されたファイルが残っていると、次回の処理で「同名ファイルが既に存在します」という別のエラーを誘発します。
`ErrorHandler` 内で `fso.DeleteFile savePath` を行っているのは、「失敗した状態を綺麗に掃除(クリーンアップ)して、次の処理に影響を与えない」ためです。

③ ログという「証拠」を残す

自動化が止まっていないのに、なぜか一部のファイルが保存されていない……。そんな時、ログがなければ原因究明に数時間かかります。
`WriteToLog` 関数によって、「いつ」「どのメールの」「どのファイルが」「なぜ」失敗したのかをテキストに刻む。これが、運用フェーズにおけるエンジニアの命綱になります。

5. まとめ:ここをクリアすれば、Outlook VBAの基本はバッチリですよ

今回のポイントを振り返りましょう。

1. ハッピーパス以外を設計する: エラーが起きることを前提にコードを書く。
2. エラーを検知の手段にする: パスワード付きZIPなどは、アクセスを試みてエラーが出ることで判断する。
3. 「ログ・通知・掃除」の3点セット: エラーが起きたら、ログを書き、管理者に知らせ、ゴミを掃除する。

これらを意識できるようになったあなたは、もう「マクロを記録するユーザー」ではありません。「業務プロセスを設計するエンジニア」への入り口に立っています。

最初は難しく感じるかもしれません。でも、一度この「堅牢な構造」をマスターしてしまえば、どんなに複雑な業務自動化にも立ち向かえるはずです。

さあ、次はもっと複雑な条件分岐や、外部APIとの連携に挑戦してみましょう。応援していますよ!

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