Move NDR messages to a folder not in the inbox - vba

I want to move NDR messages to a folder which is not in the inbox.
I found working code online which moves the NDRs but not where I want it. I assume that the problem is with the path:
Set Folders = Session.GetDefaultFolder(olFolderInbox).Folders
Set Folder = Folders.Item("NDR")
How can I move the NDRs to the "nem_kezbesitheto" subfolder in "x_spam"?
Outlook folder structure
Private WithEvents Items As Outlook.Items
Private Sub Application_Startup()
Set Items = Session.GetDefaultFolder(olFolderInbox).Items
End Sub
Private Sub Items_ItemAdd(ByVal Item As Object)
On Error Resume Next
If UCase(Item.MessageClass) = "REPORT.IPM.NOTE.NDR" Then
Set Folders = Session.GetDefaultFolder(olFolderInbox).Folders
Set Folder = Folders.Item("NDR")
If Folder Is Nothing Then
Folder = Folders.Add("NDR")
End If
Item.Move Folder
End If
End Sub

It seems the target folder is located in a separate store. Use the NameSpace.Stores property which returns a Stores collection object that represents all the Store objects in the current profile. For example:
Sub EnumerateFoldersInStores()
Dim colStores As Outlook.Stores
Dim oStore As Outlook.Store
Dim oRoot As Outlook.Folder
On Error Resume Next
Set colStores = Application.Session.Stores
For Each oStore In colStores
Set oRoot = oStore.GetRootFolder
Debug.Print (oRoot.FolderPath)
EnumerateFolders oRoot
Next
End Sub
Private Sub EnumerateFolders(ByVal oFolder As Outlook.Folder)
Dim folders As Outlook.folders
Dim Folder As Outlook.Folder
Dim foldercount As Integer
On Error Resume Next
Set folders = oFolder.folders
foldercount = folders.Count
'Check if there are any folders below oFolder
If foldercount Then
For Each Folder In folders
Debug.Print (Folder.FolderPath)
EnumerateFolders Folder
Next
End If
End Sub
So, instead of using the following line of code:
Session.GetDefaultFolder(olFolderInbox).Folders
You will have to use the following one:
Store.GetDefaultFolder(olFolderInbox).Folders
Where the store object represents the target store. You will have to find it using the Stores collection returned from the corresponding property of the Namespace class.

Navigate the folder tree from the top level Session to "nem_kezbesitheto".
It looks like x_spam is at the mailbox level. If not adjust to step from Session to mailbox to folder to folder to folder, one at a time.
Option Explicit ' Consider this mandatory
' Tools | Options | Editor tab
' Require Variable Declaration
' If desperate declare as Variant
Private WithEvents Items As Items
Private Sub Application_Startup()
Set Items = Session.GetDefaultFolder(olFolderInbox).Items
End Sub
Private Sub Items_ItemAdd(ByVal Item As Object)
Dim x_spamMailbox As folder
Dim myFolder As folder
If UCase(Item.MessageClass) = "REPORT.IPM.NOTE.NDR" Then
'Navigate the folder tree
' Assuming x_spam is at the mailbox level
Set x_spamMailbox = Session.folders("x_spam")
' Step from mailbox to folder (to folder to folder as needed)
Set myFolder = x_spamMailbox.folders("nem_kezbesitheto")
Item.Move myFolder
End If
End Sub

Related

Detect changes in folders of multiple account of outlook and send mail to specified address

I manage several mail accounts in my Outlook and I want to check if there is any change happens in any of the mails folder (received a mail). Then check Folder name is "My Out Folder" then it should forward that mail to specified account i.e "ABC#gmail.com"
The following code only handle first Mail Account folders. I don't want to use several variables for every mail so I am looking for a way to create class module so that it can detect Change_events in all the emails. only trigger when the folder name is "My Out Folder".
Following is in class "ThisOutlookSession":
Const FowardEmailAddress As String = "ABC#gmail.com"
Public WithEvents myOutFolder As Outlook.Folders
Private Sub Application_Startup()
Set MyNS = Application.GetNamespace("MAPI")
Set myOutFolder = MyNS.Folders(1).Folders
End Sub
Private Sub myOutFolder_FolderChange(ByVal Folder As Outlook.Folder)
Dim FowardItem As Outlook.MailItem
If Folder.Name = "My Out Folder" Then
Set FowardItem = Folder.Items.GetFirst
AutoForwardAllSentItems FowardItem, FowardEmailAddress
End If
End Sub
code of AutoForwardAllSentItems() is in module:
Sub AutoForwardAllSentItems(Item As Outlook.MailItem, FM$)
Dim strMsg As String
Dim myFwd As Outlook.MailItem
Set myFwd = Item.Forward
myFwd.Recipients.Add FM
myFwd.Send
'myFwd.Display
Set myFwd = Nothing
End Sub
I don't know what is best way to achieved the same results.
You need to subscribe to each folder separately. To iterate over all stores in Outlook you can use the Namespace.Stores property which returns a Stores collection object that represents all the Store objects in the current profile. Use the Stores and Store objects to enumerate all folders and search folders on all stores in the current session. For example:
Sub EnumerateFoldersInStores()
Dim colStores As Outlook.Stores
Dim oStore As Outlook.Store
Dim oRoot As Outlook.Folder
On Error Resume Next
Set colStores = Application.Session.Stores
For Each oStore In colStores
Set oRoot = oStore.GetRootFolder
Debug.Print (oRoot.FolderPath)
EnumerateFolders oRoot
Next
End Sub
Private Sub EnumerateFolders(ByVal oFolder As Outlook.Folder)
Dim folders As Outlook.folders
Dim Folder As Outlook.Folder
Dim foldercount As Integer
On Error Resume Next
Set folders = oFolder.folders
foldercount = folders.Count
'Check if there are any folders below oFolder
If foldercount Then
For Each Folder In folders
Debug.Print (Folder.FolderPath)
EnumerateFolders Folder
Next
End If
End Sub
In your case it seems you just need to get the "My Out Folder" of each store and subscribe to the events. The Store.GetDefaultFolder method returns a Folder object that represents the default folder in the store and that is of the type specified by the FolderType argument. So, you may get any standard folder and then navigate the required one.
Also you need to distinguish the Items.ItemAdd event which is fired when one or more items are added to the specified collection/folder and the Items.ItemChange event which is fired when an item in the specified collection is changed.

Reference a Shared Sub Folder in an inbox

I'm looking to modify my VBA code to reference a shared inbox that has a subfolder inside of it. The commented out code worked with my main inbox folder and a sub folder called test. I've tried to use the getSharedDefaultfolder method but the code currently does not detect an email being placed in the subfolder of my shared inbox. Does anyone have any thoughts or recommendations?
Public WithEvents objInbox As Outlook.Folder
Public WithEvents objInboxItems As Outlook.Items
Private Sub Application_Startup()
Dim olNs As Outlook.NameSpace
Dim Inbox As Outlook.MAPIFolder
Set olNs = Application.GetNamespace("MAPI")
Set shrdRecip = olNs.CreateRecipient(test#outlook.com)
Set Inbox = olNs.GetSharedDefaultFolder(shrdRecip, olFolderInbox).Folders("test")
'Set objInbox = Outlook.Application.Session.GetDefaultFolder(olFolderInbox).Folders("test")'
'Set objInboxItems = objInbox.Items'
Set objInboxItems = Inbox.Items
End Sub
Private Sub objInboxItems_ItemAdd(ByVal Item As Object)
Dim objMail As Outlook.MailItem
Dim objForward As Outlook.MailItem
MsgBox Item.Subject
If TypeOf Item Is MailItem Then
Set objMail = Item
MsgBox objMail.UnRead
If (objMail.UnRead Or False) Then
Set objForward = objMail.Forward
With objForward
.Subject = "Custom Subject"
.HTMLBody = "<HTML><BODY>Type body here. </BODY></HTML>" & objForward.HTMLBody
.Recipients.Add (usr#yahoo.com)
.Recipients.ResolveAll
.Send
MsgBox Item.Subject
End With
End If
End If
End Sub
Sub MyTEST()
End Sub```
You need to add the shared folder/store to your Outlook profile if you want to get events fired in VBA.
Also make sure an instance of the Items class was initialized correctly in the code to get the events fired.
I'd suggest calling the Recipient.Resolve method before accessing the shared folder, it attempts to resolve a Recipient object against the Address Book.
Are you sure objInboxItems is not null? By default, GetSharedDefaultFolder only returns the folder but not its subfolders unless the shared mailbox is added to the profile as a delegate mailbox and and all its folders are synchronized by Outlook.

Outlook VBA - move mail when assigned to a category

I would like to move emails to a sub-folder of my inbox when I assign it a category
I found the following code from Extended Office but it does not work.
It is supposed to move mail to a subfolder with the same name as the category and create a folder if it does not exist.
I have enabled macros in Outlook's security settings and inserted some message box alerts to confirm that does in fact run.
The code is in ThisOutlookSession
Private WithEvents xInboxFld As Outlook.Folder
Private WithEvents xInboxItems As Outlook.Items
Private Sub Application_Startup()
MsgBox "Macros are working"
Set xInboxFld = Outlook.Application.Session.GetDefaultFolder(olFolderInbox)
Set xInboxItems = xInboxFld.Items
End Sub
Private Sub xInboxItems_ItemChange(ByVal Item As Object)
MsgBox "Item Changed"
Dim xMailItem As Outlook.MailItem
Dim xFlds As Outlook.Folders
Dim xFld As Outlook.Folder
Dim xTargetFld As Outlook.Folder
Dim xFlag As Boolean
On Error Resume Next
If Item.Class = olMail Then
Set xMailItem = Item
xFlag = False
If xMailItem.Categories <> "" Then
Set xFlds = Application.Session.GetDefaultFolder(olFolderInbox).Folders
If xFlds.Count <> 0 Then
For Each xFld In xFlds
If xFld.Name = xMailItem.Categories Then
xFlag = True
End If
Next
End If
If xFlag = False Then
Application.Session.GetDefaultFolder(olFolderInbox).Folders.Add xMailItem.Categories, olFolderInbox
End If
Set xTargetFld = Application.Session.GetDefaultFolder(olFolderInbox).Folders(xMailItem.Categories)
xMailItem.Move xTargetFld
End If
End If
End Sub
I don't know exactly why but this suddenly started working today, I had restarted Outlook several times before but after I needed to force close Outlook this morning it started working.
(I'm not even sure if it started working immediately because of the restart or if it was a short time afterwards triggered by something else)

How to trigger ItemChange when a Task is updated?

I took this code from the internet to automatically send the tasks that are completed to a specific folder ("Completed Tasks"). It didn't work, I would click to complete the task and it wouldn't get moved.
I put msgboxes to pop up at three parts of the code to see where the problem is. The initialization box pops up, but the box corresponding to the ItemChange doesn't, and the other one doesn't as well. My impression is that the ItemChange isn't being called.
Public WithEvents olItems As Outlook.Items
Public Sub Application_Startup()
Set olItems = Session.GetDefaultFolder(olFolderTasks).Items
MsgBox ("initialized")
End Sub
Public Sub olItems_ItemChange(ByVal Item As Object)
Dim CompTaskf As Folder
MsgBox ("detected change")
If Item.Complete = True And Item.IsRecurring = False Then
MsgBox ("condition met")
Set CompTaskf = Session.GetDefaultFolder(olFolderTasks).Folders("Completed Tasks")
Item.Move CompTaskf
End If
End Sub
I tried:
Changing the folder permissions and starting Outlook in administrator mode.
Pointing it to a single folder with a few tasks.
Setting CompTaskf as a global variable.
Edit: corrected myolItems to olItems, now it works but only if I point to a single folder with few tasks:
Set myolItems = Session.GetDefaultFolder(olFolderTasks).Folders("Inbox").Items
It doesn't work without the .Folders(Inbox")
I thought .Items wasn't returning the items when attached right after the default folder.
I found a way to point olItems to the current folder by defining it as so every time I switch folders.
Public WithEvents olItems As Outlook.Items
Public WithEvents daFolder As Outlook.Explorer
Public Sub Application_Startup()
Set daFolder = Application.ActiveExplorer
'MsgBox ("initialized")
End Sub
'Sets daFolder as the active explorer window on startup,
' apparently necessary because i can't put
' Application.ActiveExplorer_FolderSwitch() as the sub
Public Sub daFolder_FolderSwitch()
Set olItems = Application.ActiveExplorer.CurrentFolder.Items
End Sub
'Every time i switch between folders, set olItems as the items of the current folder
Public Sub olItems_ItemChange(ByVal Item As Object)
Dim CompTaskf As Folder
'MsgBox ("detected change")
If TypeName(Item) = "TaskItem" And Item.Complete = True And Item.IsRecurring = False Then 'This verification that it's a task item is necessary, otherwise the code may crash
'MsgBox ("condition met")
Set CompTaskf = Session.GetDefaultFolder(olFolderTasks).Folders("Completed Tasks") 'Set folder i want to move tasks to
Item.Move CompTaskf 'Move task to the folder
End If
End Sub
The olItems variabel is never initialized. You are initializing the undeclared myolItems variable.

Outlook VBA move mail in subfolder which hods mail of same subject

I'd like to do the following:
On the event of receiving a new mail the subject of the mail should be checked and if the same subject exists already in any subfolder the mail shall be moved to that same subfolder. In case the same mail can't be found it shall remain in the normal inbox folder.
The target folder as such has no logical connection to the mail, so it is not called like the mail or the mail sender or something like that. It is only the folder which holds one or mails with the same subject.
I managed - by browsing through this forum - to identify the event, the subject of the mail and to perform the actual move.
What I did not manage is:
1. to create a search logic to find already existing mails with the same subject in any folder
2.to return the found folder to use it as the target destination.
This is how it looks up till now and it manages to show a message...
Private WithEvents Items As Outlook.Items
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_ItemAdd(ByVal Item As Object)
On Error GoTo ErrorHandler
Dim Msg As Outlook.MailItem
Dim MoveToFolder As Outlook.MAPIFolder
If TypeName(Item) = "MailItem" Then
Set Msg = Item
MsgBox "Here the folder must be found for '" & Msg.Subject & "'."
'Msg.Move MoveToFolder
End If
ProgramExit:
Exit Sub
ErrorHandler:
MsgBox Err.Number & " - " & Err.Description
Resume ProgramExit
End Sub
On top: Is there a specific smart way to do the same on other events like for example "SentMails"?
Thanks a lot for any support.
Ralf
You can use the AdvancedSearch method of the Application class which performs a search based on a specified DAV Searching and Locating (DASL) search string. You can read more about that method in the Advanced search in Outlook programmatically: C#, VB.NET article. So, you can find items with the same subject and then get their Parent property value which stands for the folder where they are stored.
Public blnSearchComp As Boolean
Private Sub Application_AdvancedSearchComplete(ByVal SearchObject As Search)
Debug.Print "The AdvancedSearchComplete Event fired"
If SearchObject.Tag = "Test" Then
m_SearchComplete = True
End If
End Sub
Sub TestAdvancedSearchComplete()
Dim sch As Outlook.Search
Dim rsts As Outlook.Results
Dim i As Integer
blnSearchComp = False
Const strF As String = "urn:schemas:mailheader:subject = 'Test'"
Const strS As String = "Inbox"
Set sch = Application.AdvancedSearch(strS, strF, “Test”)
While blnSearchComp = False
DoEvents
Wend
Set rsts = sch.Results
For i = 1 To rsts.Count
Debug.Print rsts.Item(i).SenderName
Next
End Sub
Is there a specific smart way to do the same on other events like for example "SentMails"?
You may consider handling the ItemSend event of the Application class which is fired whenever an Microsoft Outlook item is sent, either by the user through an Inspector (before the inspector is closed, but after the user clicks the Send button) or when the Send method for an Outlook item. In the event handler you can set the SaveSentMessageFolder property which allows to set a Folder object that represents the folder in which a copy of the e-mail message will be saved after being sent.