1

I'm trying to organize 10+ different mailboxes.

The problem is with UnreadMove. I want every time Outlook opens to look for unread mails in the default inbox, copy it and move one of the copies to a shared inbox.

It works if there is one mail to move, but when there are more I get an error

"-2147221241 - Failed Client Action"

or something similar. My Windows is not in English.

When I press ok on the failure window the mails are still copied and moved to the correct folder, so I don't know what the error means. Some mails are copying twice, so might be what the error stands for.

MoveAndCopy: incoming mail is copied and sent to the shared inbox and is marked as read in the original folder (this works).
UnreadMove: should be used when Outlook has not been open for a while and the original inboxes got new mails. Then I want the unread e-mails to be copied, marked as read and then a copy sent to the shared inbox, which should not be marked as read.

ThisOutlookSession

Private Sub Application_Startup()

Dim olApp As Outlook.Application
Dim objNS As Outlook.NameSpace

Set olApp = Outlook.Application
Set objNS = olApp.GetNamespace("MAPI")

Set Items = objNS.GetDefaultFolder(olFolderInbox).Items

End Sub

Private Sub Items_UnreadMove(ByVal Item As Object)

Dim msg As Outlook.MailItem

    If Item.Exists = True Then
        Set msg = Item
        Call UnreadMove(Item)
    End If
End Sub

Private Sub Items_ItemAdd(ByVal Item As Object)

On Error GoTo ErrorHandler
Dim msg As Outlook.MailItem

    If TypeName(Item) = "MailItem" Then
        Set msg = Item
        Call MoveAndCopy(Item)
    End If

ProgramExit:
Exit Sub

ErrorHandler:
MsgBox Err.Number & " - " & Err.Description

Resume ProgramExit
End Sub

And for the two modules:

Sub UnreadMove(Item As Outlook.MailItem)

Dim Inbox As Outlook.Folder
Dim ns As Outlook.NameSpace
Dim MailDest As Outlook.Folder
Dim CopiedItem As Outlook.MailItem

Set Inbox = ns.GetDefaultFolder(olFolderInbox)

For Each Item In Inbox
    If Item.UnRead = True Then
        Set CopiedItem = Item.Copy
        Item.UnRead = False
        Item.Save
        Set ns = Outlook.Application.GetNamespace("MAPI")
        Set MailDest = ns.Folders("myemail@test.com").Folders("MyInbox")
        CopiedItem.Move MailDest
    End If
Next Item

End Sub
Sub MoveAndCopy(Item As Outlook.MailItem)

Dim ns As Outlook.NameSpace
Dim MailDest As Outlook.Folder
Dim CopiedItem As Outlook.MailItem
    
    If Item.Class = olMail Then
        Set CopiedItem = Item.Copy
        Item.UnRead = False
        Item.Save
        Set ns = Outlook.Application.GetNamespace("MAPI")
        Set MailDest = ns.Folders("myemail@test.com").Folders("MyInbox")
        CopiedItem.Move MailDest
    End If
    
End Sub
Community
  • 1
  • 1
  • Does she have any rules running im her outlook? – Ricardo Diaz Jan 30 '21 at 11:39
  • @RicardoDiaz No I didn't find rules working for this case. Cause I wanna copy the mail and mark it as read then move the original mail to the shared folder and keep it unread. So she doesn't have to navigate to the original inbox everytime and mark it as read. I also want a copy in the original inbox, for safety measure. – Oliver Lindhardt Jan 30 '21 at 12:05

1 Answers1

1

UnreadMove makes a copy in the monitored folder. It would invoke Items_ItemAdd. The same for MoveAndCopy.

Whether this is the cause of the error you see now, this should do what you want.

Option Explicit ' Consider this mandatory
' Tools | Options | Editor tab
' Require Variable Declaration
' If desperate declare as Variant

Private WithEvents monitoredItems As Items

Private Sub Application_Startup()
    UnreadMove
    Set monitoredItems = Session.GetDefaultFolder(olFolderInbox).Items
End Sub


Sub UnreadMove()

    Dim Inbox As folder
    Dim MailDest As folder
    Dim CopiedItem As MailItem

    Dim objItem As Object

    Set Inbox = Session.GetDefaultFolder(olFolderInbox)

    Set MailDest = Session.folders("myemail@test.com").folders("MyInbox")

    ' Copying invokes itemAdd
    ' If you run this manually,
    '   after setting up monitoredItems in startup
    '  - a trick to turn itemAdd off
    Set monitoredItems = Nothing

    '
    'For Each objItem In Inbox.Items
    
    '    If objItem.Class = olMail Then
    
    '        If objItem.UnRead = True Then
    '            Debug.Print objItem.subject
    '
    '            Set CopiedItem = objItem.copy
    '            objItem.UnRead = False
    '            objItem.Save
                        
    '            CopiedItem.Move MailDest
            
    '        End If
        
    '    End If
    
    'Next objItem

    ' If the For Each index is confused by copying and moving
    '  Then a reverse For Next is needed.
    '  A reverse loop works in all situations.
    Dim i As Long
    For i = Inbox.Items.count To 1 Step -1
    
        Set objItem = Inbox.Items(i)
    
        If objItem.Class = olMail Then
    
            If objItem.UnRead = True Then
                Debug.Print objItem.subject
            
                Set CopiedItem = objItem.copy
                objItem.UnRead = False
                objItem.Save
            
                CopiedItem.Move MailDest
            
            End If
        
        End If
    
    Next

    ' reset items to be monitored with itemAdd
    Set monitoredItems = Session.GetDefaultFolder(olFolderInbox).Items

End Sub

To temporarily stop monitoring, when you make a copy in the monitored folder.

Private Sub monitoredItems_ItemAdd(ByVal Item As Object)

    Dim msg As MailItem

    If TypeName(Item) = "MailItem" Then
        Set msg = Item
        Set monitoredItems = Nothing
        
        'Call MoveAndCopy(Item)
                
        Call MoveAndCopy(msg)
        ' or
        ' MoveAndCopy msg
        Set monitoredItems = Session.GetDefaultFolder(olFolderInbox).Items

    End If

End Sub

You could stop monitoring in MoveAndCopy instead, if you wish to be more specific.

niton
  • 8,771
  • 21
  • 32
  • 52
  • Thanks, your code works fine for moving unread messages from default inbox at startup of the application. Now I just gotta figure out how to do it in real-time aswell. But after you sharing this I might actually be able to set it up myself! – Oliver Lindhardt Jan 30 '21 at 15:46
  • But I might actually just fix a rule for that. – Oliver Lindhardt Jan 30 '21 at 15:54
  • Run a script in a rule is not recommended. https://www.msoutlook.info/question/run-a-script-rule-action-is-no-longer-working-or-available – niton Jan 30 '21 at 16:01
  • Thanks for telling me, I had no idea. I just added "run a script" in the regedit but will def. try to get the script working instead then. Actually the code isn't really working as intended now either. Only mails from one inbox gets moved to the shared folder "MyInbox" when starting the application. Also same with incomming e-mails, only one of the 3 emails which I'm currently testing on gets their e-mails copied and moved to the "MyInbox" folder. – Oliver Lindhardt Jan 30 '21 at 16:42
  • In addition to the default inbox in `GetDefaultFolder(olFolderInbox)` you need an `ItemAdd` for each non-default inbox. https://stackoverflow.com/questions/9076634/get-reference-to-additional-inbox. See here as well https://stackoverflow.com/questions/65969266/outlook-vba-monitor-multiple-folders/65969944#65969944 – niton Jan 30 '21 at 18:05
  • What exactly defines a default inbox? All the emails are using the default ”inbox” for incomming e-mails. I thought that’s what the GetDefaultFolder means – Oliver Lindhardt Jan 30 '21 at 19:41
  • Default folders are the standard folders in the main mailbox. https://stackoverflow.com/questions/9076634/get-reference-to-additional-inbox – niton Jan 30 '21 at 19:45
  • Alright, so the For Each loop in UnreadMove also needs a statement for every inbox? I feel like this gets out of hand really quickly and I should just try to do some standard rules from the online outlook instead. – Oliver Lindhardt Jan 30 '21 at 19:53
  • Standard rules won't work, cause it's putting both the original email and the copied email marked as read. Otherwise it would be fine tbh. – Oliver Lindhardt Jan 30 '21 at 20:14
  • Create an array of all the mailbox names then loop through them. `Set Inbox = Session.folders(array element).folders("Inbox")` – niton Jan 30 '21 at 20:18
  • I tried my best trying to create the array, but I can't seem to get "Set Inbox = Session.folders(array element).folders("Inbox")" to work. I edited my entire code with your updated code. – Oliver Lindhardt Jan 30 '21 at 23:31
  • I'm pretty sure I missunderstood your comments, cause atm I'm not looping through the array. Gonna work some more on it. – Oliver Lindhardt Jan 30 '21 at 23:32
  • I believe the heart of original question about moving mail has been answered. Consider rolling your edit back so this answer is not invalidated. https://stackoverflow.com/questions/62093557/loop-through-two-arrays-containing-emails If you cannot apply the UBound LBound idea or cannot find a better previously asked question, cut the code down to the minimal required to demonstrate the array issue and ask a new question. – niton Jan 31 '21 at 00:50
  • You're absolutely right. Rolled it back and will further investigate. – Oliver Lindhardt Jan 31 '21 at 11:28