【実務・中級編】【中級者向け】メール送信時に添付ファイルの合計容量を計算し、制限を超える場合にファイル転送サービスURLを挿入する警告機能 – Outlook VBA解析バイブル

スポンサーリンク

Outlook VBAを掌握する極限の知見:添付ファイル容量オーバーを「未然に防ぐ」動的インターセプト機構の構築

プロフェッショナルな現場において、メール誤送信や情報漏洩の多くは「うっかり」から発生する。その代表格が、規定サイズを超える大容量ファイルの添付によるメールサーバーのパンク、あるいは誤った宛先への機密データ送信だ。

多くの開発者は、`MailItem.Send` イベントの中で単純にサイズを比較し、エラーメッセージを出すだけの幼稚な実装で満足している。しかし、チーフアーキテクトである我々が目指すべきは、ユーザーのストレスを最小限に抑えつつ、システム側でシームレスに代替手段(クラウドストレージ等のURL)へ誘導するスマートなインターセプト機構だ。

今回は、実務の現場で即座に稼働させられる、堅牢で拡張性の高い「添付ファイル容量動的制御ソリューション」を伝授する。

—

1. なぜ「単純なSendイベント処理」では実務で破綻するのか?

初心者がやりがちな設計ミスは、`ItemSend` イベント内でファイルのバイト数を取得し、制限を超えていたら `Cancel = True` で処理を中断する方法だ。

このアプローチには、以下の致命的な欠陥がある。
1. ユーザー体験の著しい低下: 送信ボタンを押した瞬間に「容量オーバーです」と突き放されるだけで、具体的な代替案(URL化の案内など)が提示されない。
2. オブジェクトライフサイクルの無視: `ItemSend` 内でHTMLボディを書き換えてURLを挿入しようとすると、Outlookの内部レンダリングとの競合により、稀にメール本文が文字化けしたり、添付ファイルが消え残ったりする異常系バグを引き起こす。

我々は、「添付ファイルが追加・削除された瞬間、あるいは送信直前のバリデーション層」において、FSO(FileSystemObject)を駆使した厳密なサイズ計算を行い、HTMLボディを動的に書き換えるアーキテクチャを採用する。

—

2. アーキテクチャの全体像と設計方針

今回のモジュール群は、以下の要件を満たすよう設計している。

  • 上限閾値の動的設定: 標準的な組織ポリシーである「10MB(10,485,760バイト)」を基準としつつ、将来の拡張に備えて定数化。
  • FSOによる正確なバイト数計測: Outlookの `Attachment.Size` プロパティは、セッション状態やエンコード方式によって稀に正確な値をとらないことがあるため、実ファイルパスが存在する場合は `FileSystemObject` を用いて物理バイト数を担保する。
  • スマートフォールバック: 制限を超過した場合、添付ファイルを自動的に(あるいはユーザーの選択により)外し、本文を指定のファイル転送サービスURLフォーマットに置き換える。

—

3. 【プロダクションコード】コピペで即座に導入できる堅牢モジュール

以下のコードを、OutlookのVBAエディタ(`ThisOutlookSession` または標準モジュール)に実装せよ。

Option Explicit

‘ ==============================================================================
‘ 組織標準 添付ファイル容量制御エンジン v2.5
‘ Architected by Chief Technical Officer
‘ ==============================================================================

‘ 許容する最大添付ファイルサイズ(バイト単位: ここでは 10MB)
Private Const MAX_TOTAL_SIZE As Long = 10485760

‘ 社内指定のファイル転送サービス用ベースURL
Private Const FILE_TRANSFER_BASE_URL As String = “https://storage.example.com/share/?token=”

Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
On Error GoTo ErrorHandler

‘ 対象がメールアイテム以外(会議予定やタスクなど)の場合はスルー
If Not TypeOf Item Is MailItem Then Exit Sub

Dim mail As MailItem
Set mail = Item

Dim totalSize As Long
totalSize = CalculateAttachmentSize(mail)

‘ ログ出力(必要に応じてDebug.PrintをAPIロギング等に置き換え)
Debug.Print “Current Attachment Total Size: ” & totalSize & ” bytes”

‘ 閾値を超過している場合のインターセプト処理
If totalSize > MAX_TOTAL_SIZE Then
Dim msg As String
msg = “【警告】添付ファイルの合計サイズが組織の送信制限(10MB)を超えています。” & vbCrLf & _
“現在のサイズ: ” & Format(totalSize / 1024 / 1024, “0.00”) & ” MB” & vbCrLf & vbCrLf & _
“送信を続行しますか?” & vbCrLf & _
“「はい」を選択すると、ファイルが削除され、自動的にファイル転送サービス用URLが本文に挿入されます。” & vbCrLf & _
“「いいえ」を選択すると送信をキャンセルします。”

Dim answer As VbMsgBoxResult
answer = MsgBox(msg, vbYesNo + vbExclamation + vbDefaultButton2, “容量超過セキュリティ警告”)

If answer = vbYes Then
‘ 添付ファイルを削除し、URLを本文にインジェクションする
Call ConvertAttachmentsToUrl(mail)
Else
‘ ユーザーが送信を中止
Cancel = True
Exit Sub
End If
End If

Exit Sub

ErrorHandler:
MsgBox “添付ファイル容量チェック中に予期せぬエラーが発生しました。” & vbCrLf & _
Err.Description, vbCritical, “System Error”
Cancel = True
End Sub

‘ ——————————————————————————
‘ 添付ファイルの合計サイズを正確に算出する(FSO併用版)
‘ ——————————————————————————
Private Function CalculateAttachmentSize(ByVal mail As MailItem) As Long
Dim total As Long
total = 0

If mail.Attachments.Count = 0 Then
CalculateAttachmentSize = 0
Exit Function
End If

Dim fso As Object
Set fso = CreateObject(“Scripting.FileSystemObject”)

Dim att As Attachment
Dim i As Long

For i = 1 To mail.Attachments.Count
Set att = mail.Attachments(i)

‘ 埋め込み画像(OLEDATA等)を除外するため、Typeをチェック
‘ olByValue (1) が通常の添付ファイル
If att.Type = olByValue Then
On Error Resume Next
‘ パスが取得できる場合(ドラッグ&ドロップやファイル選択直後)はFSOで実測
Dim filePath As String
filePath = att.PathName

If filePath <> “” And fso.FileExists(filePath) Then
total = total + fso.GetFile(filePath).Size
Else
‘ パスが取れない(一時フォルダ等に格納済み)場合はAttachment.Sizeを使用
total = total + att.Size
End If
On Error GoTo 0
End If
Next i

CalculateAttachmentSize = total
End Function

‘ ——————————————————————————
‘ 添付ファイルを除去し、ダウンロード用URLをHTMLボディに付与する
‘ ——————————————————————————
Private Sub ConvertAttachmentsToUrl(ByVal mail As MailItem)
Dim fso As Object
Set fso = CreateObject(“Scripting.FileSystemObject”)

Dim fileNames As String
fileNames = “”

‘ 逆順ループで安全に添付ファイルを削除
Dim i As Long
For i = mail.Attachments.Count To 1 Step -1
If mail.Attachments(i).Type = olByValue Then
fileNames = fileNames & “・” & mail.Attachments(i).DisplayName & “
”
mail.Attachments(i).Delete
End If
Next i

‘ 一意のダミー・トークンを生成(実際の運用ではAPI経由でアップロード処理をここに挟む)
Dim dummyToken As String
dummyToken = “SECURE-” & Format(Now, “yyyymmddhhnnss”) & “-” & Int((9999 – 1000 + 1) Rnd + 1000)

Dim generatedUrl As String
generatedUrl = FILE_TRANSFER_BASE_URL & dummyToken

‘ 本文がHTML形式かプレーンテキスト形式かで処理を分岐
If mail.BodyFormat = olFormatHTML Then
Dim htmlAddition As String
htmlAddition = “


【自動セキュリティシステム通知】
” & _
“以下の大容量添付ファイルは容量制限を超過したためサーバーから分離されました。
” & _
“以下のURLよりダウンロードしてください。
” & _
“対象ファイル:
” & fileNames & _
“ダウンロードURL: ” & generatedUrl & “


”

mail.HTMLBody = htmlAddition & mail.HTMLBody
Else
‘ プレーンテキストの場合はHTMLに強制変換するかテキストで追記
mail.BodyFormat = olFormatHTML
mail.HTMLBody = “

[自動通知] 添付ファイルがURL化されました: ” & generatedUrl & “
” & mail.HTMLBody
End If
End Sub

—

4. チーフアーキテクトが教える実装上の急所とチューニング

このコードをデプロイするにあたり、現場のエンジニアが押さえておくべき「実務の急所」を解説する。

1. 逆順ループ (`Step -1`) によるコレクション破壊の回避
`mail.Attachments` のようなCOMコレクション要素を削除していく際、正順(1からCountまで)でループを回すとインデックスがズレて必ず「要素が見つかりません」というランタイムエラーを引き起こす。コレクションの削除は必ず末尾からの逆順(Step -1)で行うこと。これがVBA開発における鉄則だ。

2. 埋め込み画像(CID添付)の誤爆防止
HTMLメール内に署名として画像が埋め込まれている場合、これらも `Attachments` コレクションに含まれる。これらを容量計算の対象に含めると、意図しない誤作動を起こす。コード内の `If att.Type = olByValue Then` は、まさにこの誤爆を防ぐための防壁である。

3. ファイル転送APIとの連携拡張性
今回のサンプルコードでは、URLのトークン部分を擬似的に生成しているが、実運用においては `ConvertAttachmentsToUrl` プロシージャの内部で HTTPリクエスト(MSXML2.ServerXMLHTTP 等) を発火させ、社内のファイルストレージAPIにファイルをアップロード、返却された実URLを `generatedUrl` に代入するよう拡張してほしい。これによって完全な自動化が達成される。

—

5. 結びにかえて

業務自動化において、マクロは「動けばいい」というものではない。例外系を網羅し、ユーザーのうっかりミスをシステムが優しく、かつ強固にカバーするデザインこそが、プロフェッショナルが書くコードの条件である。

このモジュールをあなたの組織に導入し、メール容量起因のトラブルを根絶せよ。技術の力で、現場の生産性はさらに上のステージへと引き上げられるはずだ。

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