こんにちは!Outlook VBAの世界へようこそ。
マクロの記録から一歩踏み出し、「自分の手でOutlookを自在にコントロールしたい」と思い始めたあなたへ。
今回は、業務自動化エンジニアとして現場で何度も救われてきた、「送信直前のメールを自動チェックし、不適切な場合は送信をキャンセルする」という極上のテクニックを授けましょう。
「うっかり機密情報を社外に送りそうになった」「宛先を間違えて冷や汗をかいた」……そんなヒヤリハットを、VBAの力で完全に根絶します。ここをクリアすれば、あなたのOutlook VBAスキルは間違いなく中級者の領域に到達します。一緒にマスターしていきましょう!
—
なぜ「送信時」のフック(イベント)が必要なのか?
私たちが日々使っているOutlookには、ユーザーが「送信」ボタンを押した瞬間に、裏側でこっそり割り込んで処理を実行してくれる特別な仕組み(イベント)が用意されています。
通常のVBAマクロは「ボタンを押したら動く」ものですが、今回使うのは「Outlookが特定のタイミングで自動的に呼び出してくれる特別なプロシージャ」です。
Application_ItemSend イベントの正体
Outlookがメールを送信しようとすると、OSの裏側で `Application.ItemSend` というイベントが発生します。このイベントの優秀なところは、「送信処理のまさに一歩手前で、メールのオブジェクトを私たちに引き渡してくれる」点です。
ここで私たちが「よし、このメールはOK!」と太鼓判を押せばそのまま送信され、「待て、この宛先は危ない!」と判断すれば、送信を完全に中止(キャンセル)させることができるのです。
—
現場で使える!送信キャンセル・ガードシステムの全体像
それでは早速、実際のコードを見てみましょう。
このコードは、一般的な解説サイトにあるような断片的なものではありません。実務の現場で耐えうるよう、エラーハンドリングと実践的なチェックロジックを組み込んだ「生きたコード」です。
1. 準備:イベントを司る「ThisOutlookSession」
まず大前提として、この手のイベントマクロは、標準モジュール(「標準モジュール1」など)ではなく、必ず`ThisOutlookSession`(このOutlookセッション)という特別な場所に書く必要があります。
ここが初心者が一番ハマりやすいポイントです。プロジェクトエクスプローラーにある `ThisOutlookSession` をダブルクリックし、以下のコードをそのまま貼り付けてください。
‘ ====================================================================
‘ チーフアーキテクトが贈る:送信前メール検証&ガードシステム
‘ ====================================================================
Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
On Error GoTo ErrorHandler
‘ 1. 処理対象の選別(MailItem以外、例えば予定表の送信などをスルーする)
If TypeName(Item) <> “MailItem” Then Exit Sub
Dim mail As MailItem
Set mail = Item
‘ ====================================================================
‘ 【検証ロジック 1】社外宛ての「秘密」チェック
‘ ====================================================================
‘ 例:件名に「【社外秘】」と入っているのに、宛先に社外ドメインが含まれている場合
If InStr(mail.Subject, “【社外秘】”) > 0 Then
If HasExternalRecipient(mail) Then
Dim answer As VbMsgBoxResult
answer = MsgBox(“【警告】社外秘メールに外部ドメインの宛先が含まれています!” & vbCrLf & _
“本当にこのまま送信しますか?”, _
vbYesNo + vbCritical + vbDefaultButton2, _
“送信前セキュリティチェック”)
‘ 「いいえ」が選ばれたら送信をキャンセル
If answer = vbNo Then
Cancel = True
MsgBox “送信をキャンセルしました。”, vbInformation, “キャンセル完了”
Exit Sub
End If
End If
End If
‘ ====================================================================
‘ 【検証ロジック 2】添付ファイル忘れの防止
‘ ====================================================================
‘ 例:本文に「添付」という言葉があるのに、添付ファイルが0個の場合
If (InStr(mail.Body, “添付”) > 0) Or (InStr(mail.Body, “添付ファイル”) > 0) Then
If mail.Attachments.Count = 0 Then
Dim ansAttach As VbMsgBoxResult
ansAttach = MsgBox(“本文に「添付」というワードがありますが、ファイルが添付されていません。” & vbCrLf & _
“本当に送信してもよろしいですか?”, _
vbYesNo + vbExclamation + vbDefaultButton2, _
“添付ファイル忘れチェック”)
If ansAttach = vbNo Then
Cancel = True
MsgBox “送信をキャンセルしました。ファイルを追加してください。”, vbInformation, “キャンセル完了”
Exit Sub
End If
End If
End If
‘ すべての関門をクリアした場合、メールは無事に送信されます
Exit Sub
ErrorHandler:
‘ 予期せぬエラーで業務が止まらないためのフェイルセーフ
MsgBox “送信前チェックマクロでエラーが発生しました。” & vbCrLf & _
“エラー内容: ” & Err.Description, vbCritical, “システムエラー”
‘ 安全のため、エラー時は誤送信を防ぐために念のためキャンセルする設計もアリですが
‘ 今回は業務停止を避けるためスルー(必要に応じて Cancel = True にしてください)
End Sub
‘ ====================================================================
‘ 補助関数:外部ドメインが含まれているかを判定する関数
‘ ====================================================================
Private Function HasExternalRecipient(ByVal mail As MailItem) As Boolean
Dim recip As Recipient
Dim isExternal As Boolean
isExternal = False
‘ 自社ドメインの定義(ご自身の環境に合わせて書き換えてください)
Const MY_DOMAIN As String = “@yourcompany.co.jp”
For Each recip In mail.Recipients
‘ 宛先(To), CC, BCC すべてを走査
‘ ※ Exchange環境等のSMTPアドレス解決の特性を考慮
Dim smtpAddress As String
On Error Resume Next
smtpAddress = recip.PropertyAccessor.GetProperty(“http://schemas.microsoft.com/mapi/proptag/0x39FE001E”)
On Error GoTo 0
If smtpAddress = “” Then smtpAddress = recip.Address
‘ 自社ドメインが含まれていないアドレスを発見した場合
If InStr(LCase(smtpAddress), LCase(MY_DOMAIN)) = 0 Then
isExternal = True
Exit For
End If
Next recip
HasExternalRecipient = isExternal
End Function
—
コードの核心を読み解く:3つの重要ポイント
このコードがなぜ優れているのか、エンジニアの視点から3つのポイントに絞って解説します。
1. `Cancel As Boolean` という魔法の引数
イベントプロシージャの引数にある `ByVal Item As Object, Cancel As Boolean` に注目してください。
この `Cancel` という変数に `True` を代入してプロシージャを抜けると、Outlookは「あ、送信をやめるんだな」と理解し、メールの送信処理をその場でピタッと止めてくれます。
メール画面は開いたまま(下書き状態)保持されるため、ユーザーは宛先や添付ファイルを直して、再度送信ボタンを押すことができるのです。
2. 「MailItem」かどうかの厳密な型チェック
Outlookでは、メールだけでなく「予定表(会議出席依頼)」や「連絡先」を送信することもあります。
もし、会議の招待を送信したときに `mail.Subject` や `mail.Body` なんてプロパティを叩こうものなら、型不一致エラー(オブジェクトは、このプロパティまたはメソッドをサポートしていません)でマクロがクラッシュします。
`If TypeName(Item) <> “MailItem” Then Exit Sub` というガードを最初に置くことで、予期せぬオブジェクトによる爆発を防いでいるのです。
3. 自社ドメイン判定のリアリティ(MAPIプロパティの活用)
外部宛てチェックで使用している `HasExternalRecipient` 関数を見てください。単に `recip.Address` を見るだけでは、アドレス帳から選んだ内部ユーザーの場合に内部ID(EX形式)が返ってきてしまい、正しくドメイン判定ができません。
`PropertyAccessor` を使ってSMTPアドレスを強制的に引き抜くロジックを入れている点が、現場で本当に使えるプロの技です。
—
初学者が必ずハマる「罠」と回避策
最後に、このカスタマイズを導入する際につまずきがちなポイントを先回りして解決しておきましょう。
- Q. マクロが全く反応しないのですが?
- A. セキュリティ設定を確認してください。
Outlookのマクロが無効化されている可能性が高いです。「ファイル」>「オプション」>「トラスト センター」>「トラスト センターの設定」>「マクロの設定」から、「すべてのマクロを実行可能にする(推奨しませんがテスト時はこれ)」または「デジタル署名されたマクロ…」等に設定し、Outlookを再起動してください。
- Q. コードを書いたのに動かない!
- A. 書く場所を確認してください。
標準モジュールではなく、必ずプロジェクトツリーにある `ThisOutlookSession` に書いていますか? `Application_` で始まるイベントプロシージャは、専用の場所に書かないとイベントをフックしてくれません。
—
おわりに
今回マスターした `Application_ItemSend` による送信キャンセルは、単なる「うっかり防止」にとどまりません。
企業のコンプライアンス遵守、情報漏洩の防止、そして何よりあなた自身の「業務ストレスの軽減」に直結する強力な武器です。
ここをクリアできれば、Outlook VBAの基本はもうバッチリです。
ぜひご自身の環境にこのコードを組み込み、快適で安全な自動化ライフを手に入れてください。それでは、次回の極限の知見でお会いしましょう!
