Office関連

メールを閉じたときに指定したフォルダに移動するOutlookマクロ

先日Twitterで @akashi_keirin さんが下記ツイートをされていました。

どのような理由で上記のような処理をされたいのか、ツイートを追ってみると、“メール内容を確認したに特定のメールを隔離したい”とのこと。

なるほど。
Outlookには仕分けルール機能があるので、指定した条件を満たす受信メッセージ、または送信メッセージに対して特定の処理を行えますが、この機能では“メールを読み終えたタイミング”で処理を実行することはできません。

非常に面白そうなテーマ(と言ってしまっては微妙かもしれませんが…)だったので、早速試してみることにしました。

Inspector_Closeイベントでは処理できず

最初は「メールを閉じたときの処理?じゃあInspectorオブジェクトのCloseイベントあたりにメールを移動する処理を書いておけば大丈夫余裕でしょ?」だなんて高を括っていたのですが、実際に動かしてみると「実行時エラー ‘-2147221240 (80040108)’ : このアイテムのプロパティとメソッドは、このイベント プロシージャ内では使用できません。」が発生。

どうやらInspectorオブジェクトのCloseイベントが発生したタイミングでは、まだメールが完全に閉じていないために移動処理ができないようです。
同様に、このイベントよりも前のタイミングで発生するMailItemオブジェクトのCloseイベントでも処理することはできません。

ここまで試した段階で、「これ以上無理にやらなくても良いかな?」とも思ったのですが、折角なのでもう少し突っ込んでみたいと思います。

setTimeoutによる非同期処理

『Closeイベントが発生したタイミングではメールがまだ閉じ切っていないために移動できない』のであれば、処理するタイミングをちょっとずらしてあげれば良い話です。

このようなとき、私は非同期で処理を実行します。
具体的には、下記のようなコードです。
(動作確認は32ビット版、64ビット版の両方で行いました。)

ThisOutlookSession
Option Explicit

Private m_clsInspectors As clsInspectors

Private Sub Application_Startup()
  Set m_clsInspectors = New clsInspectors
End Sub
clsInspectors(クラスモジュール)
Option Explicit

Private WithEvents m_Inspectors As Outlook.Inspectors
Private WithEvents m_MailItem As Outlook.MailItem
Private m_doc As Object

Private Sub Class_Initialize()
  Set m_Inspectors = Application.Inspectors
End Sub

Private Sub Class_Terminate()
  Set m_MailItem = Nothing
  Set m_Inspectors = Nothing
End Sub

Private Sub m_Inspectors_NewInspector(ByVal Inspector As Inspector)
  If TypeOf Inspector.CurrentItem Is Outlook.MailItem Then
    Set m_MailItem = Inspector.CurrentItem
  End If
End Sub

Private Sub m_MailItem_Close(Cancel As Boolean)
  Dim src
  Const AttributeName As String = "TimeoutHandler"
  Const TargetFolderName As String = "移動先フォルダ"
  
  Set m_doc = CreateObject("htmlfile")
  src = "document.documentElement.getAttribute('" & AttributeName & "').MoveMailItem('" & m_MailItem.EntryID & "', '" & TargetFolderName & "');"
  m_doc.DocumentElement.setAttribute AttributeName, Me
  m_doc.parentWindow.setTimeout src, 1000
End Sub

Public Sub MoveMailItem(ByVal MailItemEntryID As String, _
                        ByVal TargetFolderName As String)
'メールを指定したフォルダに移動
  On Error Resume Next
  With Application.Session
    .GetItemFromID(MailItemEntryID).Move .GetDefaultFolder(olFolderInbox).Folders.Item(TargetFolderName)
  End With
End Sub
実行画面

ポイントとなるのはMailItem_Closeイベントの処理ですね。
HTMLWindow2オブジェクトのsetTimeoutメソッドを使って、時間差でメール移動処理(MoveMailItem)を呼び出しています。

この方法は、私のような中途半端な者ではなく、本当に深い知識と経験を持った方々に10年以上前に教えていただいたコードで、たまに自分用のマクロに組み込むこともあるのですが、正直、まだこれ動くの・・・!?と思うコードです。
MSHTML(IE)を使ったトリッキーな処理ですので、いつ動かなくなってもおかしくはないでしょう。

近しい処理としては、いみひと氏が「VBAからJScriptのfunctionオブジェクトを使用する方法」(下記サイト)を紹介されていますが、このようなハックを編み出されるのは大変素晴らしく、また惜しげもなく公開されていて、誠に有難い限りです。

おわりに

さて、上で書いた通り、半ば無理やり“メールを閉じたときに指定したフォルダに移動する処理”を実行してみたのですが、個人的には、やはり仕分けルールを使ってメール受信時に振り分け等の処理を行った方が無難だと思います🙂

マクロを使わなくても様々な条件を指定できますし、「スクリプトを実行する」でマクロを組み合わせることもできます(下記記事参照)。

もしくは、クイックアクセスツールバーにメールを振り分けるマクロを登録しておいて、イベントを使った自動処理ではなく、任意のタイミングでマクロを実行しても良いかもしれません。

いずれにしても、今回のテーマは非常に興味深く、試行錯誤している間もとても楽しめました。
@akashi_keirin さん、ありがとうございました!


2021/4/18 追記:
そういえば、複数のメールが同時に開かれた場合については全く考慮していませんでした。
その場合は恐らく下記ページにあるような処理が必要になるのではないかと思うのですが、私の方では実際に試していないので分かりません。申し訳ない!💦


2021/4/22 追記:
@furyutei 氏から下記情報をいただきました。
すっきりとまとまっていて、使い勝手が良さそうなコードです。

こちら↓については、たしかに実行できなくなっていました。
数日前までは実行できていたので、Windows Updateでmshtml.dllあたりが更新されたのかもしれません。
Outlookの方は4月22日時点でもコードを直すことなく実行できているので、HtmlDocumentのdocumentModeあたりに違いがあるのではないかと思うのですが、私の方では未確認です💦

[Office Scripts]指定した列の最終セルを取得する方法前のページ

[Outlook VBA]Outlookオブジェクトモデルとして公開されていないプロパティにアクセスする方法次のページ

関連記事

  1. Office関連

    Outlookを使ってGmail送信を行うVBAマクロ

    下記G Suite アップデート ブログにある通り、今年の6月には“安…

  2. Office関連

    Office文書をパスワード付きPDFに変換するVBAマクロ

    4年ほど前に書いた、下記記事のマクロがWordでも使えるか?との質問を…

  3. Office関連

    [Office 365 Solo]日本語環境以外では使えるの?

    Office 365 Soloを使ってみて、疑問に思ったことの一つが“…

  4. Office関連

    [Word VBA]引数の型がVariantになっているのはなぜ?

    インストラクターのネタ帳でお馴染みの伊藤さんが先日下記の記事をアップさ…

  5. Office関連

    PDFを他のファイル形式に変換するVBAマクロ

    「PDF 変換 Word VBA」といったキーワード検索でのアクセスが…

コメント

  • コメント (0)

  • トラックバックは利用できません。

  1. この記事へのコメントはありません。

Time limit is exhausted. Please reload CAPTCHA.

最近の記事

アーカイブ

PAGE TOP