RPA や Excel マクロなどで Outlook オブジェクト モデルを使用して MailItem の Send メソッドによりメールを送信した際に、メールが送信されずに送信トレイに滞留したままの状態となる場合があります。
これは以下のような条件で発生します。
- メールを送信する際に Outlook が起動していない
- インターネット アカウントを使用しているか、Exchange アカウントでキャッシュ モードを有効にしている
- Send メソッドで送信した後、すぐに Outlook のオブジェクトを開放している
- メールサイズが大きかったり、一度に複数のメールを送信するなど、送信処理に時間がかかる状況である
上記の条件でメールが送信されない場合があるのは、Outlook の送信処理が以下のような順序で行われるためです。
- Send メソッドが実行されると、メールが送信トレイに保存され、送信のためのバックグラウンド タスクが起動される
- バックグラウンド タスクにより送信が実行される
- 送信が完了すると送信トレイのメールが送信済みアイテムに移動される
上記の 1. の処理が完了すると、それ以降の処理が行われる前に呼び出し元に制御が戻ります。
そして、呼び出し元のアプリケーションなどが直後に Outlook のオブジェクトを開放すると、Outlook 上では誰も Outlook を利用していない状態になります。
この状態になると、Outlook はバックグラウンド タスクが完了次第終了するのですが、何らかの理由でメール送信のタスクが起動していなかったり、複数のタスクの合間で実行中のタスクがない状況になると送信前のメールがあっても Outlook は終了します。
その結果、マクロなどでの送信が完了しても実際にはメールが送信されず、次に Outlook が起動されたタイミングで送信が行われるということになります。
これを回避するには、Outlook でメールの送信が完了したことを確認するまで、Outlook のオブジェクトを参照し続ける必要があります。
メールの送信が完了したかどうか判断する方法としては、送信トレイのアイテム数が 0 になるのを待つというものが考えられるでしょう。
appOlk という変数に Outlook.Application オブジェクトが格納されている場合に送信完了を待つ Excel VBA のサンプル コードは以下の通りです。
なお、サーバーやネットワークの問題などにより送信処理がいつまでも完了しない場合を考慮し、60 秒待っても送信トレイのアイテム数が 0 にならなければエラー表示するようにしています。
Dim fldOutbox As Object
Dim dtStart As Date
Dim bAbort As BooleanSet fldOutbox = appOlk.Session.GetDefaultFolder(4) ' 4 = olFolderOutbox
dtStart = Now
bAbort = False
While fldOutbox.Items.Count > 0 And Not bAbort
' Send メソッド実行から 60 秒以上経過していたら待つのをやめる
If DateDiff("s", dtStart, Now) > 60 Then
bAbort = True
End If
' 送信トレイにアイテムが残っていたら 5 秒待つ
Application.Wait (Now + TimeValue("00:00:05"))
Wend
'
If bAbort Then
MsgBox "送信処理が完了しませんでした。Outlook を起動して送信トレイを確認してください。"
End If