How to move email to folder based on the sender domain - vba

The attached script on selected emails, create a folder on a non-default PST (OutlookEmail.PST) based on the sender name and move the email to the folder. For e.g MyTest#thisdomain.com, it creates a folder MyTest.
I need advise modifying the script that it creates a folder based on the sender domain for e.g thisdomain.com with subfolder MyTest and then move the email.
This macro is from https://www.slipstick.com/developer/file-messages-senders-name/
Public Sub MoveSelectedMessages()
Dim objOutlook As Outlook.Application
Dim objNamespace As Outlook.NameSpace
Dim objDestFolder As Outlook.MAPIFolder
Dim objSourceFolder As Outlook.Folder
Dim currentExplorer As Explorer
Dim Selection As Selection
Dim obj As Object
Dim objVariant As Variant
Dim lngMovedItems As Long
Dim intCount As Integer
Dim intDateDiff As Integer
Dim strDestFolder As String
Set objOutlook = Application
Set objNamespace = objOutlook.GetNamespace("MAPI")
Set currentExplorer = objOutlook.ActiveExplorer
Set Selection = currentExplorer.Selection
Set objSourceFolder = currentExplorer.CurrentFolder
For Each obj In Selection
Set objVariant = obj
If objVariant.Class = olMail Then
intDateDiff = DateDiff("d", objVariant.SentOn, Now)
' I'm using 40 days, adjust as needed.
If intDateDiff >= 0 Then
sSenderName = objVariant.SentOnBehalfOfName
If sSenderName = ";" Then
sSenderName = objVariant.senderName
End If
On Error Resume Next
' Use These lines if the destination folder is not a subfolder of the current folder
'Dim objInbox As Outlook.MAPIFolder
'Set objInbox = objNamespace.Folders(objDestFolder).Folders("OutlookEmail") ' or whereever the folder is
'Set objDestFolder = objInbox.Folders(sSenderName)
Set objDestFolder = objNamespace.Folders("OutlookEmail").Folders(sSenderName)
'Set objDestFolder = objDestFolder.Folders(sSenderName)
If objDestFolder Is Nothing Then
Set objDestFolder = objNamespace.Folders("OutlookEmail").Folders.Add(sSenderName)
End If
objVariant.Move objDestFolder
'count the # of items moved
lngMovedItems = lngMovedItems + 1
Set objDestFolder = Nothing
End If
End If
Err.Clear
Next
' Display the number of items that were moved.
' MsgBox "Moved " & lngMovedItems & " messages(s)."
Set currentExplorer = Nothing
Set obj = Nothing
Set Selection = Nothing
Set objOutlook = Nothing
Set objNamespace = Nothing
Set objSourceFolder = Nothing
End Sub
A modification that creates the domain but not the subfolder:
If intDateDiff >= 0 Then
sSenderName = Right(objVariant.SenderEmailAddress, Len(objVariant.SenderEmailAddress) - InStr(objVariant.SenderEmailAddress, "#"))

This second version takes into account exchange addresses. No applicable mail available for testing.
Option Explicit ' Consider this mandatory
' Tools | Options | Editor tab
' Require Variable Declaration
Public Sub MoveSelectedMessages_ExchangeSMTP()
Dim objSenderDomainFolder As folder
Dim strSenderDomain As String
Dim strSenderEmailAddress As String
Dim objDestFolder As folder
Dim strDest As String
Dim Selection As Selection
Dim obj As Object
'Dim intDateDiff As Long
Set Selection = ActiveExplorer.Selection
For Each obj In Selection
If obj.Class = olmail Then
Debug.Print obj.Subject
'intDateDiff = dateDiff("d", obj.SentOn, Now)
'Debug.Print "intDateDiff: " & intDateDiff
'If intDateDiff >= 0 Then ' Not needed for 0
If obj.SenderEmailType = "EX" Then ' exchange
strSenderEmailAddress = obj.Sender.GetExchangeUser().PrimarySmtpAddress
Else ' smtp
strSenderEmailAddress = obj.SenderEmailAddress
End If
Debug.Print "SenderEmailAddress: " & strSenderEmailAddress
strSenderDomain = Right(strSenderEmailAddress, _
Len(strSenderEmailAddress) - InStr(strSenderEmailAddress, "#"))
Debug.Print "strSenderDomain: " & strSenderDomain
strDest = Left(strSenderEmailAddress, InStr(strSenderEmailAddress, "#") - 1)
Debug.Print "strDest: " & strDest
On Error Resume Next
' Bypass error if sSenderDomain folder does not exist, leaving objSenderDomainFolder as Nothing
Set objSenderDomainFolder = Session.folders("OutlookEmail").folders(strSenderDomain)
' Remove error bypass as soon as the purpose is served
On Error GoTo 0
If objSenderDomainFolder Is Nothing Then
Set objSenderDomainFolder = Session.folders("OutlookEmail").folders.Add(strSenderDomain)
End If
If Not objSenderDomainFolder Is Nothing Then
On Error Resume Next
' Bypass error if objDestFolder does not exist, leaving objDestFolder as Nothing
Set objDestFolder = objSenderDomainFolder.folders(strDest)
' Remove error bypass as soon as the purpose is served
On Error GoTo 0
If objDestFolder Is Nothing Then
Set objDestFolder = objSenderDomainFolder.folders.Add(strDest)
End If
obj.Move objDestFolder
End If
' Reset to Nothing for the next iteration of the selection
' Important step due to the use of On Error Resume Next
Set objSenderDomainFolder = Nothing
Set objDestFolder = Nothing
'End If
End If
Next
End Sub
First version. SMTP addresses only.
Option Explicit ' Consider this mandatory
' Tools | Options | Editor tab
' Require Variable Declaration
Public Sub MoveSelectedMessages()
Dim objSenderDomainFolder As folder
Dim strSenderDomain As String
Dim objDestFolder As folder
Dim strDest As String
Dim Selection As Selection
Dim obj As Object
'Dim intDateDiff As Long
Set Selection = ActiveExplorer.Selection
For Each obj In Selection
If obj.Class = olMail Then
Debug.Print obj.Subject
'intDateDiff = dateDiff("d", obj.SentOn, Now)
'Debug.Print "intDateDiff: " & intDateDiff
'If intDateDiff >= 0 Then ' Not needed for 0
Debug.Print "SenderEmailAddress: " & obj.SenderEmailAddress
strSenderDomain = Right(obj.SenderEmailAddress, _
Len(obj.SenderEmailAddress) - InStr(obj.SenderEmailAddress, "#"))
Debug.Print "strSenderDomain: " & strSenderDomain
strDest = Left(obj.SenderEmailAddress, InStr(obj.SenderEmailAddress, "#") - 1)
Debug.Print "strDest: " & strDest
On Error Resume Next
' Bypass error if sSenderDomain folder does not exist,
' leaving objSenderDomainFolder as Nothing
Set objSenderDomainFolder = _
Session.folders("OutlookEmail").folders(strSenderDomain)
' Remove error bypass as soon as the purpose is served
On Error GoTo 0
If objSenderDomainFolder Is Nothing Then
Set objSenderDomainFolder = _
Session.folders("OutlookEmail").folders.Add(strSenderDomain)
End If
If Not objSenderDomainFolder Is Nothing Then
On Error Resume Next
' Bypass error if objDestFolder does not exist,
' leaving objDestFolder as Nothing
Set objDestFolder = objSenderDomainFolder.folders(strDest)
' Remove error bypass as soon as the purpose is served
On Error GoTo 0
If objDestFolder Is Nothing Then
Set objDestFolder = objSenderDomainFolder.folders.Add(strDest)
End If
obj.Move objDestFolder
End If
' Reset to Nothing for the next iteration of the selection
' Important step due to the use of On Error Resume Next
Set objSenderDomainFolder = Nothing
Set objDestFolder = Nothing
'End If
End If
Next
End Sub

To get the domain name try
DomainName = Mid$(EmailAddress, InStrRev(EmailAddress, "#") + 1, _
InStrRev(EmailAddress, ".") - _
InStrRev(EmailAddress, "#") - 1)
To get the sender name try
SenderName = Left(EmailAddress, InStr(EmailAddress, "#") - 1)

Related

Sum all email.Items from Inbox + subfolders

Goodafternoon,
I am populating an list box with all the emails from Inbox + Subfolders, via Table object. This is working fine.
Then, with Doubleclick events from ListBox1, I am trying to open the email that is been selected. If the loop is going only through Inbox folder, it is going correct. But when I'm trying to loop through SubFolders from Inbox, it is not going. So I am trying to collect(sum) all the emails from Inbox + subfolder in one:
Set InboxItems = SubFolder.Items
But offcorse it is not working. What can be done?
my code:
Option Explicit
Private Sub ListBox1_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
Dim objNS As Outlook.namespace: Set objNS = GetNamespace("MAPI")
Dim oFolder As Outlook.MAPIFolder: Set oFolder = objNS.GetDefaultFolder(olFolderInbox)
Dim i As Long
Dim j As Long
Dim InboxItems As Outlook.Items
Dim thisEmail As Outlook.MailItem
Dim SubFolder As Outlook.MAPIFolder
Dim myArray() As String
Dim Folders As New Collection
Dim entryID As New Collection
Dim StoreID As New Collection
Call GetFolder(Folders, entryID, StoreID, oFolder)
myArray = ConvertToArray(indexEmailInbox)
For j = 1 To Folders.Count
Set SubFolder = Application.Session.GetFolderFromID(entryID(j), StoreID(j))
Set InboxItems = SubFolder.Items
Next
For i = LBound(myArray) To UBound(myArray)
If Me.ListBox1.Selected(i) = True Then
If TypeName(InboxItems.Item(onlyDigits(myArray(i)))) = "MailItem" Then ' it's an email
'MsgBox onlyDigits(myArray(UBound(myArray) - i - 1))
Set thisEmail = InboxItems.Item(onlyDigits(myArray(UBound(myArray) - i - 1)))
Unload Me
thisEmail.Display
Exit Sub
End If
End If
Next i
End Sub
Function ConvertToArray(ByVal value As String)
value = StrConv(value, vbUnicode)
ConvertToArray = Split(Left(value, Len(value) - 1), "§")
End Function
Sub GetFolder(folders As Collection, entryID As Collection, StoreID As Collection, fld As MAPIFolder)
Dim SubFolder As MAPIFolder
folders.Add fld.FolderPath
entryID.Add fld.entryID
StoreID.Add fld.StoreID
For Each SubFolder In fld.folders
GetFolder folders, entryID, StoreID, SubFolder
Next SubFolder
ExitSub:
Set SubFolder = Nothing
End Sub
You may .Add items to a collection one at a time.
Option Explicit ' Consider this mandatory
' Tools | Options | Editor tab
' Require Variable Declaration
' If desperate declare as Variant
Private Sub collection_Emails_Folder_And_Subfolders()
Dim objFolder As folder
Dim myItemsCol As New Collection
Dim i As Long
Dim myItems As Items
Set objFolder = Session.PickFolder
If objFolder Is Nothing Then
Exit Sub
End If
'Set objFolder = Session.GetDefaultFolder(olFolderInbox)
processFolder objFolder, myItemsCol
' Methods available are limited to:
' Add, Count, Item and Remove
Debug.Print vbCr & "Final total - myItemsCol.Count: " & myItemsCol.Count
' You may access item properties
For i = 1 To myItemsCol.Count
Debug.Print " " & i & ": " & myItemsCol(i).ReceivedTime, myItemsCol(i).subject
Next i
End Sub
Private Sub processFolder(ByVal objFolder As folder, ByVal myItemsCol As Collection)
' https://stackoverflow.com/questions/2272361/can-i-iterate-through-all-outlook-emails-in-a-folder-including-sub-folders
Dim EmailCount As Long
Dim myItem As Object
Dim myItems As Items
Dim i As Long
Dim oFolder As folder
Debug.Print vbCr & "objFolder: " & objFolder
EmailCount = objFolder.Items.Count
Debug.Print " EmailCount...: " & EmailCount
If EmailCount > 0 Then
Set myItems = objFolder.Items
myItems.Sort "[ReceivedTime]", False ' oldest to newest
For i = 1 To myItems.Count
'Debug.Print " " & i & ": " & myItems(i).ReceivedTime, myItems(i).subject
myItemsCol.Add myItems(i)
Next
End If
Debug.Print " Running total: " & myItemsCol.Count
If (objFolder.Folders.Count > 0) Then
For Each oFolder In objFolder.Folders
processFolder oFolder, myItemsCol
Next
End If
End Sub
You should be able to replace InboxItems with myItemsCol.
If TypeName(myItemsCol.Item((onlyDigits(myArray(i)))) = "MailItem" Then ' it's an email
Set thisEmail = myItemsCol.Item(onlyDigits(myArray(UBound(myArray) - i - 1)))
It seems you just need to iterate over all subfolders in Outlook to get the number of items per folder.
Sub Test()
Set objOutlook = CreateObject( "Outlook.Application" )
Set objNamespace = objOutlook.GetNamespace( "MAPI" )
Set folders = objNamespace.DefaultStore.GetRootFolder().Folders
EnumFolders folders
End Sub
Dim counter as Long = 0
' recursively invoked function
Sub EnumFolders(folders)
For Each folder In folders
Debug.Print folder.FolderPath
Debug.Print folder.Count
counter = counter + folder.Items.Count
EnumFolders folder.Folders
Next
End Sub

Count Outlook emails by Sender & date in Excel VBA

The objective is to find the total/count of emails from Sender on Monthly basis.
The below code retrieves Date/Time for a count by month.
How to display by SenderName on the worksheet?
I'm not sure if I've to use two dictionaries? If yes no knowledge about how to work around it.
Sub ReferSpecificFolder()
'Declare Outlook application & folder object variables.
Dim objOutlook as Object, objnSpace as Object, objFolder As Outlook.MAPIFolder
Dim olItem As Variant 'Object
Dim dictDate as Object
Set objOutlook = CreateObject("Outlook.Application")
Set objnSpace=objOutlook.GetNamespace("MAPI")
Set objFolder = objOutlook.GetNamespace("MAPI").Folders("xyz#microsoft.com").Folders("Sales - 2020")
Set dictDate=CreateObject("Scripting.Dictionary")
Set myItems = objFolder.Items
On Error Resume Next
If Err.Number <> 0 Then
Err.Clear
MsgBox "No such folder!"
Exit Sub
End If
If fldr.Items.Count = 0 Then
MsgBox "There were no messages found in your folders"
Exit Sub
End If
'Select the sheet to enter the data
Dim wbData As Worksheet
Dim LastRow As Long
Set wbData = ThisWorkbook.Sheets("Rawdata - Time Period")
LastRow = wbData.Range("A" & wbData.Rows.Count).End(xlUp).Row + 1
myItems.SetColumns("SenderName, SentOn")
For Each i In myItems
dateStr=GetDate(i.SentOn)
strSender=i.SenderName
If Not dictDate.Exists(dateStr) Then
dictDate(dateStr)=0
End If
dictDate(dateStr)=CLng(dictDate(dateStr))+1
Next i
For Each o In dictDate.keys
LastRow = wbData.Range("A" & wbData.Rows.Count).End(xlUp).Row + 1
With wbData
.Cells(LastRow, 1) = o 'Received Date
.Cells(LastRow, 3) = dictDate(o) 'Count
End With
Next o
Set fldr = Nothing
Set olItem = Nothing
Set olApp = Nothing
MsgBox "DONE!"
End Sub
Function GetDate(dt as Date) as String
GetDate=Year(dt) & "-" & Month(dt) & "-" & Day(dt) & " " & Hour(dt) & ":" & Minute(dt)
End Function
This generates a single sender dictionary then a date dictionary corresponding to each entry in the sender dictionary.
Option Explicit ' Consider this mandatory
' Tools | Options | Editor tab
' Require Variable Declaration
'
' If desperate declare as Variant
'
Sub ReferSpecificFolderSender()
' Early binding, must set a reference to
' Microsoft Outlook XX.X Object Library
Dim objOutlook As Outlook.Application
Dim objnSpace As Outlook.Namespace
Dim objFolder As Outlook.Folder
Dim olItemI As Object
Dim olItemJ As Object
Dim myItems As Outlook.Items
Dim myItemsDate As Outlook.Items
Dim strFilter As String
Dim dictDate As Object
Dim o As Variant
Dim dateStr As String
Dim dictSender As Object
Dim p As Variant
Dim strSender As String
Set objOutlook = CreateObject("Outlook.Application")
Set objnSpace = objOutlook.GetNamespace("MAPI")
' For the specific purpose of addressing an expected error
' due to not finding objFolder
On Error Resume Next
Set objFolder = objnSpace.Folders("xyz#microsoft.com").Folders("Sales - 2020")
If Err.Number <> 0 Then
Err.Clear
'MsgBox "No such folder!"
'Exit Sub
Set objFolder = objnSpace.PickFolder
If objFolder Is Nothing Then Exit Sub
End If
' Consider mandatory to closely follow On Error Resume Next
' Return to normal error handling
On Error GoTo 0
Set myItems = objFolder.Items
Debug.Print vbCr & "myItems.Count: " & myItems.Count
If objFolder.Items.Count = 0 Then
MsgBox "There were no messages found in " & objFolder.FolderPath
Exit Sub
End If
Set dictSender = CreateObject("Scripting.Dictionary")
' Restrict to mailitems
' 0x001A001F
' https://stackoverflow.com/questions/61793354/delete-items-in-outlook-by-type-or-message-class
'strFilter = "#SQL=""http://schemas.microsoft.com/mapi/proptag/0x001A001F"" LIKE 'IPM.Note'"
'Set myItems = myItems.Restrict(strFilter)
' 0x001A001E
' "PR_MESSAGE_CLASS" http://schemas.microsoft.com/mapi/proptag/0x001A001E
' https://www.slipstick.com/developer/read-mapi-properties-exposed-outlooks-object-model/
strFilter = "#SQL=""http://schemas.microsoft.com/mapi/proptag/0x001A001E"" LIKE 'IPM.Note'"
Set myItems = myItems.Restrict(strFilter)
Debug.Print vbCr & "Mailitems"
Debug.Print "myItems.Count: " & myItems.Count
myItems.Sort "[SenderName]", False
Set dictDate = CreateObject("Scripting.Dictionary")
Set myItemsDate = myItems
Debug.Print "myItemsDate.Count: " & myItemsDate.Count
'The sheet to enter the data
Dim wbData As Worksheet
Dim LastRow As Long
Set wbData = ThisWorkbook.Sheets("Rawdata - Time Period")
LastRow = wbData.Range("A" & wbData.Rows.Count).End(xlUp).Row + 1
' dictionary of sender names
Debug.Print "Sender dictionary"
' With the SetColumns method, Outlook only checks the properties that you have cached,
' and provides fast, read-only access to these properties.
' https://learn.microsoft.com/en-us/office/vba/api/outlook.items.setcolumns
myItems.SetColumns ("SenderName")
For Each olItemJ In myItems
strSender = olItemJ.SenderName
If Not dictSender.Exists(strSender) Then
Debug.Print " " & strSender
dictSender(strSender) = 0
End If
dictSender(strSender) = CLng(dictSender(strSender)) + 1
Next
' iterate unique sender names
For Each p In dictSender.keys
Debug.Print "Date dictionary for: " & p
myItems.Sort "[SentOn]", False
myItemsDate.SetColumns ("SenderName, SentOn")
' check item's date against the sender name dictionary
For Each olItemI In myItemsDate
strSender = olItemI.SenderName
If strSender = p Then
' unique dates for current SenderName
dateStr = GetDate(olItemI.SentOn)
If Not dictDate.Exists(dateStr) Then
dictDate(dateStr) = 0
End If
' count of ccurrences for each date
dictDate(dateStr) = CLng(dictDate(dateStr)) + 1
End If
Next
For Each o In dictDate.keys
LastRow = wbData.Range("A" & wbData.Rows.Count).End(xlUp).Row + 1
With wbData
.Cells(LastRow, 1) = p ' SenderName
.Cells(LastRow, 2) = o ' GetDate value
.Cells(LastRow, 3) = dictDate(o) ' Count
End With
Next
' delete date dictionary entries for current SenderName
dictDate.RemoveAll
Next p
ActiveSheet.Columns.AutoFit
Set objFolder = Nothing
Set olItemI = Nothing
Set olItemJ = Nothing
Set objOutlook = Nothing
Set objnSpace = Nothing
Set dictSender = Nothing
Set dictDate = Nothing
Set myItemsDate = Nothing
Debug.Print "DONE!"
'MsgBox "DONE!"
End Sub

Move e-mails by senderemailaddress outlook macro

I want to move some messages from Inbox to a subfolder but this code (that I have copied from other forum) is not working. Can you tell me what is going wrong? Do you think it is not working because of the fact that I have two different accounts in this Outlook?
Public Sub Move_Items()
'// Declare your Variables
Dim Inbox As Outlook.MAPIFolder
Dim SubFolder As Outlook.MAPIFolder
Dim olNs As Outlook.NameSpace
Dim Item As Object
Dim Items As Outlook.Items
Dim lngCount As Long
On Error GoTo MsgErr
Set Inbox Reference
Set olNs = Application.GetNamespace("MAPI")
Set Inbox = Application.ActiveExplorer.CurrentFolder
Set Items = Inbox.Items
'// Loop through the Items in the folder backwards
For lngCount = Inbox.Items.Count To 1 Step -1
Set Item = Inbox.Items.Item(lngCount)
If Item.Class = olMail Then
Select Case Item.SenderEmailAddress
'// Email_One
Case "bb"
// Set SubFolder of Inbox
Set SubFolder = Inbox.Folders("BB")
Set Item = Items.Find("[SenderEmailAddress] = 'bb#gmail.com'")
If TypeName(Item) <> "Nothing" Then
// Mark As Read
Item.UnRead = False
// Move Mail Item to sub Folder
Item.Move SubFolder
End If
'// Email_Two
Case "aa"
'// Set SubFolder of Inbox
Set SubFolder = Inbox.Folders("AA")
Set Item = Items.Find("[SenderEmailAddress] = 'aa#gmail.com'")
If TypeName(Item) <> "Nothing" Then
'// Mark As Read
Item.UnRead = False
'// Move Mail Item to sub Folder
Item.Move SubFolder
End If
Case Else:
Exit Sub
End Select
End If
Next lngCount
MsgErr_Exit:
Set Inbox = Nothing
Set SubFolder = Nothing
Set olNs = Nothing
Set Item = Nothing
Set Items = Nothing
Exit Sub
'// Error information
MsgErr:
MsgBox "An unexpected Error has occurred." _
& vbCrLf & "Error Number: " & Err.Number _
& vbCrLf & "Error Description: " & Err.Description _
, vbCritical, "Error!"
Resume MsgErr_Exit
End Sub
Your Select Case is not set correctly-
Case "bb" should be Case "bb#gmail.com" & Case "aa" should be Case "aa#gmail.com"
also Set SubFolder = Inbox.Folders("BB") BB should be your subfolder name
__
Option Explicit
Public Sub Move_Items()
'// Declare your Variables
Dim Inbox As Outlook.MAPIFolder
Dim SubFolder As Outlook.MAPIFolder
Dim Folder As Outlook.MAPIFolder '<- has been added
Dim olNs As Outlook.NameSpace
Dim Item As Outlook.MailItem
Dim Items As Outlook.Items
Dim lngCount As Long
' On Error GoTo MsgErr
'// Set Inbox Reference
Set olNs = Application.GetNamespace("MAPI")
Set Inbox = olNs.GetDefaultFolder(olFolderInbox)
Set Folder = Application.Session.PickFolder
Set Items = Inbox.Items
'// Loop through the Items in the folder backwards
For lngCount = Inbox.Items.Count To 1 Step -1
Set Item = Inbox.Items.Item(lngCount)
Debug.Print Item.Subject
If Item.Class = olMail Then
Select Case Item.SenderEmailAddress
' // Email_One
Case "bb#gmail.com"
' // Set SubFolder of Inbox
Set SubFolder = Inbox.Folders("Temp")
Set Item = Items.Find("[SenderEmailAddress] = 'bb#gmail.com'")
If TypeName(Item) <> "Nothing" Then
' // Mark As Read
Item.UnRead = False
' // Move Mail Item to sub Folder
Item.Move SubFolder
End If
' // Email_Two
Case "aa#gmail.com"
' // Set SubFolder of Inbox
Set SubFolder = Inbox.Folders("Temp")
Set Item = Items.Find("[SenderEmailAddress] = 'aa#gmail.com'")
If TypeName(Item) <> "Nothing" Then
' // Mark As Read
Item.UnRead = False
' // Move Mail Item to sub Folder
Item.Move SubFolder
End If
End Select
End If
Next lngCount
MsgErr_Exit:
Set Inbox = Nothing
Set SubFolder = Nothing
Set olNs = Nothing
Set Item = Nothing
Set Items = Nothing
Exit Sub
'// Error information
MsgErr:
MsgBox "An unexpected Error has occurred." _
& vbCrLf & "Error Number: " & Err.Number _
& vbCrLf & "Error Description: " & Err.Description _
, vbCritical, "Error!"
Resume MsgErr_Exit
End Sub

Move Mail from Sender to Sender's Folder Name

I want to move messages from the sender to the folder I created for the sender.
The SenderName is displayed as "Doe, John (US)" and my folder would be "Doe, John".
What do I need to do to compare the SenderName to a subfolder name that is two levels below "Inbox". I.e. Inbox→Folder1→"Doe, John".
Public Sub MoveToFolder()
Dim objOutlook As Outlook.Application
Dim objNameSpace As Outlook.NameSpace
Dim objDestFolder As Outlook.MAPIFolder
Dim objSourceFolder As Outlook.Folder
Dim currentExplorer As Explorer
Dim Selection As Selection
Dim obj As Object
Dim objSubfolder As Outlook.Folder
Dim olsubFolder As Outlook.Folder
Dim olApp As Outlook.Application
Dim objNS As Outlook.NameSpace
Dim olFolder As Outlook.MAPIFolder
Dim Msg As Outlook.MailItem
Dim objVariant As Variant
Dim lngMovedItems As Long
Dim intCount As Integer
Set objOutlook = Application
Set objNameSpace = objOutlook.GetNamespace("MAPI")
Set currentExplorer = objOutlook.ActiveExplorer
Set Selection = currentExplorer.Selection
Set objSourceFolder = currentExplorer.CurrentFolder
Set olApp = Outlook.Application
Set objNS = olApp.GetNamespace("MAPI")
Set olFolder = objNS.GetDefaultFolder(olFolderInbox)
Set olFolder = olFolder.Folders("Inbox")
Set colFolders = objParentFolder.Folders
For Each obj In Selection
Set objVariant = obj
Dim sfName As Object
Set sfName = Left(objVariant.senderName, Len(objVariant.senderName) - 5)
If objVariant.Class = olMail Then
On Error Resume Next
' Use These lines if the destination folder
' is not a subfolder of the current folder
For Each objSubfolder In colFolders
For Each olsubFolder In objSubfolder
If olsubFolder.Name = sfName Then
Set objDestFolder = objSubfolder
MsgBox "Ductus Exemplo"
'objVariant.Move objDestFolder
'count the # of items moved
lngMovedItems = lngMovedItems + 1
'Display the number of items that were moved.
MsgBox "Moved " & lngMovedItems & " messages(s) from " & _
sfName & "to " & objDestFolder
Else
If objDestFolder Is Nothing Then
MsgBox "No Folder Found for " & sfName
'Set objDestFolder = objSourceFolder.Folders.Add(sfName)
Exit Sub
End If
Next
Next
Next
End If
End Sub
Assumptions
The sender subfolders will be two levels below inbox but not under a single parent folder (i.e. "Doe, John" could appear under Folder1 and "Doe, Jane" under Folder2)
All emails that should be processed by the macro will be selected before executing it
The code should not create subfolders for missing senders - as there are multiple possible "parent" folders - but should output a message containing a list of missing sender folders
Conditions that trigger the end of a sender name:
A hyphen following or preceding a space (i.e. "Doe, John - US" = "Doe, John" and "Huntington-Whiteley, Rosie - CAN" = Huntington-Whiteley, Rosie")
The second instance of a comma (i.e. "Doe, John, CPA" = "Doe, John")
The second instance of a space (i.e. "Doe, John Q" = "Doe, John")
An apostrophe preceded or followed by a space (i.e. "O'Leary, John" = "O'Leary, John" but "Doe, John 'US'" = "Doe, John")
Any other non-alphabetical character (i.e. "Doe, John: US" = "Doe, John"
Proposed Solution
This code will satisfy all of the above conditions, and will output a single message at the end denoting any senders for whom folders could not be found (as opposed to a separate message for each email). It has been tested on Outlook 2013/Windows 10.
Public Sub MoveToFolder()
Dim objSelection As Selection
Set objSelection = Application.ActiveExplorer.Selection
Dim iSelected As Integer, iMoved As Integer
iSelected = objSelection.Count 'Get a total for output message
Dim StrOutput As String, StrUnmoved As String, StrName As String
StrUnmoved = "Unmoved Item Count by Sender" & vbNewLine & "============================"
Dim objNS As NameSpace
Dim objParentFolder As Folder, objSubFolder As Folder, objDestFolder As Folder
Dim BFound As Boolean, iLoc As Integer
Set objNS = Application.GetNamespace("MAPI")
Set objParentFolder = objNS.GetDefaultFolder(olFolderInbox)
'Only execute code if the parent folder has subfolders
If objParentFolder.Folders.Count > 0 Then
'Loop through all selected items
For Each Item In objSelection
If Item.Class = 43 Then
'This is an email.
BFound = False
StrName = GetSenderName(Item.SenderName)
For Each objSubFolder In objParentFolder.Folders
If objSubFolder.Folders.Count > 0 Then
On Error Resume Next
Set objDestFolder = Nothing
Set objDestFolder = objSubFolder.Folders(StrName)
On Error GoTo 0
If Not objDestFolder Is Nothing Then
'Folder found.
Item.Move objDestFolder
iMoved = iMoved + 1
BFound = True
Exit For
End If
End If
Next
If Not BFound Then
'Sender folder not found. Check if we have already logged this sender.
iLoc = 0
iLoc = InStr(1, StrUnmoved, StrName)
If iLoc > 0 Then
'Existing sender name. Increment current total.
StrUnmoved = Left(StrUnmoved, iLoc + Len(StrName) + 1) & _
Format(CInt(Mid(StrUnmoved, iLoc + Len(StrName) + 2, 5)) + 1, "00000") & Right(StrUnmoved, Len(StrUnmoved) - iLoc - Len(StrName) - 6)
Else
'New sender name.
StrUnmoved = StrUnmoved & vbNewLine & StrName & ": 00001"
End If
End If
End If
Next
If iMoved = iSelected Then
StrOutput = "All " & iSelected & " items moved to appropriate subfolders."
Else
'Remove extraneous zeroes
StrUnmoved = Replace(StrUnmoved, ": 000", ": ")
StrUnmoved = Replace(StrUnmoved, ": 00", ": ")
StrUnmoved = Replace(StrUnmoved, ": 0", ": ")
StrOutput = iMoved & "/" & iSelected & " items moved to appropriate subfolders; see below for unmoved details." & vbNewLine & vbNewLine & StrUnmoved
End If
MsgBox StrOutput
Else
MsgBox "There are no subfolders to the default inbox. Script will now exit."
End If
End Sub
Function GetSenderName(StrFullSender As String) As String
'Only take action if a non-null string is passed
If Len(StrFullSender) > 1 Then
StrFullSender = Trim(StrFullSender) 'Trim extraneous spaces
Dim StrOutput As String
'Find first case of the end of the name
Dim iChar As Integer
Dim iCommaCount As Integer
Dim iSpaceCount As Integer
For iChar = 1 To Len(StrFullSender)
Select Case Asc(Mid(StrFullSender, iChar, 1))
Case 65 To 90, 97 To 122 '192 to 246, 248 to 255 'Include 192-246 and 248-255 if you will receive emails from senders with accents or other symbols in their names
'No action necessary - this is a letter
Case 45, 151 'Hyphen or EM Dash - could be a hyphenated name
If Mid(StrFullSender, IIf(iChar = 1, 1, iChar - 1), IIf(Len(StrFullSender) - iChar > 1, 3, Len(StrFullSender) - iChar + 1)) <> _
Trim(Mid(StrFullSender, IIf(iChar = 1, 1, iChar - 1), IIf(Len(StrFullSender) - iChar > 1, 3, Len(StrFullSender) - iChar + 1))) Then Exit For
'There is a space on one or both sides of the hyphen. This is a valid stop.
Case 44
iCommaCount = iCommaCount + 1
If iCommaCount > 1 Then Exit For
Case 32
iSpaceCount = iSpaceCount + 1
If iSpaceCount > 1 Then Exit For
Case 39
If Mid(StrFullSender, IIf(iChar = 1, 1, iChar - 1), IIf(Len(StrFullSender) - iChar > 1, 3, Len(StrFullSender) - iChar + 1)) <> _
Trim(Mid(StrFullSender, IIf(iChar = 1, 1, iChar - 1), IIf(Len(StrFullSender) - iChar > 1, 3, Len(StrFullSender) - iChar + 1))) Then Exit For
'There is a space on one or both sides of the apostrophe. This is a valid stop.
Case Else
Exit For
End Select
Next
StrOutput = Trim(Left(StrFullSender, iChar - 1))
GetSenderName = StrOutput
End If
End Function
The goal appears to be organizing selected mail items based on the SenderName when invoked.
Have put a bit further as you can move items within a folder of choice when nothing in selection moved (ie. selected meeting items only).
When picking a folder to process items, the folder cannot be the main sub folder or it's child folders.
Option Explicit
Private Const SUB_FDR As String = "Folder1" ' The name of main sub-folder under Inbox to move mails to
Sub MoveSenderToFolder()
Dim oNS As NameSpace, oMainFDR As Folder, oSubFDR As Folder
Dim oItem As Variant, iMoved As Long
On Error Resume Next
Set oNS = Application.GetNamespace("MAPI")
On Error GoTo 0
If oNS Is Nothing Then
MsgBox "Cannot get MAPI namespace from Outlook! Abortting!", vbCritical + vbOKOnly, "MoveSenderToFolder()"
Else
' Proceed to Set Folders
Set oMainFDR = oNS.GetDefaultFolder(olFolderInbox)
' Get the sub folder "SUB_FDR" under Inbox
If Not oMainFDR Is Nothing Then Set oSubFDR = GetSubFolder(oMainFDR, SUB_FDR)
If oSubFDR Is Nothing Then
MsgBox "Cannot get the main sub folder """ & SUB_FDR & """ under """ & oMainFDR.Name & """"
Else
iMoved = 0
' [1] Process the Selected items
For Each oItem In ActiveExplorer.Selection
MoveItemToFolder oItem, oSubFDR, iMoved
Next
' [2] Ask to process a Folder if no MailItems are moved from Selection
If iMoved = 0 Then
If vbYes = MsgBox("Would you like to select a folder to move mail items?", vbQuestion + vbYesNo, "MoveSenderToFolder()") Then
Set oMainFDR = oNS.PickFolder ' Reuse oMainFDR object to the selected folder
' Only proceed if it's a folder not within Main Sub folder.
If Len(Replace(oMainFDR.FolderPath, oSubFDR.FolderPath, "")) = Len(oMainFDR.FolderPath) Then
For Each oItem In oMainFDR.Items
MoveItemToFolder oItem, oSubFDR, iMoved
Next
Else
MsgBox "Will not process folder/subfolders of the main folder """ & SUB_FDR & """", vbInformation + vbOKOnly, "MoveSenderToFolder()"
End If
End If
End If
Set oSubFDR = Nothing
Set oMainFDR = Nothing
End If
Set oNS = Nothing
MsgBox iMoved & " item(s) are moved.", vbInformation + vbOKOnly, "MoveSenderToFolder()"
End If
End Sub
' Move input item to a sub folder and increment counter
Private Sub MoveItemToFolder(ByRef oItem As Variant, ByRef oSubFDR As Folder, ByRef iMoved As Long)
Dim oMail As MailItem, sName As String, oTargetFDR As Folder
If TypeName(oItem) = "MailItem" Then
Set oMail = oItem
sName = GetSenderName(oMail)
Set oTargetFDR = GetSubFolder(oSubFDR, sName)
If oTargetFDR Is Nothing Then
MsgBox "Cannot get Target folder """ & oSubFDR.FolderPath & "\" & sName & """"
Else
oMail.Move oTargetFDR
iMoved = iMoved + 1
End If
Set oMail = Nothing
End If
End Sub
' Extract the Sender Name before any brackets
Private Function GetSenderName(ByRef oItem As MailItem) As String
Dim sName As String
sName = oItem.SenderName
If InStr(1, sName, "(", vbTextCompare) > 1 Then sName = Split(sName, "(")(0)
If InStr(1, sName, "<", vbTextCompare) > 1 Then sName = Split(sName, "<")(0)
If InStr(1, sName, "[", vbTextCompare) > 1 Then sName = Split(sName, "[")(0)
If InStr(1, sName, "{", vbTextCompare) > 1 Then sName = Split(sName, "{")(0)
GetSenderName = Trim(sName)
End Function
' Given a name, get the sub-folder object from a main folder (create if required)
Private Function GetSubFolder(ByRef oParentFDR As Folder, ByVal sName As String) As Folder
On Error Resume Next
Dim oFDR As Folder
Set oFDR = oParentFDR.Folders(sName)
If oFDR Is Nothing Then Set oFDR = oParentFDR.Folders.Add(sName)
Set GetSubFolder = oFDR
End Function
CODE UPDATE based on OP's comment
Searches all the sub folders within Inbox for the Sender's Name. If not found, prompts to create from Folder Picker.
Option Explicit
Private oNS As NameSpace
Sub MoveSenderToFolder()
Dim oMainFDR As Folder, oSubFDR As Folder
Dim oItem As Variant, iMoved As Long
On Error Resume Next
Set oNS = Application.GetNamespace("MAPI")
On Error GoTo 0
If oNS Is Nothing Then
MsgBox "Cannot get MAPI namespace from Outlook! Abortting!", vbCritical + vbOKOnly, "MoveSenderToFolder()"
Else
' Proceed to Set Folders
Set oMainFDR = oNS.GetDefaultFolder(olFolderInbox)
If Not oMainFDR Is Nothing Then
iMoved = 0
' [1] Process the Selected items
For Each oItem In ActiveExplorer.Selection
MoveItemToFolder oItem, oMainFDR, iMoved
Next
' [2] Ask to process a Folder if no MailItems are moved from Selection
If iMoved = 0 Then
If vbYes = MsgBox("Would you like to select a folder to move mail items?", vbQuestion + vbYesNo, "MoveSenderToFolder()") Then
Set oSubFDR = oNS.PickFolder ' Reuse oMainFDR object to the selected folder
For Each oItem In oSubFDR.Items
MoveItemToFolder oItem, oMainFDR, iMoved
Next
Set oSubFDR = Nothing
End If
End If
Set oSubFDR = Nothing
Set oMainFDR = Nothing
End If
Set oNS = Nothing
MsgBox iMoved & " item(s) are moved.", vbInformation + vbOKOnly, "MoveSenderToFolder()"
End If
End Sub
' Get Folder object based on a Name and a root folder
Private Function GetSenderFolder(ByRef oRootFDR As Folder, ByVal sName As String) As Folder
Dim oFDR As Folder, oFDR2 As Folder
For Each oFDR In oRootFDR.Folders
If oFDR.Name = sName Then
Set oFDR2 = oFDR
Exit For
End If
Next
If oFDR Is Nothing Then
For Each oFDR In oRootFDR.Folders
Set oFDR2 = GetSenderFolder(oFDR, sName)
If Not oFDR2 Is Nothing Then Exit For
Next
End If
Set GetSenderFolder = oFDR2
End Function
' Move input item (Mail Items only) to a sub folder and increment counter
Private Sub MoveItemToFolder(ByRef oItem As Variant, ByRef oRootFDR As Folder, ByRef iMoved As Long)
Dim oMail As MailItem, sName As String, oTargetFDR As Folder
If TypeName(oItem) = "MailItem" Then
Set oMail = oItem
sName = GetSenderName(oMail)
Set oTargetFDR = GetSenderFolder(oRootFDR, sName)
If oTargetFDR Is Nothing Then
If vbYes = MsgBox("Cannot get Target folder """ & oRootFDR.FolderPath & "\" & sName & """" & vbLf & _
"Would you like to create the folder from folder of your choice?", vbQuestion + vbYesNo) Then
Set oTargetFDR = CreateSubFolder(sName)
End If
End If
If Not oTargetFDR Is Nothing Then
oMail.Move oTargetFDR
iMoved = iMoved + 1
End If
Set oMail = Nothing
End If
End Sub
' Extract the Sender Name before any brackets
Private Function GetSenderName(ByRef oItem As MailItem) As String
Dim sName As String
sName = oItem.SenderName
If InStr(1, sName, "(", vbTextCompare) > 1 Then sName = Split(sName, "(")(0)
If InStr(1, sName, "<", vbTextCompare) > 1 Then sName = Split(sName, "<")(0)
If InStr(1, sName, "[", vbTextCompare) > 1 Then sName = Split(sName, "[")(0)
If InStr(1, sName, "{", vbTextCompare) > 1 Then sName = Split(sName, "{")(0)
GetSenderName = Trim(sName)
End Function
' Given a name, Create the sub-folder object from Folder Picker
Private Function CreateSubFolder(ByVal sName As String) As Folder
On Error Resume Next
Dim oFDR As Folder
Set oFDR = oNS.PickFolder
If Not oFDR Is Nothing Then Set oFDR = oFDR.Folders.Add(sName)
Set CreateSubFolder = oFDR
End Function
Update Folder Name Folders("Folder1")
Option Explicit
Sub File_olItems()
Dim olNameSpace As Outlook.NameSpace
Dim olSourceFolder As Outlook.Folder
Dim olDestFolder As Outlook.Folder
Dim currentExplorer As Explorer
Dim Selection As Selection
Dim olItem As MailItem
Dim vItem As Variant
Dim NameSender As String
Dim i As Long
Set olNameSpace = Application.GetNamespace("MAPI")
Set currentExplorer = Application.ActiveExplorer
Set Selection = currentExplorer.Selection
Set olSourceFolder = olNameSpace.GetDefaultFolder(olFolderInbox).Folders("Folder1")
For Each olItem In Selection
Set vItem = olItem
If vItem.Class = olMail Then
Debug.Print vItem.SentOnBehalfOfName
NameSender = vItem.SentOnBehalfOfName
If NameSender = ";" Then
NameSender = vItem.SenderName
End If
If InStr(1, NameSender, "(", vbTextCompare) > 1 Then
NameSender = Split(NameSender, "(")(0)
Debug.Print NameSender
End If
On Error Resume Next
Set olDestFolder = olSourceFolder.Folders(NameSender)
If olDestFolder Is Nothing Then
Set olDestFolder = olSourceFolder.Folders.Add(NameSender)
End If
vItem.Move olDestFolder
' // count items moved
i = i + 1
Set olDestFolder = Nothing
End If
Next olItem
' // Display the number of items that were moved.
MsgBox "Moved " & i & " Mail Items."
Set currentExplorer = Nothing
Set olItem = Nothing
Set Selection = Nothing
Set olNameSpace = Nothing
Set olSourceFolder = Nothing
End Sub

Run-time Error 424 Object Required

Im writing a macro for outlook 2010. I get the error on the for each loop even the first time and oFolder does contain a folder.
BTW, SaveAttachments runs correctly the first time its just the second time it bombs.
Public Sub processFolder()
Set objNS = Application.GetNamespace("MAPI")
Dim oParent As Outlook.MAPIFolder
Dim oFolder As Outlook.MAPIFolder
Dim FolderName As String
Set objInbox = objNS.GetDefaultFolder(olFolderInbox)
SaveAttachments (objInbox)
If (objInbox.Folders.Count > 0) Then
For Each oFolder In objInbox.Folders
SaveAttachments (oFolder)
Next
End If
End Sub
Sub SaveAttachments(ByVal oParent As Outlook.MAPIFolder)
'Declaration
Dim myItems, myItem, myAttachments, myAttachment As Object
Dim myOrt As String
Dim myOlApp As New Outlook.Application
myOrt = "C:\attachments"
On Error Resume Next
'for all items do...
For Each myItem In oParent.Items
'point on attachments
Set myAttachments = myItem.Attachments
'if there are some...
If myAttachments.Count > 0 Then
'add remark to message text
myItem.Body = myItem.Body & vbCrLf & _
"Removed Attachments:" & vbCrLf
'for all attachments do...
For i = 1 To myAttachments.Count
'save them to destination
myAttachments(i).SaveAsFile myOrt & _
myAttachments(i).DisplayName
'add name and destination to message text
myItem.Body = myItem.Body & _
"File: " & myOrt & _
myAttachments(i).DisplayName & vbCrLf
Next i
'for all attachments do...
While myAttachments.Count > 0
'remove it (use this method in Outlook XP)
'myAttachments.Remove 1
'remove it (use this method in Outlook 2000)
myAttachments(1).Delete
Wend
'save item without attachments
myItem.Save
End If
Next
'free variables
Set myItems = Nothing
Set myItem = Nothing
Set myAttachments = Nothing
Set myAttachment = Nothing
Set myOlApp = Nothing
Set myOlExp = Nothing
Set myOlSel = Nothing
End Sub
You have mixed and matched the method of calling SaveAttachments
Choose one or the other
Call SaveAttachments(objInbox) ' <--- Call requires brackets
SaveAttachments objInbox ' <--- No brackets
SaveAttachments oFolder ' <--- No brackets