会議出席依頼を遅延配信すると発生する問題について

誤送信対策のため、Outlook の送信ルールの遅延配信設定やアドインにより、メールの送信を数分保留するというような運用をされている方は多いと思います。
その際、メールだけでなく会議出席依頼にも遅延配信が設定されるようになっているかもしれませんが、その場合に送信トレイの会議出席依頼を開いてしまうと以下のような事象が発生します。

  • 送信トレイの会議出席依頼を開くと、その会議出席依頼が送信トレイから削除される
  • 削除済みアイテムに移動された会議出席依頼を送信トレイに移動しても送信されない
  • 会議出席依頼が削除されてしまった会議については会議の更新しか送信できなくなるが、それを送信しても出席者側では正しく処理できない

これは、会議出席依頼の特殊な動作によって発生します。

Outlook の会議出席依頼は、元になる予定表上の会議アイテムが必要となり、単独では存在できません。
そして、会議出席依頼自体の変更などは想定されておらず、何らかの変更が必要な場合は会議アイテムを変更することになります。
そのため、送信トレイの会議出席依頼を開くと、その会議出席依頼自体ではなく元になった会議アイテムが開かれ、送信トレイの会議出席依頼は削除されるという動作になります。

このような事象を回避するためには会議出席依頼については遅延配信をさせないという運用をする必要があります。
例えば、自動仕分けの送信時のルールで遅延配信を設定している場合であれば、例外条件として [会議出席依頼または会議の更新である場合を除く] を追加します。
また、マクロやアドインなどであれば、MessageClass が IPM.Schedule で始まるアイテムについては遅延配信を設定しないというものが考えられます。

アイテムの種別にかかわらず To や Cc を取得するための関数

コメントにて以下のご要望をいただきました。


お世話になります。
毎日の仕事の振り返りのヒントとして、Outlookから発信したメール、開催通知等(以後メール等と表記)を記録に残しておきたいと思っています。
以前は「ジャーナル」機能があったのでそれを使っていたのですが、現在では自動的に記録する機能がありません。

そこで、メール等がSentOnになったらExcelのファイルに追記していくOutlookVBAマクロを作ってみました。
———————–8<———————–8<———————–
Option Explicit

Dim WithEvents mySentItems As Items ‘ ItemAdd イベントをハンドルするオブジェクト

‘ Outlook 起動時に実行されるイベント
Private Sub Application_Startup()
  Set mySentItems = Session.GetDefaultFolder(olFolderSentMail).Items ‘ 送信済みアイテム フォルダーへのアイテム追加をハンドルするためのオブジェクト設定
End Sub

‘ 送信済みアイテムに移ってきたメッセージの情報をExcelファイルに追記する処理
Private Sub mySentItems_ItemAdd(ByVal Item As Object)
  Dim excelApp As Object ‘ Excelオブジェクトの作成
  Set excelApp = CreateObject(“Excel.Application”)
  Dim workbook As Object ‘ Excelファイルを開く
  Set workbook = excelApp.Workbooks.Open(“C:Users********送信ログ.xlsx”)
  Dim sheet As Object ‘ 追記するシートを選択
  Set sheet = workbook.Sheets(“送信ログ”)
  Dim lastRow As Long lastRow = sheet.Cells(sheet.Rows.Count, 1).End(-4162).Row ‘ 最終行を取得 ‘ データを追記
  sheet.Cells(lastRow + 1, 1).Value = Format(Item.SentOn, “yyyy/mm/dd hh:mm:ss”)
  sheet.Cells(lastRow + 1, 2).Value = Item.To
  sheet.Cells(lastRow + 1, 3).Value = Item.subject
  workbook.Save ‘ Excelファイルを保存
  workbook.Close ‘ Excelファイルを閉じる
  Set sheet = Nothing ‘ Excelオブジェクトを解放
  Set workbook = Nothing
  Set excelApp = Nothing

End Sub
———————–8<———————–8<———————–
上記のマクロはメールを送信したときは問題なく機能しますが、会議開催通知などの場合は
Item.To
のところでエラーになります。
(送信済フォルダに入ってくるのはメールだけとは限らないからだと思いますが)

送信したメール等はすべて記録しておきたいので、どのように修正すればよいでしょうか。
よろしくご教授ください


To プロパティと Cc プロパティについては、MailItem オブジェクトでのみ使用できるものです。
そのため、会議出席依頼に相当する MeetingItem オブジェクトでこれらのプロパティを取得しようとするとエラーとなります。
To や Cc をサポートしないオブジェクトでも、Recipients プロパティからあて先情報が取得できるので、これをもとに To や Cc の文字列を生成することでご要望は満たせるでしょう。
以下の関数は引数 objItem で指定されたメールなどのアイテムから lType で指定された種類の受信者すべての表示名を取得するものです。

Private Function GetToCc(ByVal objItem As Object, lType As Long)
     Dim strNames As String
     Dim objRec As Recipient
     strNames = ""
     For Each objRec In objItem.Recipients
         If objRec.Type = lType Then
             strNames = strNames & objRec.Name & "; "
         End If
     Next
     ' 余計な最後の ; を削除
     If strNames <> "" Then
         strNames = Left(strNames, Len(strNames) - 2)
     End If
     GetToCc = strNames
End Function

例えば、

    sheet.Cells(lastRow + 1, 2).Value = Item.To

としている個所を、

    sheet.Cells(lastRow + 1, 2).Value = GetToCc(Item, olTo)

のようにすることで、メール以外のアイテムでもエラーを発生させることなくあて先情報が取得できます。

受信トレイの返信済みメールをアーカイブ フォルダーに移動するマクロ

未返信のメールを別のフォルダーに移動するマクロ のコメントにて以下のご要望をいただきました。


はじめまして。Outlookで相手のメールに返信した時に返信した元のメールを自動でアーカイブするマクロを作りたいのですが、同じように以下のプロパティをチェックすれば作成可能でしょうか?

PR_ICON_INDEX (メッセージ一覧で表示するアイコンの指定) が 261 (返信アイコン) に変わる

PR_LAST_VERB_EXECUTED (メッセージに対して最後に実行された処理) が 102 (差出人に返信) または 103 (全員に返信) に変わる

当方、送信済みメールも受信ボックスにコピーされるように設定しており、受信ボックスの中を「送信済みメールのコピー=返信待ちメールもしくは自分のメールで終わったメール」「受信メール(未返信)=要返信もしくは相手のメールで終わったメール」のみにするのが目的です。

自分が返信したメールを受信ボックスにコピーするので、返信元のメールはアーカイブに送りたいと考えております。ご助言いただけると助かります。


自分が返信したメールを確認するのであれば PR_ICON_INDEX などでも確認はできますが、これだけだと相手が返信してきたメールが判断できず、「送信済みメールのコピー=返信待ちメールもしくは自分のメールで終わったメール」が実現できないと思われます。
Outlook オブジェクト モデルでは、Conversation オブジェクトを使用してメールのスレッドのツリーを確認できるので、件名が RE: で始まるメールの親 (返信元) のメールをアーカイブに移動するという処理を行えば、ご要望は満たせると思います。
マクロは以下の様になります。

Public Sub ArchiveOldItemInThreads()
     Dim fldInbox As Folder
     Dim fldArchive As Folder
     Dim colItems As Items
     Dim objConv As Conversation
     Dim curItem As Object
     Dim prevItem As Object
     Dim i As Integer
     ' 受信トレイの取得
     Set fldInbox = Session.GetDefaultFolder(olFolderInbox)
     ' アーカイブ フォルダーの取得
     Set fldArchive = fldInbox.Parent.Folders("アーカイブ")
     ' 受信トレイのアイテムを受信日時の降順で並び替え
     Set colItems = fldInbox.Items
     colItems.Sort "ReceivedTime", True
     ' アイテムを一つずつチェック
     For i = fldInbox.Items.Count To 1 Step -1
         Set curItem = fldInbox.Items(i)
         ' 件名が RE: で始まる場合はスレッドのチェック
         If UCase(curItem.Subject) Like "RE:*" Then
             ' Conversation オブジェクトを取得
             Set objConv = curItem.GetConversation()
             ' Conversation より返信元のメールを取得
             Set prevItem = objConv.GetParent(curItem)
             ' 返信元メールが見つかったら
             If Not prevItem Is Nothing Then
                 ' 既にアーカイブ フォルダーに移動されていなければ
                 If prevItem.Parent <> fldArchive Then
                     ' アーカイブ フォルダーに移動
                     prevItem.Move fldArchive
                 End If
             End If
         End If
     Next
End Sub

マクロの登録方法やメニューへの追加について

Outlook アドインの有効・無効に関連するレジストリ

Outlook では、アドインの有効・無効に関連する様々なレジストリがあり、それぞれ用途が異なります。
そのため、用途が異なるレジストリを誤って使用すると、想定した結果が得られないことになります。
今回は、優先度が高い順にそれぞれの用途を説明します。

1.ポリシーの AddinList


キー:
HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\16.0\Outlook\Resiliency\AddinList

名前:
アドインの ProgID

種類:
REG_SZ

値:
0 = 無効、1 = 有効、2 = ユーザー設定

用途:
管理者が特定のアドインの有効化または無効化を強制したいときに使用します。
このレジストリで設定を行うとユーザーが有効・無効の変更ができなくなるため、最も優先順位が高いといえます。
ただし、キーとしては HKEY_LOCAL_MACHINE で設定はできず、あくまでもユーザー単位のポリシーで設定するものとなります。
なお、設定する値が数値ですが、値の種類が REG_SZ となる点に注意が必要です。
また、DLL ファイルの破損やレジストリ設定の不備、アドイン自体の不具合などの理由でアドインの読み込みが失敗する場合、このレジストリで有効化を強制してもアドインを有効にすることはできません。

2.HKEY_CURRENT_USER の DisabledItems と CrashingAddinList


キー 1:
HKEY_CURRENT_USER\Software\Microsoft\Office\16.0\Outlook\Resiliency\DisabledItems

キー 2:
HKEY_CURRENT_USER\Software\Microsoft\Office\16.0\Outlook\Resiliency\CrashingAddinList

名前:
8 桁のランダムな 16 進数

種類:
REG_BINARY

値:
アドインの DLL のパスを含むバイナリデータ

用途:
Outlook がアドインの実行によるクラッシュやロードの失敗などを検知して無効化した場合に、無効化したアドインの情報を保存するために使用します。
上記のレジストリに登録されているアドインについては、Outlook の正常な動作を保つため、後述の LoadBehavior で 3 が指定されていても、アドインは無効となります。

3.HKEY_CURRENT_USER の LoadBehavior


キー:
HKEY_CURRENT_USER\Software\Microsoft\Office\Outlook\Addins

名前:
アドインの ProgID

種類:
REG_DWORD

値:
0-2 = 無効、3  = 有効

用途:

ユーザーが指定したアドインの起動時の読み込みを行うかどうかの設定です。
ユーザー単位でインストールされたアドインにはもともとキーが存在しており、インストール時に値が設定されます。
一方、マシン単位でインストールされたアドインでも、ユーザーがアドイン設定のダイアログで有効・無効の設定を変更すると、こちらの LoadBehavior が設定され、この設定が HKEY_LOCAL_MACHINE の設定より優先されます。

4.HKEY_LOCAL_MACHINE の LoadBehavior


キー:
HKEY_LOCAL_MACHINE\Software\Microsoft\Office\Outlook\Addins

名前:
アドインの ProgID

種類:
REG_DWORD

値:
0-2 = 無効、3  = 有効

用途:

マシン単位でインストールされたアドインの起動時の読み込み設定の初期値です。
アドインのインストーラーで設定されますが、前述の通りユーザーで設定が変更されると HKEY_CURRENT_USER に設定が行われ、そちらが優先されます。
そのため、この設定でアドインの有効・無効を管理者が制御することはできません。

5.HKEY_CURRENT_USER の DoNotDisableAddinList


キー:
HKEY_CURRENT_USER\Software\Microsoft\Office\16.0\Outlook\Resiliency\DoNotDisableAddinList

名前:
アドインの ProgID

種類:
REG_DWORD

値:
アドインが無効になった理由を示す値

用途:

Outlook により自動的に無効化されたアドインについて、ユーザーが無効化しないよう指定するものです。
この設定は DisabledItems に設定されたアドインでも有効にすることができるので、その点に関しては優先度が高いといえます。
しかし、ユーザーが意図的に無効化し、LoadBehavior が 0 や 2 になっている場合は、その設定が優先されてアドインが無効になります。
つまり、あくまでもユーザーが設定することを目的としているものであり、管理者がこの設定でアドインの有効化を強制することはできません。
無効化されたアドインを有効化するためのレジストリとして紹介されていることもあるため、このレジストリを展開してアドインの有効化を強制しようと考えてしまうこともあるかと思いますが、前述の通り管理者がアドインの有効化を強制するためには AddinList というレジストリ設定があり、DoNotDisableAddinList を使用するのは不適切かつ不十分です。
また、設定する値によっては、ユーザーに対して「このアドインにより Outlook の起動が遅くなりました。」のように、実際には発生していない事象が発生したかのように表示されるため、ユーザーの不安を煽る可能性があります。

Copilot が使用できない Outlook

今月から Microsoft 365 Apps の Outlook でも Copilot が使用できるようになりました。
ただ、使用できるチャネルには制限があり、半期エンタープライズ チャネルでは使用できません。
通常、Outlook に新機能が追加された場合、半期エンタープライズ チャネルには半年以上遅れて実装されるのですが、Copilot に関しては以下のような理由により半期エンタープライズ チャネルで実装されないことが Microsoft 365 Admin Monthly Digest – Feb 2024 – Microsoft Community Hub で公表されています。

The speed at which Copilot for Microsoft 365 evolves to bring the latest and greatest to your users’ fingertips makes it ineligible for users running Semi-Annual Enterprise Channel. Having updates come 6 months apart makes it extremely difficult to provide a great experience for both users and IT. This goes beyond just generative AI, as the pace of technology in general only continues to accelerate. 

要約すると、半年の一度の修正というペースでは生成 AI の進化に追いつかないということです。
同様の理由で Office 2021 LTSC や今年リリースされる予定の Office 2024 LTSC でも Copilot は使用できません。

企業ユーザーなどでは安定性などを考慮して半期エンタープライズ チャネルを使用されている場合も多いと思いますが、Copilot を使用するとなると以下のいずれかの方法をとる必要があるでしょう。

  • 最新チャネルに切り替える
  • 月次エンタープライズ チャネルに切り替える
  • 新しい Outlook for Windows に切り替える

上記のどれが良いかとなると、半期エンタープライズ チャネルからの切り替えなら月次エンタープライズ チャネルがおすすめです。
最新チャネルは新しい機能がいち早く使用可能となりますが、それに伴う不具合発生のリスクもあります。
また、新しい Outlook for Windows については更新チャネルのような概念はなく、修正が不定期に行われ、管理者でコントロールすることもできません。

しかし、月次エンタープライズ チャネルであれば、最新チャネルで見つかった重大な不具合が修正された状態でリリースされることが期待されるほか、最新とその前の二つのバージョンがサポートされており、更新の頻度を 2 カ月に 1 回とすることも可能です。

そもそも半期エンタープライズ チャネルでも毎月セキュリティ修正がリリースされており、最近はセキュリティ修正に伴う問題が半期エンタープライズ チャネルでも発生しているので、半期エンタープライズ チャネルだから安定しているとも言い切れません。
この機会に、月次エンタープライズ チャネルへの切り替えを検討するのもよいでしょう。

返信を行うマクロで [返信/転送時に元のメッセージのウィンドウを閉じる] を実装する方法

コメントにて以下のご要望をいただきました。


「返信メッセージで表示名を連絡先のものに置き換えるマクロ」を
もう何年も便利に使わせて頂いている者ですが,このマクロに一つ要望があります.

このマクロを使ってメールの返信/転送を実行しますと,
「返信/転送時に元のメッセージのウィンドウを閉じる」が効かなくなります.

これを効くように改善出来ないでしょうか.
もし可能でしたら効くようにして頂きたいのです.


マクロで ReplyAll メソッドや Forward メソッドを実行した場合、Outlook は [返信/転送時に元のメッセージのウィンドウを閉じる] の設定を参照しません。
そのため、この設定がオンでも元のメッセージのウィンドウは開いたままになります。
これを回避するには、マクロ自体で明示的にウィンドウを閉じる必要があります。
具体的には ReplyAll や Forward の直後に Close で返信元のメールを閉じるということです。
例えば、

Set objReply = ActiveExplorer.CurrentItem.ReplyAll

として返信メールを作成している場合、その次の行に

ActiveExplorer.CurrentItem.Close

と記載することで元のメッセージを閉じることができます。

Outlook オブジェクト モデルによりメールを送信しようとしても、送信トレイに滞留してしまう現象について

RPA や Excel マクロなどで Outlook オブジェクト モデルを使用して MailItem の Send メソッドによりメールを送信した際に、メールが送信されずに送信トレイに滞留したままの状態となる場合があります。
これは以下のような条件で発生します。

  • メールを送信する際に Outlook が起動していない
  • インターネット アカウントを使用しているか、Exchange アカウントでキャッシュ モードを有効にしている
  • Send メソッドで送信した後、すぐに Outlook のオブジェクトを開放している
  • メールサイズが大きかったり、一度に複数のメールを送信するなど、送信処理に時間がかかる状況である

上記の条件でメールが送信されない場合があるのは、Outlook の送信処理が以下のような順序で行われるためです。

  1. Send メソッドが実行されると、メールが送信トレイに保存され、送信のためのバックグラウンド タスクが起動される
  2. バックグラウンド タスクにより送信が実行される
  3. 送信が完了すると送信トレイのメールが送信済みアイテムに移動される

上記の 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 Boolean
    Set 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

CSV ファイルへのエクスポートで分類項目が全角だと 3 文字以上だと出力できない

Outlook で予定表などのデータを CSV ファイルにエクスポートをする際に、分類項目が全角で 3 文字以上になるとその分類項目が欠落するという事象が発生します。

これは、Outlook で CSV ファイルにエクスポートすると 1 行目が文字化けする現象についてでも説明した、CSV ファイルの UTF-8 化による不具合のようです。
この不具合についてはまだ修正が行われていないようですので、上記の記事でも紹介した以下のレジストリ設定を行うことで回避が可能です。

キー: HKEY_CURRENT_USER\Software\Microsoft\Office\16.0\Outlook\UserInfo
名前: ExportWithAscii
種類: REG_DWORD
値: 1

Temp\Diagnostics\Outlook に作成されるログを終了時に削除するマクロ

コメントにて以下のご要望をいただきました。


お世話になっております。

Outlook Logging フォルダーに ETL ファイルが作成されないようにする方法

を参考に

C:\Users\***\AppData\Local\Temp\Diagnostics\OUTLOOK

に生成されるテキストドキュメントを作成されない方法はございますか?

放置していたら、10Gb以上あったので・・・


環境変数 %TEMP% で示されるフォルダーの下の Diagnostics には Office 製品共通のコンポーネントによる動作履歴ログが保存されます。
こちらについて調査してみましたが、作成されないようにする方法は見つかりませんでした。

そのため、終了時にログを削除するようなマクロを作ってみました。
マクロ実行中に書き込みされていたログについては削除できない場合がありますが、古いログについては削除されます。
マクロは以下の通りです。

Private Sub Application_Quit()
     On Error Resume Next
     Dim strDiag As String
     Dim strLog As String
     ' ログ ファイルが保存されているフォルダーを取得
     strDiag = Environ("TEMP") & "\Diagnostics\OUTLOOK\"
     ' フォルダーのファイルを取得
     strLog = Dir(strDiag)
     ' ファイルの列挙が終わるまで繰り返し
     While strLog <> ""
         ' ファイルを削除
         Kill strDiag & "\" & strLog
         ' 次のファイルを取得
         strLog = Dir()
     Wend
End Sub

マクロの登録方法やメニューへの追加について

Recipient と AddressEntry

Outlook オブジェクト モデルには、受信者のプロパティを取得するために Recipient というオブジェクトがあり、これによりメールアドレスや表示名が取得可能です。
一方、Recipient の AddressEntry プロパティとして取得可能な AddressEntry オブジェクトでも、同様にメールアドレスや表示名が取得可能となっています。
今回はこの二つのオブジェクトの違いについて説明します。

Recipient オブジェクトは、その名の通りメールアイテムに設定されている受信者の情報を取得するものです。
そのため、このオブジェクトから取得可能な情報はメールアイテムに含まれている情報に限られます。

一方、AddressEntry オブジェクトはアドレス帳のエントリに対応するもので、アドレス帳から情報を取得します。
これにより、Exchange 環境においては、受信者の名前やアドレスだけでなく、会社名や所属部署などの詳細な情報を取得することが可能です。

したがって、単にメールアドレスや表示名などメールに含まれる情報だけを取得するのであれば Recipient のプロパティで十分ですが、アドレス帳から情報を取得する必要があるなら AddressEntry を使用すことになります。
ただ、Exchange キャッシュ モードがオフの場合、AddressEntry でプロパティを取得すると時間がかかる場合があり、例えば宛先に 100 人追加されているメールアイテムの受信者の情報を AddressEntry で取得しようとすると環境によっては数分かかることもあります。
そのため、こちらのオブジェクトの使用には注意が必要です。

また、Outlook の連絡先アドレス帳から設定したあて先の AddressEntry では、Exchange のように連絡先の会社名や所属部署などの情報を取得することはできません。
連絡先アドレス帳に対応する連絡先の情報を取得するには、AddressEntry の GetContact メソッドにより対応する ContactItem を取得し、そのアイテムから必要な情報にアクセスします。