「単にメールを送るだけのマクロ」から、「ビジネスを守るプロフェッショナルなツール」へ。
こんにちは。業務自動化の深淵を探求するチーフアーキテクトです。
普段、マクロの記録やネットの切り貼りコードで「動けばいいや」と妥協していませんか?
中級者への階段を登るあなたが次に挑むべきは、「安全性」と「信頼性」の構築です。
今回は、実務で最も恐ろしい「ウイルス感染ファイルの誤送信」を防ぐため、送信直前に添付ファイルを外部スキャンエンジンでチェックし、危険があれば送信を強制停止するという、極めて実践的なセキュリティ実装を解説します。
ここをクリアすれば、あなたのOutlook VBAスキルは「趣味」から「実務レベル」へと昇華します。さあ、始めましょう。
—
1. 動作の全体像:なぜ「一時保存」が必要なのか?
Outlookのメールに添付されたファイルは、実は「メールアイテム(MailItem)」というオブジェクトの中にバイナリデータとして格納されています。
多くのウイルススキャナ(Windows Defenderや外部APIなど)は、メモリ上のデータではなく、「実際のファイル」を対象に動作します。
そのため、以下のステップを踏む必要があります。
1. ゲートチェック: 送信ボタンが押された瞬間に処理を割り込ませる(`ItemSend`イベント)。
2. 一時展開: 添付ファイルをPCの「一時フォルダ(Temp)」に物理的に保存する。
3. 外部連携: 保存したファイルをスキャンエンジン(CLIツールやAPI)に渡す。
4. 判定: スキャン結果が「安全」なら送信を続行。「危険」なら一時ファイルを削除して送信をキャンセルする。
—
2. 魂のコード:セキュリティ・スキャン・ゲートウェイ
このコードは、Outlookの `ThisOutlookSession` モジュールに記述します。
今回は例として、Windows標準の Windows Defender (MpCmdRun.exe) をコマンドラインから呼び出す構成にしていますが、API連携の場合も「コマンドを送って戻り値を受け取る」という本質は同じです。
‘ ==========================================================================
‘ Outlook VBA Security Gateway: Attachment Virus Scanner
‘ ————————————————————————–
‘ 役割: 送信前に全ての添付ファイルを一時保存し、外部スキャナで安全性を確認する。
‘ 設置場所: ThisOutlookSession
‘ ==========================================================================
Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
Dim mail As Outlook.MailItem
Dim att As Outlook.Attachment
Dim fso As Object
Dim shell As Object
Dim tempFolder As String
Dim filePath As String
Dim scanResult As Long
‘ 1. メールの判定(メール以外の場合はスルー)
If Not TypeOf Item Is MailItem Then Exit Sub
Set mail = Item
‘ 添付ファイルがなければそのまま送信
If mail.Attachments.Count = 0 Then Exit Sub
‘ 2. オブジェクトの初期化
Set fso = CreateObject(“Scripting.FileSystemObject”)
Set shell = CreateObject(“WScript.Shell”)
‘ 一時フォルダのパスを取得(ユーザーごとのTempフォルダ)
tempFolder = Environ(“TEMP”) & “\OutlookScan_” & Format(Now, “hhmmss”)
If Not fso.FolderExists(tempFolder) Then fso.CreateFolder(tempFolder)
On Error GoTo ErrorHandler
‘ 3. 添付ファイルを一つずつチェック
For Each att In mail.Attachments
‘ インライン画像(署名など)は除外する等のロジックも検討可能
filePath = tempFolder & “\” & att.FileName
‘ 一時保存
att.SaveAsFile filePath
‘ 4. 外部スキャナの実行(例:Windows Defenderのコマンドラインツール)
‘ MpCmdRun.exe のパスは環境に合わせて調整してください
‘ -Scan -ScanType 3 -File [パス] で特定ファイルをスキャン
‘ ReturnCode: 0=脅威なし, 2=脅威検出
Dim cmd As String
cmd = “””%ProgramFiles%\Windows Defender\MpCmdRun.exe”” -Scan -ScanType 3 -File “”” & filePath & “”””
‘ スキャン実行(同期実行:終わるまで待機。ウィンドウは非表示)
scanResult = shell.Run(cmd, 0, True)
‘ 5. 判定(0以外は問題ありとみなす)
If scanResult <> 0 Then
MsgBox “【警告】添付ファイルにセキュリティ上のリスクが検出されました。” & vbCrLf & _
“ファイル名: ” & att.FileName & vbCrLf & vbCrLf & _
“送信を中止します。”, vbCritical, “セキュリティ・ブロック”
Cancel = True ‘ 送信をキャンセル
Exit For
End If
Next att
Cleanup:
‘ 6. 後始末:一時フォルダとファイルを削除
If fso.FolderExists(tempFolder) Then
fso.DeleteFolder tempFolder, True
End If
Set fso = Nothing
Set shell = Nothing
Exit Sub
ErrorHandler:
MsgBox “スキャン処理中にエラーが発生しました。安全のため送信を停止します。” & vbCrLf & _
Err.Description, vbExclamation
Cancel = True
Resume Cleanup
End Sub
—
3. ここがプロの知見:解説と注意点
① `Application_ItemSend` イベントの魔力
このイベントは、ユーザーが「送信」ボタンをクリックした直後、かつ実際にメールがサーバーへ送られる前に発火します。
引数の `Cancel` に `True` を代入するだけで、送信プロセスを完全にストップできます。これが「最強の防波堤」となる理由です。
② `WScript.Shell.Run` の第3引数
`shell.Run(cmd, 0, True)` の `True` が極めて重要です。
これは「コマンドの実行が終わるまで、VBAの次の行を読まない(同期処理)」という意味です。ここを `False` にしてしまうと、スキャンが終わる前に「異常なし」と判定して送信されてしまいます。
③ ファイル名競合とクリーンアップ
実務でよくあるエラーが「同名のファイルがTempフォルダに既に存在する」ことによる書き込み失敗です。
今回のコードでは、実行のたびに時刻(`hhmmss`)を含めたユニークなフォルダを作成し、最後にフォルダごと削除することで、ゴミを残さず、エラーも防いでいます。
④ APIを利用する場合のヒント
もしVirusTotalなどのWeb APIを利用したい場合は、`MSXML2.XMLHTTP` オブジェクトを使用して、保存したファイルをPOST送信するコードに差し替えます。ただし、APIの応答待ち(タイムアウト)には注意が必要です。
—
4. 陥りやすい罠:なぜ動かない?
1. マクロが無効になっている
Outlookの「トラストセンター」でマクロを有効にする必要がありますが、実務では「デジタル署名」を付与するのが正解です。
2. 外部ツールのパスが違う
Windows DefenderのパスはOSのバージョンや32bit/64bitによって異なる場合があります。必ず事前にコマンドプロンプトで動作確認をしてください。
3. 書き込み権限がない
`Environ(“TEMP”)` を使うのは、そこが「ユーザーが必ず書き込みを許されている場所」だからです。
—
最後に:一歩先を目指すあなたへ
「自動化」の目的は楽をすることだけではありません。「人間が介在することで発生するミス(リスク)を、システムで物理的に不可能にすること」にこそ、真の価値があります。
今回のスキャン実装は、その第一歩です。
ここをベースに、「特定のドメイン宛の時はさらに厳格なチェックを入れる」「送信ログを外部DBに保存する」といった拡張を考えてみてください。
「ここをクリアすれば、Outlook VBAの基本はバッチリですよ」。
その先にある「高度な自動化」の世界で、またお会いしましょう。応援しています!
