Outlook VBA オブジェクトモデルの構造

# Outlook VBA の始め方
Outlook VBA でコードを書き始めようとしたとき、「はて、何を起点にどう記述すれば良いのか？」と悩む人が大多数だと思う。それは、使い慣れたExcelやWordと違ってOutlookのオブジェクトモデルに慣れ親しんでないからだ。また、ExcelやWordと違って「マクロの記録」が出来ないのも一因だろう。
そういうわけでこのエントリを記述しているのだが、私自身未だによく分かっていないところがある。そのため、記事をそのたびに更新していくことになるのでその点はご了承願いたい。更新通知が届くので、宜しければ是非ストックして頂くことを願う。

## 何はともあれVBE
前述のようにOutlook VBAには「マクロの記録」はないので、Visual Basic Editor (VBE)でゴリゴリ書いていく必要がある。WordやExcelと同様に、まずはリボンのユーザー設定から「開発」タブを有効にしてVBEを起動しよう。もちろん「 ALT + F11 」で直接起動してもいいし、リボンやクイックアクセスツールバーにアイコンを設置して起動してもいい。
おなじみ画面の左側「プロジェクトエクスプローラー」を見るとトップレベルで**`Project1`**となっている。この状態で上書き保存すると、**`Project1 (VbaProject.OTM)`**と変化する。この「**`VbaProject.OTM`**」がOutlookマクロファイルの実体だ。なお、場所は **`%userprofile%\AppData\Roaming\Microsoft\Outlook`** の中にある。
あとは標準モジュールなどを挿入してコードを書いていくとよい。


## 公式サイトを眺めてみる
公式サイトのヘルプは非常に重要だ。最も多く閲覧することになるだろう。
[◆ OutlookでのVisual Basic for Applicationsの使用 | Microsoft Docs ( 2019.6.8 )](https://docs.microsoft.com/ja-jp/office/vba/outlook/concepts/getting-started/using-visual-basic-for-applications-in-outlook)
リンク先が英語表示になった場合は、右上の(英語で読む)のトグルを解除すると日本語表示になる。基本的に機械翻訳なので時には？？？となることもあるだろう。そういう場合はGoogle翻訳を併用しても良いだろう。


# 各オブジェクトへの基本的なアプローチは3つ
    - Namespace : 名前空間から各種オブジェクトを取得する
    - Explorer  : メインの画面に関連するオブジェクトを取得する
    - Inspector : メイン以外の画面に関連するオブジェクトを取得する

## 1. Namespace を起点にする
Namespaceを起点にする場合の書き方は以下の通り。指定できる名前空間は **`MAPI`** のみである。Namespaceからはほとんどのオブジェクトにアクセスできる。

```vb:Namespace
Application.GetNamespace("MAPI")
' 下記で代用も出来る
Application.Session
```
### Namespaceからアクセス出来る代表的なオブジェクト

```
Applicationオブジェクト      ※このツリー図の最終更新日 : 2021.4.30
 |
 +-NameSpaceオブジェクト : Application.GetNameSpace("MAPI")
    |                        ※使用出来るデータソースは MAPI のみ
    |                      Application.Session
    |                          と記述してもよい
    |
    +-Accountsオブジェクト   : 現在のプロファイルに定義されているアカウントのコレクション
    |  +-Accountオブジェクト : 現在のプロファイルに定義されているアカウント
    |     |
    |     +-Store       オブジェクト : .DeliveryStoreプロパティ
    |     +-Recipient   オブジェクト : .CurrentUserプロパティ、.GetRecipientFromIDメソッド
    |     +-AddressEntryオブジェクト : .GetAddressEntryFromIDメソッド
    |
    +-AddressListsオブジェクト       : AddressListのコレクション
    |  +-AddressListオブジェクト     : AddressEntryオブジェクトを含むアドレス帳
    |     |
    |     +-AddressEntriesオブジェクト  : AddressEntryのコレクション
    |        +-AddressEntryオブジェクト : メッセージングシステムがメッセージを配信できるユーザー、
    |                                     グループ、パブリックフォルダーのいずれかを表す
    +-Storesオブジェクト
    |  +-Storeオブジェクト : Outlookデータファイル ( = *.pst )
    |    ※他の取得方法
    |      Application.Namespace("MAPI").DefaultStore
    |      Application.Namespace("MAPI").Accounts.Item(n).DeliveryStore
    |
    +-Foldersオブジェクト
    |  +-Folderオブジェクト ※一番上のFolderオブジェクトは [Outlookデータファイル] を示す
    |     |                                                    ※Storesとは別の意味で
    |     |  --> Application.GetNameSpace("MAPI").Folders.Item(Index)
    |     |                              または  .Folders(Index)
    |     |
    |     +-Foldersオブジェクト : 2階層目([Outlookデータファイル]内のFolders)
    |        |
    |        +-Folderオブジェクト
    |           | |
    |           | +-1. Index で指定 [ .Folders.Item(Index) または .Folders(Index) ]
    |           | |  ※Indexおよびその内容はOutlookデータファイルの種類によって変化する
    |           | |                             ※例：ローカルのpstファイルの場合
    |           | |  .Folders.Item(1)                = 削除済みアイテム
    |           | |  .Folders.Item(2)                = 受信トレイ
    |           | |  .Folders.Item(3)                = 送信トレイ
    |           | |  .Folders.Item(4)                = 送信済みアイテム
    |           | |  .Folders.Item(5)                = 予定表
    |           | |  .Folders.Item(6)                = 連絡先
    |           | |  .Folders.Item(7)                = 履歴
    |           | |  .Folders.Item(8)                = メモ
    |           | |  .Folders.Item(9)                = タスク
    |           | |  .Folders.Item(10)               = 下書き
    |           | |  .Folders.Item(11)               = RSS フィード
    |           | |  .Folders.Item(12)               = スレッド アクション設定
    |           | |  .Folders.Item(13)               = クイック操作設定
    |           | |  .Folders.Item(14)               = 迷惑メール
    |           | |  .Folders.Item(15)               = 感染した項目
    |           | |
    |           | +-2. 名前(上記の Name)で指定
    |           | |  .Folders("受信トレイ")
    |           | |  以下省略
    |           | |
    |           | +-3. OlDefaultFolders列挙で指定 [ .GetDefaultFolder(olFolderInbox) ]
    |           |   ※注意点：指定時の階層は Namespace の直下
    |           |     ○ Application.GetNamespace("MAPI").GetDefaultFolder(～)
    |           |     × Application.GetNamespace("MAPI").Folders(1).GetDefaultFolder(～)
    |           | 
    |           |       Enum Name                   Value    Description
    |           |   olFolderInbox                      6   受信トレイ
    |           |   olFolderDrafts                    16   下書き
    |           |   olFolderSentMail                   5   送信済みアイテム
    |           |   olFolderDeletedItems               3   削除済みアイテム
    |           |   olFolderRssFeeds                  25   RSSフィード
    |           |                                          感染した項目
    |           |   olFolderOutbox                     4   送信トレイ
    |           |   olFolderJunk                      23   迷惑メール
    |           |                                          検索フォルダ
    |           | 
    |           |   olPublicFoldersAllPubliceFolders  18   Exchangeパブリックストア内のAll Public Folders
    |           |   olFolderManagedEmail              29   管理対象のフォルダグループの最上位フォルダ
    |           |   olFolderSyncIssues                20   同期の失敗フォルダ
    |           |    +-olFolderConflicts              19    +- 競合フォルダ
    |           |    +-olFolderLocalFailures          21    +- ローカルの失敗フォルダ
    |           |    +-olFolderServerFailures         22    +- サーバーの失敗フォルダ
    |           | 
    |           |   olFolderCalendar                   9   予定表
    |           |   olFolderContacts                  10   連絡先
    |           |   olFolderSuggestedContacts         30   連絡先候補
    |           |   olFolderTasks                     13   タスク
    |           |   olFolderNotes                     12   メモ
    |           |   olFolderJournal                   11   履歴
    |           |   olFolderToDo                      28   ToDo(フラグ)
    |           | 
    |           |   ※ Outlookデータファイルが複数ある場合は、プロファイルのプロパティで[既定]に
    |           |      なっているデータファイルから取得される
    |           |
    |           |  ※ Tasks と ToDo の違い
    |           |    Tasks --- タスクフォルダ にあるもの
    |           |    ToDo  --- MailItemやContactItemなど様々なフォルダアイテムに設定したフラグ
    |           |
    |           |    ※「ToDoバーのタスク」とか「タスクにフラグを付けられる」とかでややこしくなってしまう
    |           |
    |           |
    |           +-Itemsオブジェクト : フォルダーに含まれる[Outlookアイテムオブジェクト]のコレクション
    |           |  |     取得  Items(n) または Items.Item(n)  : 上記の各フォルダの中身
    |           |  |
    |           |  |  Outlookアイテムオブジェクト一覧
    |           |  |    AppointmentItem        : 予定表フォルダーの1回限りの予定や会議、または定期的な予定や会議
    |           |  |    ContactItem            : 連絡先フォルダー内の連絡先を表す
    |           |  |    DistListItem           : 連絡先フォルダー内の配布リストを表す
    |           |  |    DocumentItem           : Outlookフォルダー内のアイテムのうち、Microsoft Outlookアイテム
    |           |  |                             以外のドキュメントを表す
    |           |  |    JournalItem            : 履歴フォルダー内の履歴項目を表す
    |           |  |    MailItem               : メールメッセージを表す
    |           |  |    MeetingItem            : 別のユーザーやグループの操作による受信者の予定表フォルダーへの変更
    |           |  |    NoteItem               : メモフォルダー内のメモを表す
    |           |  |    PostItem               : パブリックフォルダーへの投稿アイテムを表す
    |           |  |    RemoteItem             : 受信トレイフォルダーのリモートアイテムを表す
    |           |  |    ReportItem             : 受信トレイフォルダー内のメール配信レポートを表す
    |           |  |    SharingItem            : 受信トレイフォルダー内の共有メッセージを表す
    |           |  |    StorageItem            : 常に隠しアイテムとして親フォルダーに保存され、Outlookソリューション
    |           |  |                             の個人用データを格納するMAPIのメッセージオブジェクトです
    |           |  |    TaskItem               : タスクフォルダー内のタスクを表す
    |           |  |    TaskRequestItem        : 他のパーティやグループの仕事によって発生した、受信者のタスクリストに
    |           |  |                             対する変更の内容を表す
    |           |  |    TaskRequestAcceptItem  : TaskRequestItemへの応答(受入)を表す。呼び出し元ユーザーによって送信される
    |           |  |    TaskRequestDeclineItem : TaskRequestItemへの応答(辞退)を表す。呼び出し元ユーザーによって送信される
    |           |  |    TaskRequestUpdateItem  : TaskRequestItemへの応答(変更)を表す。呼び出し元ユーザーによって送信される
    |           |  |
    |           |  +-Attachmentsオブジェクト    : Attachmentのコレクション
    |           |     +-Attachmentオブジェクト : 添付ファイル
    |           |
    |           |
    |           +-Viewsオブジェクト : 現在のフォルダ内のすべての Viewオブジェクトのコレクションを格納
    |              |                 ※メニューバーの[表示]タブ＞[現在のビュー]グループ の関連
    |              |
    |              +-Viewオブジェクト : データの並べ替え、グループ化、および表示に使用出来るカスタマイズ可能なビュー
    |                 |
    |                 +-olViewType列挙
    |                    |
    |                    +- 0 = olTableView         : TableView        オブジェクト
    |                    +- 1 = olDailyTaskListView : 予定表の日毎のタスクリストを含むTableViewオブジェクト
    |                    +- 1 = olCardView          : CardView         オブジェクト
    |                    +- 2 = olCalendarView      : CalendarView     オブジェクト
    |                    +- 3 = olIconView          : IconView         オブジェクト
    |                    +- 4 = olTimelineView      : TimelineView     オブジェクト
    |                    +- 5 = olBusinessCardView  : BusinessCardView オブジェクト
    |                    +- 7 = olPeopleView        : PeopleView       オブジェクト
    |
    +-Categoriesオブジェクト    : 分類
    |  +-Categoryオブジェクト   : 分類項目
    |
    +-SyncObjectsオブジェクト   : Application.GetNameSpace("MAPI").SyncObjects で取得
    |  +-SyncObjectオブジェクト : ユーザーの送受信グループ
    |
    +-その他取得できるプロパティ
        |
        +- CurrentProfileName           : 現在のプロファイル名を取得
        +- CurrentUser                  : 現在のユーザ名を取得
        +- Type                         : オブジェクトの種類を示す文字列を返す = MAPI
        +- Offline                      : Exchangeサーバへの接続(切断)状態を示すブール値
        +- AutoDiscoverConnectionMode   : 自動接続するExchangeサーバの接続の種類を返す olAutoDiscoverConnectionMode列挙
        +- AutoDiscoverXml              : Exchangeサーバの自動検出サービスから返されるXML文字列
        +- ExchangeConnectionMode       : ユーザのプライマリExchangeアカウントの接続モードを返す olExchangeConnectionMode列挙
        +- ExchangeMailboxServerName    : ユーザのプライマリExchangeアカウントのメールボックスをホストするサーバの名前を文字列で返す
        +- ExchangeMailboxServerVersion : ユーザのプライマリExchangeアカウントのメールボックスをホストするサーバのバージョンを文字列で返す
```


## 2. Explorer を起点にする
Explorer とは Outlookを立ち上げたときに最初に表示されるメインの画面のこと。
画像ではメール画面になっているが、予定表、連絡先、タスク、メモなどもこの画面で表示出来ることはご存じの通りだ。
![outlook_explorer_01_landscape.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307310/5457ae43-fd66-7d44-3859-ae1119a2df2a.jpeg)
閲覧ウィンドウを閉じている状態で画面を縦長にした場合は以下のように表示される。
![outlook_explorer_02_portrait1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307310/70a45817-b721-db32-2a14-c00a3e03cdb5.jpeg)
また、閲覧ウィンドウを表示している状態でウィンドウを縦長にしたり、スマートフォンなど縦長の画面の場合は以下のように表示される。
![outlook_explorer_03_portrait2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307310/343b5dd5-e74f-823b-60bc-9053dbe916e9.jpeg)

## 基本的な書き方

```vb:Application.Explorer
Application.ActiveExplorer    'アクティブなExplorer
Application.Explorers(n)      '開いているn番目のExplorer
Application.Explorers.Item(n) 'Explorer(n) と同意だが、こう書いた方がIntelliSenseが働く
```
### Explorerからアクセス出来る代表的なオブジェクト

```
Application      ※このツリー図の最終更新日 : 2021.4.30
 |
 +-Explorersオブジェクト   : Explorerのコレクション
    +-Explorerオブジェクト : フォルダー(Folderオブジェクト)の内容が表示されるウィンドウを表す
       |                    ※簡単にいうとメインの画面
       |
       +-AccountSelectorオブジェクト : BackStageビューのアカウント選択箇所を示す
       |  |
       |  +-Accountオブジェクト
       |     ※ ActiveExplorer.AccountSelector.SelectedAccount
       |       で、現在のアカウントを取得出来る。その他のアカウントを選択的に取得は出来ないが、
       |       SelectedAccountChangeイベントでアカウントの変更を確認出来る。
       |
       +-NavigationPaneオブジェクト : ナビゲーションウィンドウ
       |  |  
       |  +-NavigationModulesオブジェクト
       |     +-NavigationModuleオブジェクト
       |     | ※派生オブジェクト
       |     +-MailModule     : メール   *
       |     +-CalendarModule : 予定表   *
       |     +-ContactsModule : 連絡先   *
       |     +-TasksModule    : タスク   *
       |     +-NotesModule    : メモ     *
       |     +-JournalModule  : 履歴     *
       |     +-SolutionModule : アドイン
       |
       |       *で示したModule
       |         |
       |         +-NavigationGroupsオブジェクト
       |             +-NavigationGroupオブジェクト : olGroupType列挙
       |                 |
       |                 +-NavigationFoldersオブジェクト
       |                     +-NavigationFolderオブジェクト
       |                         |
       |                         +-Folderオブジェクト
       |
       +-Panesオブジェクト : [ショートカット](OutlookBar)のみ
       |  |
       |  +-OutlookBarPaneオブジェクト
       |     |
       |     +-OutlookBarStorageオブジェクト
       |        |
       |        +-OutlookBarGroupsオブジェクト
       |           +-OutlookBarGroupオブジェクト
       |              |
       |              +-OutlookBarShortcutsオブジェクト
       |                 +-OutlookBarShortcutオブジェクト
       |
       |    ※ > ? ActiveExplorer.Panes(1).Contents.Groups(1).Shortcuts(1).Name
       |    ※ > Outlook Today
       |
       +-PreviewPaneオブジェクト
```
### Explorerの基本的な配置とオブジェクトの関係
![outlook_explorer_04_landscape.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307310/16aa418c-5891-e315-443d-8deb24f5beb8.jpeg)
![outlook_explorer_05_portrait1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307310/65d74ea0-18b7-bed8-814e-56b4d56ca508.jpeg)![outlook_explorer_06_portrait2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307310/e4a70b5c-4952-a7c0-f8d9-a52a3d14e90c.jpeg)



### ActiveExplorer.Selectionで現在表示されているフォルダに関係するOutlookアイテムが取得できる
```vb:ActiveExplorer.Selection
'// メールフォルダの受信トレイを開いているとき、受信メールの一つを選択しているとき
Debug.Print ActiveExplorer.Selection.Count             ' = 1
Debug.Print TypeName(ActiveExplorer.Selection.Item(0)) ' = MailItem
'※ Selection.Item(n)のIndex(添え字)は 0 から始まるので注意されたい

Dim objMail As MailItem
Set objMail = ActiveExplorer.Selection.Item(0)
Debug.Print objMail.Subject

'// 同様にして、AppointmentItem, ContactItem, TaskItem, NoteItemなどを画面の選択から取得していくことができる
```

## 3. Inspector を起点にする
Inspector とは、Explorer の他に開いた画面全般を指す。例えば新規メール画面や、連絡先の詳細編集画面などである。
![outlook_inspector_01_newmail.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307310/7beebf60-72f2-2956-3b4b-bb8c193c82a1.jpeg)
![outlook_inspector_02_newschedule.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307310/6c7996bb-5398-810d-44ee-569dfa0deccf.jpeg)

## 基本的な書き方
```
Application.ActiveInspector    'アクティブなInspector
Application.Inspectors(n)      '開いているn番目のInspector
Application.Inspectors.Item(n) 'Inspectors(n) と同意だが、こう書いた方がIntelliSenseが働く
```

### Inspectorからアクセス出来る代表的なオブジェクト

```
Application      ※このツリー図の最終更新日 : 2021.4.7
 |
 +-Inspectorsオブジェクト   : Inspectorのコレクション
    +-Inspectorオブジェクト : Explorer以外で現在開いているアイテムウィンドウ(メール, 予定, 連絡先など)
       |
       +-Itemsオブジェクト : .CurrentItem で取得
       |
       +-Pagesオブジェクト : .ModifiedFormPages で取得
```

# その他
## (1) Application.ActiveWindow について
これまでにOutlookのアプリケーション画面は **`Explorer`** と **`Inspector`** があることを示したが、一方でこういうコマンドがある。

```vb:Application.ActiveWindow
Application.ActiveWindow
```
これが示すのは、現在のアクティブ画面が Explorer なのか Inspector なのか分からない場合の判定だ。TypeNameをかけてみると **`Explorer`**か**`Inspector`**になる。注意して欲しいのは、**`WindowsコレクションやWindowオブジェクトはない`**ということだ。

## (2) Outlook VBAにおける表示位置の単位
ExcelやWordでWindow(Workbook, Document)やユーザーフォームの表示や位置指定をするときに使われる単位はポイントと呼ばれる単位であり、ピクセルに対して次の関係がある。なお、座標の基点は プライマリディスプレイの左上が ( 0, 0 )で、右および下がプラス領域となる。

```vb:ポイントとピクセルの関係
  1 point = 1 pixel  * 0.75
  1 pixel = 1 point  / 0.75
          = 1 point  * 1.333...

  ex.   1920 pixel = 1440 point
```
ところが、Outlookの場合、ExplorerやInspectorの単位はピクセルそのままとなっているので注意が必要だ。更に気をつけたいのは、ユーザーフォームのみがポイント単位である点だ。