1

I have the following code in Outlook. On my first attempt the deleted mail was sent to my main account inbox and not the shared mailbox.

I would like to
1- pick the shared delete folder by default
2- avoid looping the delete folder
3- speed up the code if possible as size of mail box is > 1 Million mails. It is error free but I can track the progress.

Dim objNameSpace As Outlook.NameSpace
Dim objMainFolder As Outlook.Folder
Dim olNs As NameSpace
Dim lngItem As Long
Dim Mails_itm As MailItem
Dim myNameSpace As Outlook.NameSpace
Dim myInboxDest As Outlook.Folder
Dim myInboxSc As Outlook.Folder
Dim myDestFolder As Outlook.Folder
Dim myItems As Outlook.Items
Dim myItem As Object

Set objNameSpace = Application.GetNamespace("MAPI")
Set objMainFolder = objNameSpace.PickFolder

Call ProcessCurrentFolder(objMainFolder)

End Sub

ProcessCurrentFolder(ByVal objParentFolder As Outlook.MAPIFolder)

    Dim objCurFolder As Outlook.MAPIFolder
    Dim objMail As Outlook.MailItem
    Dim DeletedFolder As Outlook.Folder
    Dim olNs As Outlook.NameSpace
    Dim lngItem As Long
    On Error Resume Next
  
    Set olNs = Application.GetNamespace("MAPI")
    Set DeletedFolder = olNs.GetDefaultFolder(olFolderDeletedItems)
    For Each objMail In objParentFolder.Items
        i = 0
        For lngItem = objParentFolder.Items.Count To 1 Step -1
            Set objMail = objParentFolder.Items(lngItem)
            If TypeName(objMail) = "MailItem" Then
                If ((objMail.ReceivedTime) < DateAdd("yyyy", -7, Date)) Then         
                    objMail.Move DeletedFolder
                    i = i + 1
                End If
            End If
            DoEvents
        Next lngItem
    Next
    If (objParentFolder.Folders.Count > 0) Then
        For Each objCurFolder In objParentFolder.Folders
            Call ProcessCurrentFolder(objCurFolder)
        Next
    End If
End Sub
Community
  • 1
  • 1
Med123
  • 15
  • 4
  • Please, clarify what "get the sh delete folder pick by default for deleting" should mean. Do you mean avoiding using of `PickFolder` and defining/setting a default one (something like `InBox`)? Neither "Avoid the looping the delte folder" is not so clear. Do you mean avoiding looping to the parent folder mail items? Does the above code work in Outlook VBA, or it is an automation from another application (Excel, Word etc.)? – FaneDuru Apr 30 '22 at 11:13
  • The code work in outlook, however on my first attempt the delete mail was sent to my main account inbox and not the shared mailbox. Ideally I would like a code
    1- to loop all folder and subfolder and delete based on condition, here on date.
    2- move the items on the Delete folder from SH
    3- I am talking about 1 million email, hence I might need a loop to clear the delete folder, however move within the same mailbox should not change the mail box size?
    – Med123 Apr 30 '22 at 17:04
  • To point to a non-default mailbox https://stackoverflow.com/questions/9076634/get-reference-to-additional-inbox. To point to a subfolder https://stackoverflow.com/questions/8322432/using-visual-basic-to-access-subfolder-in-inbox – niton Apr 30 '22 at 23:12

2 Answers2

0

When placing a question, it is good to check it from time to time and answer the clarification questions, if any...

Supposing that your first required issue means replacing the folder picker option and directly setting objMainFolder, your first code should be adapted as:

Sub ProcessOldMails()
 Dim objNameSpace As outlook.NameSpace
 Dim objMainFolder As outlook.Folder

 Set Out = GetObject(, "Outlook.Application")
 Set objNameSpace = Out.GetNamespace("MAPI")

 Set objNameSpace = Application.GetNamespace("MAPI")
 'Set objMainFolder = objNameSpace.PickFolder 'uncomment if my supposition is wrong
 'set the folder to be processed directly, if it is an InBox subfolder:
 'Please use its real name instead of "MyFolderToProcess":
 Set objMainFolder = objNameSpace.GetDefaultFolder(olFolderInbox).Folders("MyFolderToProcess")
    ProcessCurrentFolder objMainFolder, Application
End Sub

In order to make the process faster, you can filter the folder content and iterate only between the remained mails:

Sub ProcessCurrentFolder(ByVal objParentFolder As outlook.MAPIFolder, app As outlook.Application)
    Dim objCurFolder As outlook.MAPIFolder
    Dim objMail As outlook.MailItem
    Dim DeletedFolder As outlook.Folder
    Dim olNs As outlook.NameSpace
    Dim lngItem As Long, strFilter As String, oItems As items
  
    Set olNs = app.GetNamespace("MAPI")
    Set DeletedFolder = olNs.GetDefaultFolder(olFolderDeletedItems)
    
    strFilter = "[ReceivedTime]<'" & Format(DateAdd("yyyy", -7, Date), "DDDDD HH:NN") & "'"
    Set oItems = objParentFolder.items.Restrict(strFilter) 'extract only mails older then 7 years
     Debug.Print "Mails to be moved to Deleted Items: " & oItems.count 'just to see how many such folders exist
   For lngItem = oItems.count To 1 Step -1
       oItems(lngItem).Move DeletedFolder
   Next lngItem
   If (objParentFolder.Folders.count > 0) Then
        For Each objCurFolder In objParentFolder.Folders
            Call ProcessCurrentFolder(objCurFolder, app)
        Next
   End If
End Sub

I used app second parameter only because I tried it as an Outlook automation from Excel, and it was easier to insert only two lines...

Please, test the suggested solution and send some feedback. If my understanding was not a correct one, do not hesitate to ask for clarifications, firstly answering my questions from the comment.

Now, I need to go out...

FaneDuru
  • 38,298
  • 4
  • 19
  • 27
  • Editing posts after looking at another answers is really a great strategy ;) – Eugene Astafiev Dec 27 '22 at 09:28
  • @Eugene Astafiev I looked now in my computer and checked who firstly placed the answer and what it contained. I couldn't remember what happened. Now I can. I posted that piece of code before you, without testing it, not having time to do it, considering that it must work. After some time I tested it and observed that it used to loose the reference iterating in that way. And iterating backwards was the logic approach. **Not because I looked to your code**! I found a larger piece of code with my other trials to sort it. It looks that **you copied** my code, (correctly) adapting only that part. – FaneDuru Dec 27 '22 at 10:49
  • Ha-ha... Hope it was a joke that I copied your code :) – Eugene Astafiev Dec 27 '22 at 12:23
  • @Eugene Astafiev Not exactly... :) I place my answer at 13:23 (you can edit and see it) and it looks improbable (to me, at least) both of us to feel the need to place the next comment after the line showing the number of mails to be moved: `'just to see how many such folders exist`... I felt very bad seeing your comment. Without remembering the context and seeing a piece of code almost identic, without any checking I could not understand how **my code has been placed in the circumstances you tried suggesting**. Then I checked and I dared to mention that you copied it an hour and half after... – FaneDuru Dec 27 '22 at 12:41
  • @Eugene Astafiev I don't want suggesting that you could not imagine a similar piece of code, (as you did, for that small iteration part). But, at least those two comments looks very improbable to be born in our minds simultaneously. It was (only) easier to place the correct code in that way... – FaneDuru Dec 27 '22 at 12:44
  • My answer was about improving performance and doing things correctly in Outlook. Let's stop any further discussions about that - I've made conclusions and opinion about things. – Eugene Astafiev Dec 27 '22 at 13:07
  • @Eugene Astafiev The same improving I tried posting the second answer part. I was wrong in the way I tried iterating and corrected after testing. Nothing against stopping the discussion. – FaneDuru Dec 27 '22 at 13:14
  • As you say the `improvement` is the key answer to the question posted. I didn't find it in your post and decided to answer. – Eugene Astafiev Dec 27 '22 at 18:09
0

Use the Find/FindNext or Restrict methods to get items that correspond to your conditions instead of iterating over all items in the folder. Read more about these methods in the following articles:

When you iterate over found items and move them to another folder you must use a reverse loop which allows prevent errors at runtime because decreasing the number of items by calling the Move method leads to decreasing the number of items.

Sub ProcessCurrentFolder(ByVal objParentFolder As outlook.MAPIFolder, app As outlook.Application)
    Dim objCurFolder As outlook.MAPIFolder
    Dim objMail As outlook.MailItem
    Dim DeletedFolder As outlook.Folder
    Dim olNs As outlook.NameSpace
    Dim lngItem As Long, strFilter As String, oItems As items
  
    Set olNs = app.GetNamespace("MAPI")
    Set DeletedFolder = olNs.GetDefaultFolder(olFolderDeletedItems)
    
    strFilter = "[ReceivedTime] < '" & Format(DateAdd("yyyy", -7, Date), "DDDDD HH:NN") & "'"
    Set oItems = objParentFolder.items.Restrict(strFilter) 'extract only mails older then 7 years
     Debug.Print "Mails to be moved to Deleted Items: " & oItems.count 'just to see how many such folders exist
  For i = oItems.Count to 1 Step -1
        Set objMail = oItems(i)
        objMail.Move DeletedFolder
  Next
   
   ' it makes sense to move this part to the beginning of the method to process subfolders first  
   If (objParentFolder.Folders.count > 0) Then
        For Each objCurFolder In objParentFolder.Folders
            Call ProcessCurrentFolder(objCurFolder, app)
        Next
   End If
End Sub

See For Each loop: Some items get skipped when looping through Outlook mailbox to delete items for more information.

Eugene Astafiev
  • 47,483
  • 3
  • 24
  • 45
  • HOW can I make to run for the entire SH ?, works for 1 folders subfolders but I am struggling to get it done for the entire SH > 500 (Folders/Subfolders) – Med123 May 02 '22 at 11:39
  • You need to run it against the [RootFolder](https://learn.microsoft.com/en-us/office/vba/api/outlook.store.getrootfolder) then, not the `Deleted items` folder. – Eugene Astafiev May 02 '22 at 11:49