【Outlook VBA】添付ファイルの爆弾を未然に防ぐ!容量超過の動的検知とURL置換の極限最適化
開発プロジェクトのリーダーである私のもとに、よくこんな相談が持ち込まれる。
「ユーザーが巨大なファイルを添付して送信エラーになり、下書きが消えてパニックになった」
「取引先から『メールサーバーの容量制限で弾かれた』とクレームが入った」
ビジネスの現場において、メーラーの添付ファイル制限(一般的には10MB〜25MB程度)は常にエンジニアの頭痛の種だ。これを人力の注意喚起や、送信ボタンを押した後のエラーメッセージに頼るのは、システム設計の観点から見ても「怠慢」と言わざるを得ない。
今回は、Outlook VBAを用いて「添付ファイルの合計容量をミリ秒単位で事前計算し、規定値を超えた瞬間にファイルを自動退避(または削除)し、本文へファイル転送サービスのURLプレースホルダーを動的に挿入する堅牢な警告ツール」の全貌を伝授する。
中級者へのステップアップとして、単に動くコードではなく、オブジェクトのライフサイクルや、Outlook特有の罠を回避するプロフェッショナルな設計思想を叩き込む。
—
1. なぜ「送信時エラー」では遅いのか?設計思想の核心
素人がやりがちなアプローチは、`Application_ItemSend` イベントで添付ファイルのサイズを合計し、超過していたら `Cancel = True` で止めるというものだ。
だが、これでは実務上使い物にならない。なぜか?
1. ユーザー体験の悪化: 送信ボタンを押して待たされた挙句、「容量オーバーです」と冷たく突き放され、入力した長文のコンテキストが失われる恐怖感を与える。
2. 非同期イベントの罠: `ItemSend` 内でファイルをゴリゴリ操作しようとすると、OutlookのCOMオブジェクトが不安定になり、最悪の場合強制終了(フリーズ)を引き起こす。
我々が目指すべきは、「添付された瞬間(AttachmentAddイベント)にバックグラウンドでサイレントに容量を監視し、閾値を超えたらシームレスに本文と添付構造を書き換える」というリアクティブな設計だ。
—
2. 実装上の技術的ハードルと解決策
このツールを実装するにあたり、以下の3つの技術的壁を突破する必要がある。
- FileSystemObject (FSO) の正確なファイルサイズ取得:
添付された `Attachment` オブジェクトから直接正確なバイト数を取得するのは、Outlookの内部キャッシュ仕様上、危険が伴う。一度ローカルの一時領域(Temp)等に保存されている実体のパス(`Path`プロパティ)を特定し、FSO経由で正確なサイズを計測するのが鉄則だ。
- 本文(HTMLBody)の安全なパースと置換:
プレーンテキストではなく、現在のビジネスメールの主流であるHTMLメールに対して動的に文字列を挿入する場合、既存のHTML構造を破壊してはならない。署名の直上や本文の末尾を正規表現または特定のマーカーで安全に捉える必要がある。
- 無限ループの防止:
プログラムから添付ファイルを削除し、本文を書き換えるというアクションは、再びOutlookのイベントを誘発する可能性がある。フラグ管理によるイベントの排他制御が不可欠だ。
—
3. プロダクションコード:容量監視・URL置換エンジン
以下のコードは、Outlookの `ThisOutlookSession` モジュールに実装することを想定した、実戦投入可能なプロダクションコードである。
あらかじめ、組織内で利用しているファイル転送サービス(OneDrive, Box, GigaFile便など)のURLテンプレートを定数として定義しておく。
Option Explicit
‘ ==============================================================================
‘ 20年戦えるOutlook VBA: 添付ファイル容量動的制御エンジン
‘ Chief Architect Reviewed.
‘ ==============================================================================
‘ 許容する添付ファイルの合計上限(バイト単位)
‘ 例: 10MB = 10 1024 1024
Private Const MAX_ATTACHMENT_SIZE As Long = 10485760
‘ 容量超過時に挿入するファイル転送サービスのダミーURL(実環境に合わせて変更)
Private Const FILE_TRANSFER_URL_TEMPLATE As String = “
【自動通知】添付ファイルが容量制限を超過したため、以下の転送サービスにアップロードしてください。
アップロード用URL: https://example.com/upload?token=SECURE_TOKEN_SAMPLE
”
‘ イベントの多重発火を防ぐためのセマフォ(フラグ)
Private isProcessing As Boolean
‘ メールアイテムのイベントをフックするための宣言
Public WithEvents TargetMail As Outlook.MailItem
‘ 新規メール作成時や既存メールオープン時にイベントをバインド
Private Sub Application_NewMailEx(ByVal EntryIDString As String)
‘ 受信メールは対象外
End Sub
‘ メール作成ウィンドウが開いた際のフック(ThisOutlookSessionに記述する場合)
Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
‘ 送信時の最終防衛ライン
If TypeOf Item Is Outlook.MailItem Then
If CheckTotalAttachmentSize(Item) > MAX_ATTACHMENT_SIZE Then
Dim msg As String
msg = “添付ファイルの合計容量が制限(10MB)を超えています。” & vbCrLf & _
“自動的にURL置換処理を行うか、手動で容量を削減してください。”
MsgBox msg, vbCritical, “送信阻止 – 容量オーバー”
‘ ここで強制キャンセルする場合の処理
‘ Cancel = True
End If
End If
End Sub
実際のロジックを担うクラス/モジュール側コード
実際の業務では、メールアイテムごとのイベントを確実に捉えるため、インスペクターのオープンイベント等を活用する。以下は、アクティブなインスペクターの `MailItem` を監視する核心部分である。
‘ 添付ファイルが追加された瞬間に発火するイベント
‘ ※このコードは MailItem を WithEvents で宣言したクラスモジュールに配置するのがベストプラクティス
Public WithEvents MonitoredMail As Outlook.MailItem
Private Sub MonitoredMail_AttachmentAdd(ByVal Attachment As Outlook.Attachment)
If isProcessing Then Exit Sub
On Error GoTo ErrorHandler
isProcessing = True
Dim fso As Object
Set fso = CreateObject(“Scripting.FileSystemObject”)
Dim totalSize As Long
totalSize = 0
Dim att As Outlook.Attachment
Dim targetPath As String
‘ 1. 現在添付されているすべてのファイルのサイズを合算
For Each att In MonitoredMail.Attachments
‘ テンポラリに保存されているファイルのパスからサイズを取得
targetPath = att.PathName
If targetPath <> “” Then
If fso.FileExists(targetPath) Then
totalSize = totalSize + fso.GetFile(targetPath).Size
End If
End If
Next att
‘ 2. 制限を超過しているかの判定
If totalSize > MAX_ATTACHMENT_SIZE Then
‘ ユーザーへの警告
Dim message As String
message = “【警告】添付ファイルの合計容量が ” & Format(totalSize / 1048576, “0.00”) & ” MB となり、制限(10MB)を超過しました。” & vbCrLf & _
“すべての添付ファイルを自動削除し、本文にファイル転送サービスの案内を挿入します。”
MsgBox message, vbExclamation, “容量超過アラート”
‘ 3. 添付ファイルを逆順で削除(インデックスずれを防ぐため)
Dim i As Long
For i = MonitoredMail.Attachments.Count To 1 Step -1
MonitoredMail.Attachments.Item(i).Delete
Next i
‘ 4. 本文がHTML形式かPlain形式かで分岐してURLを挿入
If MonitoredMail.BodyFormat = olFormatHTML Then
MonitoredMail.HTMLBody = FILE_TRANSFER_URL_TEMPLATE & MonitoredMail.HTMLBody
Else
MonitoredMail.Body = “【自動通知】添付ファイルが容量制限を超えたため削除されました。” & vbCrLf & _
“以下のURLを使用してください: https://example.com/upload?token=SECURE_TOKEN” & vbCrLf & vbCrLf & _
MonitoredMail.Body
End If
‘ 変更を保存
MonitoredMail.Save
End If
CleanUp:
isProcessing = False
Set fso = Nothing
Exit Sub
ErrorHandler:
MsgBox “容量チェック中に予期せぬエラーが発生しました: ” & Err.Description, vbCritical
Resume CleanUp
End Sub
Private Function CheckTotalAttachmentSize(mail As Outlook.MailItem) As Long
Dim fso As Object
Set fso = CreateObject(“Scripting.FileSystemObject”)
Dim totalSize As Long: totalSize = 0
Dim att As Outlook.Attachment
For Each att In mail.Attachments
If att.PathName <> “” Then
If fso.FileExists(att.PathName) Then
totalSize = totalSize + fso.GetFile(att.PathName).Size
End If
End If
Next att
CheckTotalAttachmentSize = totalSize
Set fso = Nothing
End Function
—
4. 運用上の注意点とアーキテクトからの助言
このツールを現場に展開するにあたり、以下のポイントを必ず押さえておいてほしい。
1. セキュリティソフトとの競合:
強力なアンチウイルスソフトが導入されている環境では、`Attachment.PathName` を参照した瞬間にファイルスキャンが走り、わずかなロック競合(Permission Denied)が発生することがある。これを回避するため、ファイルアクセス時には必ず `On Error Resume Next` を適切に挟むか、リトライロジックを入れるのがプロの技だ。
2. デジタル署名(マクロの署名):
企業のセキュリティポリシーにおいて、野良マクロは即座にブロックされる。必ず社内のルート証明書または自己署名証明書(SelfCert)を用いてVBAプロジェクトに署名を行い、グループポリシー(GPO)等で信頼できる発行元として配布すること。
3. ユーザーへの事前アナウンス:
ファイルを添付した瞬間に「勝手にファイルが消えてURLに置き換わった」となると、リテラシーの低いユーザーはパニックを起こす。必ずツール導入の意図(サーバー保護と大容量送受信の円滑化)を説明し、ポップアップメッセージの文言も自社のポリシーに合わせて最適化してほしい。
—
総括
システム開発の本質は、「人のミスをカバーする仕組み」をいかにエレガントに構築するかにある。
今回紹介した「添付ファイルの動的容量制御」は、単なるコードのテクニックに留まらず、メールというインフラのボトルネックをスマートに解消するアーキテクチャそのものだ。
君たちの現場でも、この知見をベースに堅牢な自動化ツールを組み上げ、無駄なトラブルを根絶してほしい。さらなる高みを目指す健闘を祈る。
