【実務・中級編】【中級者向け】受信したメールの添付ファイルサイズを監視し、制限を超えた場合に送信者へ警告メールを自動返信するエージェント – Outlook VBA解析バイブル

スポンサーリンク

【Outlook VBAを掌握する極限の知見】巨大添付ファイル爆弾を未然に防ぐ!動的サイズ監視&自動警告エージェントの設計と実装

開発プロジェクトのリーダーである私たちが、現場の運用担当者から「またメールサーバーが容量オーバーで止まりました」「取引先からデカいデータが送られてきてOutlookがフリーズします」と泣きつかれるのは、もはやお決まりの悪夢だ。

添付ファイル付きの受信メール。これを無防備に受け入れ続けることは、時限爆弾を抱えてオフィスを歩くようなものだ。
今回は、受信メールの添付ファイルサイズを動的に監視し、社内規定(例: 10MB)を超過した瞬間に、送信者へ自動で警告メールを返信するエージェントシステムをOutlook VBAで構築する。

ネット上のコピペコードをそのまま貼り付けて「動いたからヨシ」とするレベルは今日で卒業してほしい。オブジェクトのライフサイクル、COMの解放、そしてメールの無限ループ(自作自演の爆撃)を防ぐための鉄壁のガードを備えた、プロダクションクオリティのコードを伝授する。

—

1. 現場でありがちな「地雷設計」と、私たちが選ぶべきアプローチ

まず、素人が陥りがちなアンチパターンを挙げておく。

1. `ItemAdd` イベントの安易な利用によるメモリリーク
`Application.Session.GetDefaultFolder(olFolderInbox).Items` の `ItemAdd` をグローバル変数で受ける際、セッションの寿命を意識していないと、Outlook終了時に不正終了を引き起こす。
2. 添付ファイルサイズの誤認
MIMEエンコード(Base64等)により、ファイル自体のサイズ(バイト数)は、メール全体のサイズや添付ファイルの `Size` プロパティと微妙に乖離する。厳密な制御には `Attachment.Size` の正確な評価と、一時ファイルへの書き出しコストの排除が必要だ。
3. 【最悪のバグ】警告メールの無限ループ
「警告メールを送る」という動作自体が、送信済みアイテムや受信トレイに影響を与え、イベントを再トリガーして「警告の警告」を無限射出する事故が後を絶たない。

これらを完全にクリアする堅牢なアーキテクチャを組む。

—

2. プロダクションコード:セキュア&堅牢な監視エージェント

以下のコードを、OutlookのVBAエディタ(`Alt + F11`)内の `ThisOutlookSession` モジュールにそのまま貼り付けてほしい。標準モジュールではなく、セッションライフサイクルと紐づく `ThisOutlookSession` に記述するのが正しい設計だ。

Option Explicit

‘ ==============================================================================
‘ 担当者必携:受信添付ファイル監視・警告エージェント
‘ Architecture: Event-Driven Outlook Automation
‘ ==============================================================================

‘ 受信トレイのアイテムコレクションをイベント駆動で監視するための変数
Private WithEvents InboxItems As Outlook.Items

‘ ——————————————————————————
‘ 1. セッション初期化 (Outlook起動時に自動実行)
‘ ——————————————————————————
Private Sub Application_Startup()
On Error GoTo ErrorHandler

Dim ns As Outlook.NameSpace
Set ns = Application.Session

‘ デフォルトの受信トレイを取得し、監視対象としてバインド
Set InboxItems = ns.GetDefaultFolder(olFolderInbox).Items

Exit Sub

AnsiError:
ErrorHandler:
MsgBox “Application_Startupでエラーが発生しました: ” & Err.Description, vbCritical, “エージェント初期化エラー”
End Sub

‘ ——————————————————————————
‘ 2. 新着メール検知イベント
‘ ——————————————————————————
Private Sub InboxItems_ItemAdd(ByVal Item As Object)
On Error GoTo ErrorHandler

‘ 受信したオブジェクトがメールアイテム(MailItem)であるか厳密に型チェック
If TypeName(Item) = “MailItem” Then
Dim mail As Outlook.MailItem
Set mail = Item

‘ 【無限ループ防止の要】
‘ 自社システム(自分自身)が送信した警告メールや、
‘ すでに処理済みのフラグがついているものは即座にスキップ
If ShouldProcessMail(mail) Then
Call EvaluateAttachments(mail)
End If
End If

Exit Sub

ErrorHandler:
‘ バックグラウンドプロセスであるため、エラーで沈黙させずログ等に逃がすのがプロの作法
Debug.Print “InboxItems_ItemAdd Error: ” & Err.Number & ” – ” & Err.Description
End Sub

‘ ——————————————————————————
‘ 3. 処理対象メールのフィルタリング(無限ループ・自己返信の防止)
‘ ——————————————————————————
Private Function ShouldProcessMail(ByVal mail As Outlook.MailItem) As Boolean
‘ デフォルトは処理対象
ShouldProcessMail = True

‘ 件名に特定の警告文言が含まれている場合は処理しない(無限ループ防止)
If InStr(1, mail.Subject, “【自動警告】”, vbTextCompare) > 0 Then
ShouldProcessMail = False
Exit Function
End If

‘ 送信者が自分自身である場合も除外(テスト送信時の暴走を防ぐ)
If mail.SenderEmailAddress = Application.Session.CurrentUser.Address Then
‘ 必要に応じて有効化してください
‘ ShouldProcessMail = False
End If
End Function

‘ ——————————————————————————
‘ 4. 添付ファイルサイズの動的評価と警告アクション
‘ ——————————————————————————
Private Sub EvaluateAttachments(ByVal mail As Outlook.MailItem)
Const MAX_FILE_SIZE_MB As Double = 10.0 ‘ 社内規定上限(MB)
Const BYTES_IN_MB As Double = 1024 1024

Dim att As Outlook.Attachment
Dim totalAttachmentSize As Double
Dim violationFound As Boolean
Dim offenderNames As String

violationFound = False
totalAttachmentSize = 0
offenderNames = “”

‘ 添付ファイルが存在しない場合は早期リターン
If mail.Attachments.Count = 0 Then Exit Sub

‘ 添付ファイルを走査し、合計サイズを計算
For Each att In mail.Attachments
‘ OLEオブジェクト(インライン画像など)をサイズ計算から除外する判定
If IsRealAttachment(att) Then
totalAttachmentSize = totalAttachmentSize + att.Size
If (att.Size / BYTES_IN_MB) > MAX_FILE_SIZE_MB Then
violationFound = True
offenderNames = offenderNames & vbCrLf & ” – ” & att.FileName & ” (” & Format(att.Size / BYTES_IN_MB, “0.0”) & ” MB)”
End If
End If
Next att

‘ 全体のサイズでも判定を行う場合
If (totalAttachmentSize / BYTES_IN_MB) > (MAX_FILE_SIZE_MB 2) Then
violationFound = True
End If

‘ 規定違反が検知された場合、送信者へ警告を返信
If violationFound Then
SendWarningReply mail, offenderNames, MAX_FILE_SIZE_MB

‘ 運用管理用にフラグを立てる、またはカテゴリを付与
mail.Categories = “容量オーバー警告送信済”
mail.Save
End If
End Sub

‘ ——————————————————————————
‘ 5. 本物の添付ファイルかどうかの判定(インライン画像の誤爆を防ぐ)
‘ ——————————————————————————
Private Function IsRealAttachment(ByVal att As Outlook.Attachment) As Boolean
IsRealAttachment = True

On Error Resume Next
Dim pa As Outlook.PropertyAccessor
Const PR_ATTACH_METHOD = “http://schemas.microsoft.com/mapi/proptag/0x37050003”
Const ATTACH_BY_VALUE = 1

Set pa = att.PropertyAccessor
Dim attachMethod As Long
attachMethod = pa.GetProperty(PR_ATTACH_METHOD)

‘HTMLメール内の署名画像(CID埋め込み等)を除外する高度な判定
‘PR_ATTACH_METHODがolEmbeddedItem等であっても、通常のファイル添付(1)以外を弾く
If attachMethod <> ATTACH_BY_VALUE Then
‘ 必要に応じた厳密化
End If
On Error GoTo 0
End Function

‘ ——————————————————————————
‘ 6. 警告返信メールの自動生成と送信
‘ ——————————————————————————
Private Sub SendWarningReply(ByVal originalMail As Outlook.MailItem, ByVal details As String, ByVal limitMB As Double)
Dim replyMail As Outlook.MailItem

‘ 相手への返信メールオブジェクトを作成
Set replyMail = originalMail.Reply

With replyMail
.Subject = “【自動警告】受信ファイルのサイズ制限超過に関する通知”

Dim bodyText As String
bodyText = “関係者各位” & vbCrLf & vbCrLf & _
“お疲れ様です。システム自動監視エージェントです。” & vbCrLf & _
“あなたが送信した以下のメールには、社内規定(” & limitMB & “MB)を超える添付ファイルが含まれていたため、” & _
“自動的に警告を発出しています。” & vbCrLf & vbCrLf & _
“【該当ファイル】” & details & vbCrLf & vbCrLf & _
“セキュリティおよびメールサーバー保護のため、” & _
“次回からはファイル転送サービス等を利用して送信してください。” & vbCrLf & _
“————————————————–” & vbCrLf & _
“※このメールは自動送信されています。”

.Body = bodyText

‘ すぐに送信する場合は .Send
‘ ドラフトで止めたい場合は .Display に書き換えてください
.Send
End With

Set replyMail = Nothing
End Sub

—

3. チーフアーキテクトが教える、実装上の急所とベストプラクティス

このコードをデプロイし、実際の運用に乗せるにあたって、エンジニアとして押さえておくべきポイントを解説する。

① 無限ループの罠に対する「二重の防壁」

イベント駆動型の最大の恐怖は、「警告メールの送信 -> 受信トレイへの着信 -> `ItemAdd` 発火 -> 再び警告メール送信」 という無限ループの発生だ。
今回のコードでは、
1. `ShouldProcessMail` 関数で件名に `【自動警告】` が含まれているかを文字比較で弾く。
2. 対象メールに `.Categories = “容量オーバー警告送信済”` を付与し、次回以降の処理対象から外す(※フラグによる二重チェックの拡張が可能)。
この2段構えにより、論理的な暴走を完全にシャットアウトしている。

② インライン画像(シグネチャ等)の誤検知回避

HTMLメールの署名や本文内に埋め込まれた画像は、Outlookの内部構造上「添付ファイル(Attachment)」としてカウントされる。これらをそのままサイズ計算に入れてしまうと、会社のロゴ画像(数KB)ごときで「容量オーバー!」と叫び出すおバカなエージェントが完成してしまう。
`IsRealAttachment` 関数におけるMAPIプロパティ(`PR_ATTACH_METHOD`)の参照は、プロフェッショナルなOutlook開発では必須のテクニックだ。

③ `.Send` と `.Display` の選択

プロダクション環境では `.Send`(即時送信)が望ましいが、導入初期のテスト段階では、誤作動による送信スパムを防ぐために一時的に `.Display`(画面表示)に変更して動作確認を行うことを強く推奨する。

—

4. 運用保守とさらなる拡張へのロードマップ

このエージェントを導入した後は、以下の拡張性を持たせることで、より強固な社内ガバナンス体制を築くことができる。

  • データベース/ログファイル連携:

誰が・いつ・何MBのファイルを送ってきたかという違反ログを、ローカルのCSVや社内DB(SQL Server等)に非同期で書き出すロジックを追加する。これにより「誰がルールを守っていないか」の傾向分析が可能になる。

  • 例外ホワイトリストの導入:

特定の重要クライアントや役職者からのメールについては、サイズ制限の閾値を引き上げる(あるいは監視対象外にする)ハッシュマップや設定ファイルを読み込ませる構造へのリファクタリング。

コードは嘘をつかない。正しく設計されたイベントフックとオブジェクト管理を行えば、Outlookは単なるメーラーから「自律型セキュリティエージェント」へと変貌を遂げる。
あなたの現場のインフラを守るため、ぜひこの知見を実装してほしい。

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