起動時に [週の最初の曜日] を当日の曜日に変更するマクロ

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


いつも参考にさせていただいています。

Outlookの予定表を「稼働日」で表示した際に、常に「今日を左側に表示」して、今日を起点に稼働日分を表示したいと思っています。

そこで、OUTLOOKの「週のはじめの曜日」をOUTLOOK起動時に今日の曜日に変更することで実現できると考えたのですが、OUTLOOKのVBAで実現する方法をご教示いただけないでしょうか。

みなさまのお知恵を拝借いたしたく、よろしくお願いいたします。

以上です。


Outlook の [週の最初の曜日] は以下のレジストリ値として保存されています。

キー: HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\16.0\Outlook\Options\Calendar
名前: FirstDOW
種類: REG_DWORD
値: 0-6

そこで、起動時に実行される Application_Startup イベントで上記のレジストリに当日の曜日に該当する数字を設定すれば、ご要望の動作でしょう。
ただし、[Outlook の設定をクラウドに保存する] という設定があるバージョンでは、これがオンになっているとクラウドの設定が優先されてしまうので、オフにする必要があります。

マクロは以下の通りです。

'
Private Sub Application_Startup()
     Dim wshShell As Object
     '
     Set wshShell = CreateObject("WScript.Shell")
     wshShell.RegWrite "HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\16.0\Outlook\Options\Calendar\FirstDOW", Weekday(Now) - 1, "REG_DWORD"
End Sub

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

特定の分類項目が設定されているアイテムを CSV に従って移動するマクロ ドメイン対応版

特定の分類項目が設定されているアイテムを CSV に従って移動するマクロ 階層対応版のコメントにて以下のご要望をいただきました。


昨年は本マクロを開発いただき、本当にありがとうございました。
Outlookの「仕分けルール」の容量制限もない上に、「仕分けルール」よりも
動作が高速で大変重宝しています。

ところで、本マクロの仕分け用CSVを手作業で良いので、メールアドレスの
ドメイン等が同一のメールを仕分けするように再度の改定をいただくよう
お願いできませんでしょうか。(aaa@xxxxx.co.jp, bbb@xxxxx.co.jp 等を
同一のフォルダに送ることを希望)

Web上の情報等から自作を試みましたが、うまく動作させられませんでした。
アドバイスいただけますと大変幸甚です。

よろしくお願いいたします。


CSV ファイルの差出人のアドレスの列にドメインのみを指定してあった場合に、差出人のドメインで振り分けるようにマクロを修正しました。
MoveItemsToSubFolder と ImportRulesFromCSV は以前のマクロと同じなので、すでに定義されている場合はこちらは以前のものを使用してください。

' 特定の分類項目が設定されているアイテムを CSV に従って移動するマクロ
Public Sub MoveItemsBySenderDomainInCSV()
     ' 移動対象となる分類項目の設定
     Const MOVE_MARK = "処理完了"
     Dim dicRules As Scripting.Dictionary
     Dim fldInbox As Folder
     Dim i As Integer
     Dim objItem As Object
     Dim strAddr As String
     Dim strDomain As String
     Dim strPath As String
     Dim fldDest As Folder
     ' CSV ファイルの内容を Dictionary に読み込み
     Set dicRules = CreateObject("Scripting.Dictionary")
     ImportRulesFromCSV dicRules
     '
     Set fldInbox = Session.GetDefaultFolder(olFolderInbox)
     ' 受信トレイのアイテムを最後から確認
     For i = fldInbox.Items.Count To 1 Step -1
         Set objItem = fldInbox.Items(i)
         ' 処理対象となる分類項目が設定されていたら
         If InStr(objItem.Categories, MOVE_MARK) > 0 Then
             ' 差出人のアドレスを取得
             strAddr = UCase(objItem.SenderEmailAddress)
             ' 差出人のドメインを取得
             strDomain = Mid(strAddr, InStr(strAddr, "@") + 1)
             ' Dictionary にアドレスが設定されていたら
             If dicRules.Exists(strAddr) Then
                 ' アイテムを指定されたパスに移動
                 strPath = dicRules(strAddr)
                 MoveItemsToSubFolder objItem, strPath
             ' Dictionary にドメインが設定されていたら
             ElseIf dicRules.Exists(strDomain) Then
                 ' アイテムを指定されたパスに移動
                 strPath = dicRules(strDomain)
                 MoveItemsToSubFolder objItem, strPath
             End If
         End If
     Next
End Sub
'
' アイテムを指定されたパスに移動するマクロ
Public Sub MoveItemsToSubFolder(objItem As Object, strPath As String)
     Dim fldRoot As Folder
     Dim fldDest As Folder
     ' ルートフォルダーを取得
     Set fldRoot = Session.GetDefaultFolder(olFolderInbox).Parent
     ' パスが 1 階層のみならルート直下のフォルダーに移動
     If InStr(strPath, "\") = 0 Then
         objItem.Move fldRoot.Folders(strPath)
     Else
         Dim arrPath As Variant
         Dim strFolder As Variant
         ' パスを \ で分割
         arrPath = Split(strPath, "\")
         Set fldDest = fldRoot
         ' 分割したパスごとにフォルダーをたどる
         For Each strFolder In arrPath
             Set fldDest = fldDest.Folders(strFolder)
         Next
         ' たどり着いたフォルダーに移動
         objItem.Move fldDest
     End If
End Sub
'
' CSV ファイルの内容を Dictionary オブジェクトに読み込むマクロ
Private Sub ImportRulesFromCSV(dicRules As Object)
     ' 移動ルールが格納されている CSV ファイルのファイル名
     Const CSV_FILE = "c:\temp\moverules.csv"
     Dim strFolder As String
     Dim strAddrs As String
     Dim arrAddrs As Variant
     Dim strAddr As Variant
     ' CSV ファイルを読み込みのため開く
     Open CSV_FILE For Input As #1
     ' 1 行目はヘッダーのためスキップ
     Line Input #1, strFolder
     ' ファイルの終わりまで繰り返す
     While Not EOF(1)
         ' CSV からフォルダーとアドレスを読み込み
         Input #1, strFolder, strAddrs
         strAddrs = UCase(strAddrs)
         ' アドレスに ; が含まれていなければ単一のアドレス
         If InStr(strAddrs, ";") = 0 Then
             ' アドレスが Dictionary になければ
             If Not dicRules.Exists(strAddrs) Then
                 ' アドレスをキーとしてフォルダー名を Dictionary に追加
                 dicRules.Add strAddrs, strFolder
             End If
         Else
             ' ; を区切りとして文字列を分割
             arrAddrs = Split(strAddrs, ";")
             ' 分割したアドレスごとに処理
             For Each strAddr In arrAddrs
                 ' アドレスが Dictionary になければ
                 If Not dicRules.Exists(strAddr) Then
                     ' アドレスをキーとしてフォルダー名を Dictionary に追加
                     dicRules.Add strAddr, strFolder
                 End If
             Next
         End If
     Wend
     Close #1
End Sub

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

Outlook の連絡先アドレス帳の表示名を「姓 名」の順に設定するマクロ

Outlook の連絡先アイテムを作成する際に、連絡先アドレス帳の表示名には通常「姓 名」の順に設定されます。(日本語環境の場合)
しかし、Exchange Online や Outlook.com の環境で、気が付くと「名 姓」の順になってしまっているという事例が確認されています。
こうなった場合には手作業で戻すか、一度 CSV にエクスポートしてインポートするというような方法で対処可能ですが、こういう時こそマクロの出番といえます。

連絡先アドレス帳の表示名は連絡先アイテムの Subject プロパティになりますので、このプロパティに姓 (LastName) と名 (FirstName) を連結した文字列を設定するという簡単なものになります。
マクロは以下の通りです。

Public Sub FixLastFirst()
     Dim fldContact As Folder
     Dim objContact As Object
     Dim strFullName As String
     ' 既定の連絡先フォルダーを取得
     Set fldContact = Session.GetDefaultFolder(olFolderContacts)
     ' 現在開いているフォルダーに対して実行する場合は以下のコードを使用
     'Set fldContact = ActiveExplorer.CurrentFolder
     '
     For Each objContact In fldContact.Items
         With objContact
             ' 連絡先アイテムのみ処理
             If .MessageClass = "IPM.Contact" Then
                 ' 姓と名の両方が設定されている場合のみ処理
                 If .LastName <> "" And .FirstName <> "" Then
                     ' 表示名として「姓 名」を設定
                     strFullName = .LastName & " " & .FirstName
                     ' 会社名がある場合は " - 会社名" を追加
                     If .CompanyName <> "" Then
                         strFullName = strFullName & " - " & .CompanyName
                     End If
                     ' 現在の表示名が「姓 名」ではない場合のみ変更して保存
                     If .Subject <> strFullName Then
                         .Subject = strFullName
                         .Save
                     End If
                 End If
             End If
         End With
     Next
End Sub

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

特定の条件で受信したメールについて、メール本文に含まれるアドレスに返信するマクロ

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


Outlookのマクロで下記のような動きをさせることは可能でしょうか。

「特定の件名」または「特定のメールアドレス」から受信した場合に
そのメール本文に記載されているメールアドレス宛に自動返信する
マクロができないでしょうか。

メール本文には、文字の揺らぎはなく、必ず「メールアドレス:xxxx@xx.net」
と記載されています。

可能であれば構文を教えていただけませんでしょうか。


以下のようなマクロで実現できます。

'
Private Sub Application_NewMailEx(ByVal EntryIDCollection As String)
     Dim objItem As Object
     Dim objMail As MailItem
     '
     Set objItem = Session.GetItemFromID(EntryIDCollection)
     ' 受信メールが通常のメールだったら
     If objItem.MessageClass = "IPM.Note" Then
         Set objMail = objItem
         CheckIfNeedReply objMail
     End If

End Sub
'
Private Sub CheckIfNeedReply(objMail As MailItem)
     Const REPLY_SENDER = "user1@example.com"
     Const REPLY_SUBJECT = "要返信"
     ' 差出人のアドレスが特定のアドレスなら返信
     If objMail.SenderEmailAddress = REPLY_SENDER Then
         ReplyToAddressInBody objMail
     ' 件名が特定の文字列なら返信
     ElseIf objMail.Subject = REPLY_SUBJECT Then
     ' 件名が特定の文字列を含むという場合は以下の記述
     ' ElseIf objMail.Subject like "*" & REPLY_SUBJECT & "*" Then
         ReplyToAddressInBody objMail
     End If
End Sub
' 本文中のメールアドレスに返信する
Private Sub ReplyToAddressInBody(objMail As MailItem)
     Const VALID_ADDR_CHAR = "abcdefghijklmnopqrstuvwxyz0123456789.@!#$%&'*+-/=?^_`{|}~"
     Const REPLY_BODY = "メールを受信しました。"
     Dim strBody As String
     Dim i As Integer
     Dim strReplyAddr As String
     Dim fAddr As Boolean
     Dim c As String
     Dim objReply As MailItem
     Dim objRec As Recipient
     ' 本文からメールアドレスを取得する
     strBody = LCase(objMail.Body)
     i = InStr(strBody, "メールアドレス:")
     If i < 0 Then Exit Sub
     strReplyAddr = ""
     fAddr = False
     While Len(strReplyAddr) = 0 Or fAddr = True
         c = Mid(strBody, i, 1)
         fAddr = CBool(InStr(VALID_ADDR_CHAR, c))
         If fAddr Then
             strReplyAddr = strReplyAddr & c
         End If
         i = i + 1
     Wend
     ' メールに返信する
     Set objReply = objMail.Reply
     ' 返信メールの宛先を残すなら以下の 3 行は削除
     For i = objReply.Recipients.Count To 1 Step -1
         objReply.Recipients.Remove i
     Next
     ' 本文から取り出したメールアドレスを宛先に追加
     Set objRec = objReply.Recipients.Add(strReplyAddr)
     objRec.Type = olTo
     objRec.Resolve
     ' 本文を追記して送信
     objReply.Body = REPLY_BODY & objReply.Body
     objReply.Send
End Sub

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

タスクをドラッグアンドドロップして作成した予定から実働時間を算出するマクロ

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


タスクを予定表にドラッグ&ドロップするとタスクに紐づいた予定が作成されるのを利用して、VBAでタスクの実働時間を紐づいた予定から算出して自動反映したいです。
タスクに紐づいた予定を取得するにはどのようにすればよろしいでしょうか?
ConversationTopicは一致しますが、同じConversationTopicがある場合、紐づいていない予定も取得してしまいます。
ご教授のほどよろしくお願いいたします。


タスク アイテムを予定表にドラッグアンドドロップして予定を作成した場合、その予定アイテムの PidLidLinkedTaskItems というプロパティには元になったタスクの EntryID が格納されています。
そのため、件名で予定アイテムを絞り込んだ後、PidLidLinkedTaskItems の ID とタスク アイテムの ID が一致すれば関連付けられたアイテムと判断可能です。
現在開いているタスク アイテムに関連付けられている予定の時間から実働時間を算出するマクロは以下の通りです。

'
Public Sub CollectActualWorkFromCalendar()
     On Error Resume Next
     Const PidLidLinkedTaskItems = "http:" & _
         "//schemas.microsoft.com/mapi/id/{00062002-0000-0000-C000-000000000046}/820C1102"
     Dim tskItem As TaskItem
     Dim fldAppts As Folder
     Dim colAppts As Items
     Dim apptItem As AppointmentItem
     Dim strTaskID As String
     ' 現在表示しているタスク アイテムを取得
     Set tskItem = ActiveInspector.CurrentItem
     strTaskID = tskItem.EntryID
     ' タスク アイテムの実働時間をリセット
     tskItem.ActualWork = 0
     ' 予定表からタスクと同じ件名の予定を取得
     Set fldAppts = Session.GetDefaultFolder(olFolderCalendar)
     Set colAppts = fldAppts.Items.Restrict("[件名]='" & tskItem.Subject & "'")
     ' 予定アイテムを一つずつチェック
     For Each apptItem In colAppts
         Dim arrIDs As Variant
         Dim strLinkedID As String
         Set arrIDs = Nothing
         strLinkedID = ""
         With apptItem.PropertyAccessor
             Err.Clear
             ' 予定に関連付けられているアイテムの ID を取得
             arrIDs = .GetProperty(PidLidLinkedTaskItems)
             strLinkedID = .BinaryToString(arrIDs(0))
             ' 関連付けられたアイテムの ID とタスクの ID が一致したら
             If strLinkedID = strTaskID Then
                 ' 実働時間に予定の長さを追加
                 tskItem.ActualWork = tskItem.ActualWork + apptItem.Duration
             End If
         End With
     Next
     ActiveInspector.CommandBars.ExecuteMso "ShowTaskDetailsPage"
End Sub

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

Word のマクロで作成したメールの Cc に連絡先グループのメンバーを展開して追加するマクロ

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


Word VBAからOutlookを操作して、新規作成から下書きを保存したいと考えております。

下記が本題です。

CCに連絡先グループの全員のアドレスを入力したいのですが調べてもわかりませんでした。

構文を教えていただけないでしょうか。


ご質問のようなマクロの動作を実現するには以下の 3 つの処理が必要になります。

  1. 連絡先フォルダーから Cc に追加したい連絡先グループを検索する
  2. 連絡先グループを展開する
  3. 展開したメンバーを Cc に追加する

さらに、これを Word のマクロで実行するということなので、Outlook.Application オブジェクトを生成するなどの処理も必要になるでしょう。
連絡先グループを展開する方法については、以前、連絡先グループのメンバーを展開してメールアドレスを取得するマクロで説明していますのでそちらも参考にしてください。
サンプルのマクロは以下の様になります。
CreateMailWithCcingPDL の DL_NAME などを書き換えて使用してください。

'

Public Sub CreateMailWithCcingPDL()
     ' 追加する連絡先グループの表示名を指定
     Const DL_NAME = "DistList1"
     '
     Dim olkApp As Object
     Dim olkMail As Object
     ' Outlook.Application オブジェクトを生成
     Set olkApp = CreateObject("Outlook.Application")
     ' 新規メールを作成
     Set olkMail = olkApp.CreateItem(0)
     ' メールの宛先に連絡先グループを追加
     AddDLToMailCc olkMail, DL_NAME
     ' 必要に応じて宛先や件名や本文などを設定
     olkMail.to = "to@example.com"
     olkMail.Subject = "連絡先グループテスト"
     olkMail.Body = "テストです。"
     ' 作成したメールを下書きに保存
     olkMail.Save
     ' 作成したメールを表示
     olkMail.Display
End Sub
' メールアイテムの Cc に連絡先グループを展開して追加するマクロ
Private Sub AddDLToMailCc(olkMail As Object, strDLName As String)
     Dim fldContacts As Object
     Dim objItem As Object
     Set fldContacts = olkMail.Application.Session.GetDefaultFolder(10)
     For Each objItem In fldContacts.Items
         If TypeName(objItem) = "DistListItem" Then
             If objItem.Subject = strDLName Then
                 Dim strExpanded As String
                 olkMail.Cc = ExpandGroup(objItem, strExpanded)
                 Exit For
             End If
         End If
     Next
     ' 展開したアドレスを名前解決
     olkMail.Recipients.ResolveAll
End Sub
' 連絡先グループを再帰的に展開する関数
Private Function ExpandGroup(distList As Object, strExpanded As String) As String
     Dim strNames As String
     Dim objMember As Object
     strNames = ""
     For i = 1 To distList.MemberCount
         Set objMember = distList.GetMember(i)
         If objMember.AddressEntry.Type = "MAPIPDL" Then
             Dim distListSub As Object
             ' 入れ子になっているグループの場合は 43 文字目からがアイテムのエントリー ID
             strEntryID = Mid(objMember.AddressEntry.ID, 43)
             If InStr(strExpanded, strEntryID) > 0 Then
                 ' 展開済みのグループについては展開しない
             Else
                 'エントリー ID から連絡先グループを取得
                 Set distListSub = distList.Application.Session.GetItemFromID(strEntryID)
                 ' 再帰的に展開
                 strNames = strNames & ExpandGroup(distListSub, strExpanded)
             End If
         Else
             ' グループでなければ表示名とアドレスを取得
             strNames = strNames & GetNameAddrEx(objMember)
         End If
     Next
     ' 展開した情報を返す
     ExpandGroup = strNames
End Function
' 受信者オブジェクトから表示名とアドレスの文字列を取得する関数
Private Function GetNameAddrEx(oRec As Object) As String
     Const PR_ORIGINAL_DISPLAY_NAME = "http:" & "//schemas.microsoft.com/mapi/proptag/0x3a13001e"
     Const PR_SMTP_ADDRESS = "http:" & "//schemas.microsoft.com/mapi/proptag/0x39fe001e"
     Dim strAddress As String
     If oRec.AddressEntry.Type = "SMTP" Then
         strAddress = oRec.Address
     ElseIf oRec.AddressEntry.AddressEntryUserType = 11 Then
         ' アドレスエントリーが連絡先グループであれば
         Dim strExpanded As String
         strExpanded = ""
         GetNameAddrEx = ExpandGroup(oRec, strExpanded)
         Exit Function
     Else ' Exchange 対応
         If oRec.AddressEntry.AddressEntryUserType = olOutlookContactAddressEntry Then
             strAddress = oRec.AddressEntry.PropertyAccessor.GetProperty(PR_ORIGINAL_DISPLAY_NAME)
         Else
             strAddress = oRec.AddressEntry.PropertyAccessor.GetProperty(PR_SMTP_ADDRESS)
         End If
     End If
     ' 表示名に SMTP アドレスが含まれている場合はアドレスはつけない
     If InStr(oRec.Name, strAddress) > 0 Then
         GetNameAddrEx = oRec.Name & "; "
     Else
         GetNameAddrEx = oRec.Name & "<" & strAddress & ">" & "; "
     End If
End Function

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

差出人をもとにフォルダーに振り分けるルールを CSV ファイルにエクスポートするマクロ 階層対応版

差出人をもとにフォルダーに振り分けるルールを CSV ファイルにエクスポートするマクロ のコメントにて以下のご要望をいただきました。


ありがとうございます。元質問者です。今のところ数フォルダで試したのみですが、うまく
動作するようです。少し気になったのが、
1) CSV>フォルダ分類の方のコメントにも書いたように、手元では、「受信トレイ」と分類
先の各フォルダが同一階層に配置されていて、本マクロで書き出したCSVで再振り分けし
ようとすると、「受信トレイ」下に同名フォルダが無いためエラーになってしまうこと
2) このマクロでCSVを書き出した場合、社内のアドレスは以下のような特殊な表記に
なること
フォルダ名, /o=ExchangeLabs/ou=Exchange Administrative Group (xxxxxxx)
/cn=Recipients/cn=xxxx
の2点です。2)は、出力CSVを参照する上で特段の障害にはならないのですが、
振り分け先を「受信トレイ」と同一階層にするということは難しいのでしょうか。
質問ばかりで申し訳ございませんがよろしくお願いいたします。


ルールの振り分け先が受信トレイのサブフォルダーではない場合、ルールにはフォルダーの階層情報は含まれていないため、フォルダーの階層構造をマクロで解析する必要があります。
以前のマクロを受信トレイと同一階層やそのサブフォルダーに振り分けするルールの場合に「xxx¥yyy」というような形で出力するよう修正したマクロは以下の様になります。

' 特定の人から受信したメッセージをフォルダーに移動するルールのみ CSV にエクスポートするマクロ 階層対応版
Public Sub ExportMoveBySenderRules2()
     On Error Resume Next
     ' 移動ルールをエクスポートする CSV ファイルのファイル名
     Const CSV_FILE = "c:\temp\moverules.csv"
     Dim fldRoot As Folder
     Dim colRules As Rules
     Dim oneRule As Rule
     Dim oneRec As Recipient
     Dim strAddr As String
     Dim strFolder As String
     ' エクスポートする CSV ファイルを書き込み用に開く
     Open CSV_FILE For Output As #1
     ' 1 行目にヘッダーを書き込む
     Print #1, "フォルダー名,アドレス"
     ' ルート フォルダーの取得
     Set fldRoot = Session.DefaultStore.GetRootFolder()
     ' ルール一覧を取得
     Set colRules = Session.DefaultStore.GetRules
     ' ルールを一つずつ処理
     For Each oneRule In colRules
         strFolder = ""
         strAddr = ""
         ' フォルダー移動のアクションかの確認
         With oneRule.Actions.MoveToFolder
             ' フォルダー移動のアクションが設定されていたら
             If Not .Folder Is Nothing Then
                 ' フォルダーパスを取得
                 strFolder = GetFolderPath(.Folder, fldRoot)
             End If
         End With
         ' 差出人を条件とするかの確認
         With oneRule.Conditions.From
             ' 差出人が条件に設定されていたら
             If .Recipients.Count > 0 Then
                 ' 受信者ごとに処理
                 For Each oneRec In .Recipients
                     ' 受信者のアドレスを ; で区切って連結
                     strAddr = strAddr & oneRec.AddressEntry.Address & ";"
                 Next
                 ' 最後の余計な ; を削除
                 strAddr = Left(strAddr, Len(strAddr) - 1)
             End If
         End With
         ' 移動先フォルダーと差出人の両方がルールにあったら
         If strFolder <> "" And strAddr <> "" Then
             ' CSV ファイルに書き込み
             Print #1, strFolder; ","; strAddr
         End If
     Next
     Close #1
End Sub
' フォルダーのパスを取得する関数
Private Function GetFolderPath(fldSub As Folder, fldRoot As Folder) As String
     Dim strPath As String
     ' サブフォルダーの名前をパスに設定
     strPath = fldSub.Name
     ' 親フォルダーを取得
     Set fldSub = fldSub.Parent
     ' 親フォルダーがルート フォルダーになるまで繰り返す
     While fldSub.EntryID <> fldRoot.EntryID
         ' 親フォルダーの名前をパスの先頭に追加
         strPath = fldSub.Name & "\" & strPath
         ' さらに親フォルダーを取得
         Set fldSub = fldSub.Parent
     Wend
     ' 生成したフォルダー パスを返す
     GetFolderPath = strPath
End Function

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

特定の分類項目が設定されているアイテムを CSV に従って移動するマクロ 階層対応版

特定の分類項目が設定されているアイテムを CSV に従って移動するマクロのコメントにて以下のご要望をいただきました。


振り分け先を、受信トレイのサブフォルダーでなく、受信トレイや送信済みアイテムと同じ階層の別名フォルダーにすることは可能でしょうか。また、それら別名フォルダーをさらに階層化して

受信トレイ
振り分け先1
振り分け先1(サブ1)
振り分け先1(サブ2)
振り分け先2

お伺いしてばかりで申し訳ございません。


移動先のフォルダーをルートから指定し、¥ でパスを区切って指定できるように以前のマクロを修正しました。
例えば、「受信トレイ」の下の「フォルダーA」に移動する場合は「受信トレイ¥フォルダーA」、受信トレイと同じ階層の「振り分け先1」に移動する場合は「振り分け先1」、その下の「サブ1」に移動する場合は「振り分け先1¥サブ1」と CSV のフォルダー名に指定します。

'

' 特定の分類項目が設定されているアイテムを CSV に従って移動するマクロ
Public Sub MoveItemsBySenderInCSV2()
     ' 移動対象となる分類項目の設定
     Const MOVE_MARK = "処理完了"
     Dim dicRules As Scripting.Dictionary
     Dim fldInbox As Folder
     Dim i As Integer
     Dim objItem As Object
     Dim strAddr As String
     Dim strPath As String
     Dim fldDest As Folder
     ' CSV ファイルの内容を Dictionary に読み込み
     Set dicRules = CreateObject("Scripting.Dictionary")
     ImportRulesFromCSV dicRules
     '
     Set fldInbox = Session.GetDefaultFolder(olFolderInbox)
     ' 受信トレイのアイテムを最後から確認
     For i = fldInbox.Items.Count To 1 Step -1
         Set objItem = fldInbox.Items(i)
         ' 処理対象となる分類項目が設定されていたら
         If InStr(objItem.Categories, MOVE_MARK) > 0 Then
             ' 差出人のアドレスを取得
             strAddr = UCase(objItem.SenderEmailAddress)
             ' Dictionary にアドレスが設定されていたら
             If dicRules.Exists(strAddr) Then
                 ' アイテムを指定されたパスに移動
                 strPath = dicRules(strAddr)
                 MoveItemsToSubFolder objItem, strPath
             End If
         End If
     Next
End Sub
'
' アイテムを指定されたパスに移動するマクロ
Public Sub MoveItemsToSubFolder(objItem As Object, strPath As String)
     Dim fldRoot As Folder
     Dim fldDest As Folder
     ' ルートフォルダーを取得
     Set fldRoot = Session.GetDefaultFolder(olFolderInbox).Parent
     ' パスが 1 階層のみならルート直下のフォルダーに移動
     If InStr(strPath, "\") = 0 Then
         objItem.Move fldRoot.Folders(strPath)
     Else
         Dim arrPath As Variant
         Dim strFolder As Variant
         ' パスを \ で分割
         arrPath = Split(strPath, "\")
         Set fldDest = fldRoot
         ' 分割したパスごとにフォルダーをたどる
         For Each strFolder In arrPath
             Set fldDest = fldDest.Folders(strFolder)
         Next
         ' たどり着いたフォルダーに移動
         objItem.Move fldDest
     End If
End Sub
'
' CSV ファイルの内容を Dictionary オブジェクトに読み込むマクロ
Private Sub ImportRulesFromCSV(dicRules As Object)
     ' 移動ルールが格納されている CSV ファイルのファイル名
     Const CSV_FILE = "c:\temp\moverules.csv"
     Dim strFolder As String
     Dim strAddrs As String
     Dim arrAddrs As Variant
     Dim strAddr As Variant
     ' CSV ファイルを読み込みのため開く
     Open CSV_FILE For Input As #1
     ' 1 行目はヘッダーのためスキップ
     Line Input #1, strFolder
     ' ファイルの終わりまで繰り返す
     While Not EOF(1)
         ' CSV からフォルダーとアドレスを読み込み
         Input #1, strFolder, strAddrs
         strAddrs = UCase(strAddrs)
         ' アドレスに ; が含まれていなければ単一のアドレス
         If InStr(strAddrs, ";") = 0 Then
             ' アドレスが Dictionary になければ
             If Not dicRules.Exists(strAddrs) Then
                 ' アドレスをキーとしてフォルダー名を Dictionary に追加
                 dicRules.Add strAddrs, strFolder
             End If
         Else
             ' ; を区切りとして文字列を分割
             arrAddrs = Split(strAddrs, ";")
             ' 分割したアドレスごとに処理
             For Each strAddr In arrAddrs
                 ' アドレスが Dictionary になければ
                 If Not dicRules.Exists(strAddr) Then
                     ' アドレスをキーとしてフォルダー名を Dictionary に追加
                     dicRules.Add strAddr, strFolder
                 End If
             Next
         End If
     Wend
     Close #1
End Sub


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

差出人をもとにフォルダーに振り分けるルールを CSV ファイルにエクスポートするマクロ

先週作成したマクロについては、以下のような追加のご要望もありました。


すみません。欲を言えば、設定済みルールをExcelかCSVに書き出し(.rwzという特殊な仕様でなく)、またExcelやCSVで作成したリストからルールを読み込むようなことが出来れば素晴らしいのですが。VBA追加分だけでも、Excel等の外部リストから読み込んで仕訳けが出来れば大変に助かります。よろしくお願いいたします。


自動仕分けのルールについては Outlook Object モデルでアクセスできないものや、データ化が難しいものもあり、丸ごとエクスポートということは困難です。
しかし、特定の条件とアクションのみに限定するということであればエクスポートできるものもあります。

「特定の人から受信したメッセージをフォルダーに移動する」というルールを、先週のマクロで読み込み可能な形式の CSV ファイルにエクスポートするマクロは以下のようになります。

'

' 特定の人から受信したメッセージをフォルダーに移動するルールのみ CSV にエクスポートするマクロ
Public Sub ExportMoveBySenderRules()
     On Error Resume Next
     ' 移動ルールをエクスポートする CSV ファイルのファイル名
     Const CSV_FILE = "c:\temp\moverules.csv"
     Dim colRules As Rules
     Dim oneRule As Rule
     Dim oneRec As Recipient
     Dim strAddr As String
     Dim strFolder As String
     ' エクスポートする CSV ファイルを書き込み用に開く
     Open CSV_FILE For Output As #1
     ' 1 行目にヘッダーを書き込む
     Print #1, "フォルダー名,アドレス"
     ' ルール一覧を取得
     Set colRules = Session.DefaultStore.GetRules
     ' ルールを一つずつ処理
     For Each oneRule In colRules
         strFolder = ""
         strAddr = ""
         ' フォルダー移動のアクションかの確認
         With oneRule.Actions.MoveToFolder
             ' フォルダー移動のアクションが設定されていたら
             If Not .Folder Is Nothing Then
                 ' フォルダー名を取得
                 strFolder = .Folder.Name
             End If
         End With
         ' 差出人を条件とするかの確認
         With oneRule.Conditions.From
             ' 差出人が条件に設定されていたら
             If .Recipients.Count > 0 Then
                 ' 受信者ごとに処理
                 For Each oneRec In .Recipients
                     ' 受信者のアドレスを ; で区切って連結
                     strAddr = strAddr & oneRec.AddressEntry.Address & ";"
                 Next
                 ' 最後の余計な ; を削除
                 strAddr = Left(strAddr, Len(strAddr) - 1)
             End If
         End With
         ' 移動先フォルダーと差出人の両方がルールにあったら
         If strFolder <> "" And strAddr <> "" Then
             ' CSV ファイルに書き込み
             Print #1, strFolder; ","; strAddr
         End If
     Next
     Close #1
End Sub

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

特定の分類項目が設定されているアイテムを CSV に従って移動するマクロ

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


「特定の分類項目にマークしたInboxメールのメールアドレスによるフォルダーへの仕分け」

種々VBA情報のご提供本当にありがとうございます。題記につきお伺いします。

(初心者で、自前で作成を試みていますがつまずいてます。)

現状、この作業はOutlook標準の仕分けルールを使って作業していますが、仕分け

に登録できる項目に容量制限があり、追加登録が出来なくなりました。

VBAコードをお教えいただけますと大変幸甚です。

ありがとうございます。ご理解のとおり、「差出人のメールアドレスによるフォルダーの仕分け」が希望です。ただし、仕分けるのは分類項目で「処理完了」のフラグを立てたもののみとし、そうでない場合はルールがヒットしても受信トレイに残すことを希望します

すでにOutlookの仕訳ルールで400件以上のルールを設定しましたが、それらはそのまま残し、登録しきれなかった追加仕訳分のみサブルール的にVBA処理を行うことを希望します。

(本当はOutlookで、仕訳も含む記録領域を増やすことが好ましい方向であろうことは理解します。)

よろしくお願いいたします。   


以下のようなフォーマットの CSV ファイルを読み込み、特定の分類項目が設定されているメールについて CSV ファイルの内容に基づいて移動するマクロを作りました。

フォルダー名,アドレス
Folder1,user1@example.com
Folder2,user2@example.com;user3@example.com

フォルダーは受信トレイのサブフォルダーとして存在するものと仮定しています。
また、複数の差出人を同じフォルダーに振り分ける場合は、; で区切って指定することでルールを 1 行にまとめられるようにしました。

このマクロのポイントは Dictionary オブジェクトを使ったことにあります。
Dictionary オブジェクトは VBA の組み込み機能ですが、これを使うと任意の文字列または数字のキーとペアとなるアイテムのデータが扱えるようになり、メールアドレスごとの振り分け先のフォルダーの検索というような処理が非常に簡単になります。

マクロは以下の通りです。

' 特定の分類項目が設定されているアイテムを CSV に従って移動するマクロ
Public Sub MoveItemsBySenderInCSV()
     ' 移動対象となる分類項目の設定
     Const MOVE_MARK = "処理完了"
     Dim dicRules As Object
     Dim fldInbox As Folder
     Dim i As Integer
     Dim objItem As Object
     Dim strAddr As String
     Dim strFolder As String
     Dim fldDest As Folder
     ' CSV ファイルの内容を Dictionary に読み込み
     Set dicRules = CreateObject("Scripting.Dictionary")
     ImportRulesFromCSV dicRules
     ' 受信トレイを取得
     Set fldInbox = Session.GetDefaultFolder(olFolderInbox)
     ' 受信トレイのアイテムを最後から確認
     For i = fldInbox.Items.Count To 1 Step -1
         Set objItem = fldInbox.Items(i)
         ' 処理対象となる分類項目が設定されていたら
         If InStr(objItem.Categories, MOVE_MARK) > 0 Then
             ' 差出人のアドレスを取得
             strAddr = objItem.SenderEmailAddress
             ' Dictionary にアドレスが設定されていたら
             If dicRules.Exists(strAddr) Then
                 ' Dictionary からフォルダー名を取得
                 strFolder = dicRules(strAddr)
                 ' 受信トレイのサブフォルダーを取得
                 Set fldDest = fldInbox.Folders(strFolder)
                 ' アイテムを指定されたフォルダーに移動
                 objItem.Move fldDest
             End If
         End If
     Next
End Sub
'
' CSV ファイルの内容を Dictionary オブジェクトに読み込むマクロ
Private Sub ImportRulesFromCSV(dicRules As Object)
     ' 移動ルールが格納されている CSV ファイルのファイル名
     Const CSV_FILE = "c:\temp\moverules.csv"
     Dim strFolder As String
     Dim strAddrs As String
     Dim arrAddrs As Variant
     Dim strAddr As Variant
     ' CSV ファイルを読み込みのため開く
     Open CSV_FILE For Input As #1
     ' 1 行目はヘッダーのためスキップ
     Line Input #1, strFolder
     ' ファイルの終わりまで繰り返す
     While Not EOF(1)
         ' CSV からフォルダーとアドレスを読み込み
         Input #1, strFolder, strAddrs
         ' アドレスに ; が含まれていなければ単一のアドレス
         If InStr(strAddrs, ";") = 0 Then
             ' アドレスが Dictionary になければ
             If Not dicRules.Exists(strAddrs) Then
                 ' アドレスをキーとしてフォルダー名を Dictionary に追加
                 dicRules.Add strAddrs, strFolder
             End If
         Else
             ' ; を区切りとして文字列を分割
             arrAddrs = Split(strAddrs, ";")
             ' 分割したアドレスごとに処理
             For Each strAddr In arrAddrs
                 ' アドレスが Dictionary になければ
                 If Not dicRules.Exists(strAddr) Then
                     ' アドレスをキーとしてフォルダー名を Dictionary に追加
                     dicRules.Add strAddr, strFolder
                 End If
             Next
         End If
     Wend
     Close #1
End Sub

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