【実務・中級編】【中級者向け】メール作成時に「添付ファイルのウイルススキャン」を外部APIと連携して実行する – Outlook VBA解析バイブル

スポンサーリンク

「ただ送るだけのコード」なら、初心者でも書ける。
しかし、企業の屋台骨を支えるエンジニアが書くべきは、「企業の信頼を失墜させない、堅牢なゲートウェイ」としてのコードだ。

こんにちは、チーフアーキテクトだ。
今日は、Outlook VBAの実務において避けては通れない、しかし多くの者が「面倒だから」と目を背けてきた領域——「添付ファイルの自動ウイルススキャン連携」について講義する。

マクロでメールを自動生成し、大量に配信する。素晴らしい。だが、その添付ファイルが汚染されていたら? あなたが作ったツールは、一瞬で「社内感染の起点」へと成り下がる。

今回は、Outlookの送信イベントをフックし、外部のスキャナ(CLI/API)と連携して、安全が確認された場合にのみ送信を許可する「防波堤」の実装を伝授する。

—

1. アーキテクチャの設計思想:なぜ「送信直前」なのか

設計において最も重要なのは、「どこで検閲を行うか」だ。
メール作成時に随時チェックするのは非効率極まりない。正解は、Outlookの`Application_ItemSend`イベントを利用した、送信確定直前のインターセプトだ。

実装の三原則

1. ステイジング(隔離保存): 添付ファイルをメモリから物理的な一時フォルダへ書き出す。
2. スキャン実行: 外部プロセス(Windows DefenderやClamAV、あるいはVirusTotal API等)を呼び出し、戻り値を評価する。
3. ロールバック(送信中止): 脅威が検知された場合、`Cancel = True` を叩き込み、絶対に外に出さない。

—

2. プロダクション・コード:ウイルススキャン連携の実装

ここでは、汎用性が高い「コマンドライン・スキャナ(例:Windows DefenderのMpCmdRun.exe)」を呼び出す例を示す。API連携の場合も、この実行部をHTTP通信に差し替えるだけだ。

ThisOutlookSession

イベントを補足するため、必ず`ThisOutlookSession`に記述する。

‘
‘ Event: Application_ItemSend
‘ Description: 送信ボタン押下時に起動。添付ファイルの安全性を検証する。
‘
Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
Dim mail As Outlook.MailItem

‘ メールオブジェクト以外(会議出席依頼など)はスキップ
If Not TypeOf Item Is MailItem Then Exit Sub
Set mail = Item

‘ 添付ファイルがない場合はパス
If mail.Attachments.Count = 0 Then Exit Sub

‘ セキュリティ・スキャン実行
If Not IsAttachmentSafe(mail) Then
MsgBox “【警告】添付ファイルにセキュリティ上のリスクが検知されました。” & vbCrLf & _
“送信を中止します。管理者に連絡してください。”, vbCritical, “セキュリティ・ゲート”
Cancel = True ‘ 送信を強制キャンセル
End If
End Sub

標準モジュール:ScannerModule

ここで「一時保存」と「スキャナ呼び出し」の泥臭い処理を完結させる。

Option Explicit

‘
‘ Function: IsAttachmentSafe
‘ Description: 全ての添付ファイルを一時保存し、外部スキャナでチェックする
‘
Public Function IsAttachmentSafe(ByRef mail As Outlook.MailItem) As Boolean
Dim fso As Object
Set fso = CreateObject(“Scripting.FileSystemObject”)

Dim tempFolder As String
tempFolder = CreateTempStage(fso) ‘ 一時フォルダの作成

Dim att As Outlook.Attachment
Dim filePath As String
Dim isSafe As Boolean: isSafe = True

On Error GoTo ErrorHandler

‘ 1. 全添付ファイルをローカルに展開
For Each att In mail.Attachments
filePath = tempFolder & “\” & att.FileName
att.SaveAsFile filePath

‘ 2. 外部スキャナの呼び出し(ここでは例としてWindows Defender CLIを使用)
If Not RunVirusScan(filePath) Then
isSafe = False
Exit For
End If
Next att

‘ 3. 後処理:一時フォルダの削除
Cleanup tempFolder, fso

IsAttachmentSafe = isSafe
Exit Function

ErrorHandler:
‘ エラー時は「安全ではない」と判断し、送信を止めるのが安全側の設計(Fail-Safe)
IsAttachmentSafe = False
If Not fso Is Nothing Then Cleanup tempFolder, fso
End Function

‘ — 外部スキャナ呼び出し(CLI連携の実装例) —
Private Function RunVirusScan(ByVal filePath As String) As Boolean
Dim shell As Object
Set shell = CreateObject(“WScript.Shell”)
Dim waitOnReturn As Boolean: waitOnReturn = True
Dim windowStyle As Integer: windowStyle = 0 ‘ 非表示で実行
Dim exitCode As Integer

‘ 例:Windows Defenderのコマンドラインツールを使用
‘ ※パスは環境に合わせて調整すること
Dim cmd As String
cmd = “””%ProgramFiles%\Windows Defender\MpCmdRun.exe”” -Scan -ScanType 3 -File “”” & filePath & “”””

‘ 実行
exitCode = shell.Run(cmd, windowStyle, waitOnReturn)

‘ Windows Defenderの場合、戻り値 0 が「脅威なし」
RunVirusScan = (exitCode = 0)
End Function

‘ — ヘルパー関数:一時ディレクトリ作成 —
Private Function CreateTempStage(fso As Object) As String
Dim path As String
path = fso.GetSpecialFolder(2) & “\OutlookScan_” & Format(Now, “yyyymmddHHnnss”)
If Not fso.FolderExists(path) Then fso.CreateFolder path
CreateTempStage = path
End Function

‘ — ヘルパー関数:クリーンアップ —
Private Sub Cleanup(path As String, fso As Object)
On Error Resume Next
If path <> “” And fso.FolderExists(path) Then fso.DeleteFolder path, True
End Sub

—

3. チーフアーキテクトによる深掘り解説

なぜ `WScript.Shell.Run` なのか

VBAから外部プログラムを叩く方法はいくつかあるが、`Run` メソッドの第三引数を `True` に設定することで、「スキャンが終わるまでVBAの処理を待機(同期実行)」させることができる。
非同期で進めてしまうと、スキャン結果が出る前にメールが送信されてしまうという、致命的なレースコンディション(競合状態)が発生する。これは絶対に避けねばならない。

Fail-Safe(フェイルセーフ)の原則

`ErrorHandler` を見てほしい。エラーが発生した際、この関数は `False` を返すように設計してある。
「スキャンに失敗した(スキャナが動かなかった)」場合、「安全かどうかわからない」のだから、「安全ではない」とみなして送信を止める。 これがプロの設計思想だ。

ファイルシステムのライフサイクル管理

`CreateTempStage` でタイムスタンプ付きのフォルダを作成しているのは、同時実行時の衝突を避けるためだ。また、`Cleanup` 関数で確実にフォルダを消し去る。
ストレージにゴミを残すツールは、運用担当者から最も嫌われる。作成したものは、責任を持って消す。これが「ライフサイクルを知り尽くした」者の作法だ。

—

4. さらに高度な実装へ:API連携のヒント

もし、社内のサンドボックス・ソリューションや VirusTotal API を利用したい場合は、`RunVirusScan` 関数の中身を `MSXML2.XMLHTTP` を使ったPOSTリクエストに置き換えればよい。

その際の注意点は、「タイムアウト設計」だ。
外部APIはネットワーク遅延やサービスダウンの影響を受ける。無限にOutlookをフリーズさせるわけにはいかない。
1. リクエスト送信前にユーザーに「スキャン中…」のステータスを表示する(モードレスフォーム等)。
2. レスポンスが30秒以上返らない場合は、送信を一時保留にするか、管理者承認フローへ回す。

最後に

VBAは、単なる「マクロ」ではない。
適切な設計思想を注ぎ込めば、エンタープライズ級のセキュリティ・ゲートウェイとして機能する。

「動けばいい」というコードから卒業し、「何が起きても破綻しない」堅牢なシステムを構築してほしい。それが、現場を支えるエンジニアとしての矜持だ。

健闘を祈る。

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