Switching between accounts then looping through email - vba

I am attempting to dump all emails in the junk email folder of a NON-Default outlook account into the inbox so that I can then perform additional logic on the email.
However I am unable to figure out how to reference the junk box or even the inbox of the non-default account, my code keeps going through my default account even with an account check in place.
Public Sub New_Mail()
Dim oAccount As Outlook.Account
Dim objSourceFolder As Outlook.MAPIFolder
Dim objDestFolder As Outlook.MAPIFolder
dim lngCount as long
lngcount = 0
For Each oAccount In Application.Session.Accounts ' cycle through accounts till we find the one we want
If oAccount = "desired.account#domain.ca" Then
Set objSourceFolder = objNamespace.GetDefaultFolder(olFolderJunk) ' select junk folder of the account
Set objDestFolder = objNamespace.GetDefaultFolder(olFolderInbox) ' select inbox of the account
For lngCount = objSourceFolder.Items.Count To 1 Step -1 ' Go through all items in inbox, if a mail object, move into inbox
Set objVariant = objSourceFolder.Items.Item(dblCount)
DoEvents
If objVariant.Class = olMail Then
Set objCurrentEmail = objVariant ' the inbox item is an email, so change object type to olMail (email object)
objCurrentEmail.Categories = "red category"
objCurrentEmail.Move objDestFolder ' Move the email to the required folder
End If
Next
End If
Next
End Sub
EDIT:
After Eric's Answer I'd like share my now working code.
Private Sub clearJunk()
Dim objVariant As Variant ' Variant object to handle and inbox item
Dim objCurrentEmail As Outlook.MailItem ' Temporary email object for logic
Dim dblCount As Double ' Double used to count email items in the inbox
Dim objStore As Outlook.Store ' Store Object to cycle through email accounts
Dim objRoot As Outlook.Folder ' Folder object to define Inbox of desired account
Dim folders As Outlook.folders ' FolderS object to holder folders...lol
Dim Folder As Outlook.Folder ' Temporary Folder object
Dim foldercount As Integer ' integer to count folders in account
Dim objInboxFolder As Outlook.MAPIFolder ' MAPI folder object to move emails to or from
Dim objJunkFolder As Outlook.MAPIFolder ' MAPI folder object to move emails to or from
Dim objRandomFolder As Outlook.MAPIFolder ' MAPI folder object to move emails to or from
'--------------------------------------------------------------------
' Cycle through each account in outlook client and find desired account
For Each objStore In Application.Session.Stores
If objStore = "desired.account#domain.ca" Then ' If we find the account
Set objRoot = objStore.GetRootFolder ' Store int objRoot Object
On Error Resume Next
Set folders = objRoot.folders ' Check if it has folders
foldercount = folders.Count
If foldercount Then ' if folders exist
For Each Folder In folders ' Go through each folder AND ....
' Look for Junk Email folder, Inbox Folder, and some random customer folder.
' Store in individual objects for future referencing
If Folder.FolderPath = "\\desired.account#domain.ca\Junk Email" Then
Set objJunkFolder = Folder
End If
If Folder.FolderPath = "\\desired.account#domain.ca\Inbox" Then
Set objInboxFolder = Folder
End If
If Folder.FolderPath = "\\desired.account#domain.ca\Random Custom Folder" Then
Set objRandomFolder = Folder
End If
Next
End If
' Now we have everything identified lets move emails!
For dblCount = objJunkFolder.Items.Count To 1 Step -1
Set objVariant = objJunkFolder.Items.Item(dblCount)
DoEvents
If objVariant.Class = olMail Then
Set objCurrentEmail = objVariant
objCurrentEmail.Categories = "Red Category"
objCurrentEmail.Move objInboxFolder
End If
Next
End If
Next
End Sub

You need to call Store.GetDefaultFolder(olFolderInbox) for the non-default accounts. Get the Store object from the Account.DeliveryStore property - in most cases that will be the correct store unless for example it is a PST account that has messages delivered to another account's store (perhaps even the default account's store).

Related

How to move "Re:" & "Fwd:" email received in a shared inbox to a subfolder?

All the reply (RE:) and the forward (FWD:) mails received in a shared inbox has to automatically move to an "Ongoing folder".
This code is not working.
Private Sub Application_NewMail()
Dim olNameSpace As NameSpace
Set olNameSpace = GetNamespace("MAPI")
Dim olDestFolder As Folder
Set olDestFolder = olNameSpace.Folders("xxx#gmail.com").Folders("Ongoing")
Dim olLookUpFolder As Folder
Set olLookUpFolder = olNameSpace.Folders("xxx#gmail.com").Folders("Inbox")
' olMail is a Class. Avoid as a variable name
'Dim olMail As MailItem
Dim olObj As Object ' Outlook items are not necessarily mailitems
For Each olObj In olLookUpFolder.Items 'loop through Tickets folder to find original mail
If olObj.Class = olMail Then
Set objMail = objItem
v = objMail.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x10810003")
If (v = 102) Or (v = 104) Then
olObj.Move olDestFolder ' move to InProgress folder
Exit For
End If
End If
Next
End Sub
Firstly, do not use "for each" against a collection that you are modifying (by calling MailItem.Move). Use a down loop.
Secondly, never loop through all items in a folder (you wouldn't use a SELECT query in SQL without a WHERE clause, would you?) - use Items.Find/FindNext or Items.Restrict:
set query = "#SQL=(""http://schemas.microsoft.com/mapi/proptag/0x10810003"" = 102) or (""http://schemas.microsoft.com/mapi/proptag/0x10810003"" = 104)"
set olItems = olLookUpFolder.Items.Restrict(query)
for i = olItems.Count to 1 step -1
set olObj = olItems.Item(i)
...

Get Inbox associated with mailbox that is not the main mailbox

I'm trying to get the inbox of a specific email address where there is more than one address connected to the same Outlook.
I can only succeed if I check the main mailbox (the first listed in Outlook).
dim outlApp as Object
dim outlNsp as Object
dim outlMapp as Object
dim outlsubMapp as Object
dim Mappar as Object
outlApp = CreateObject("Outlook.Application")
outlNsp = outlApp.GetNamespace("MAPI")
outlMapp = outlNsp.Folders.item(Mail_username)
Mappar = outlMapp.Folders
outlsubMapp = Mappar.item(6)
'6 is olFolderInbox enum value
outlsubMapp = outlNsp.GetDefaultFolder(6)
'6 is olFolderInbox enum value
Inbox = outlsubMapp.Name
If I change Mail_username I still get the first email inbox folder.
This macro lists every store to which you have access and the top level folders which will include their Inboxes. It shows how to access stores and folders that are not defaults.
I am not sure if this is a complete answer but it will get you started. Try the macro then come back with any questions.
Sub ListStoresAndTopLevelFolders()
Dim FldrCrnt As Folder
Dim InxFldrChild As Long
Dim InxStoreCrnt As Long
Dim StoreCrnt As Folder
With Application.Session
For InxStoreCrnt = 1 To .Folders.Count
Set StoreCrnt = .Folders(InxStoreCrnt)
With StoreCrnt
Debug.Print .Name
For InxFldrChild = .Folders.Count To 1 Step -1
Set FldrCrnt = .Folders(InxFldrChild)
With FldrCrnt
Debug.Print " " & .Name
End With
Next
End With
Next
End With
End Sub
You can use the Store.GetDefaultFolder method which returns a Folder object that represents the default folder in the store and that is of the type specified by the FolderType argument. This method is similar to the GetDefaultFolder method of the NameSpace object. The difference is that this method gets the default folder on the delivery store that is associated with the account, whereas NameSpace.GetDefaultFolder returns the default folder on the default store for the current profile.
To get all stores in the profile you need to use the Stores property of the Namespace class:
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

Move old email in conversation to subfolder

I am looking for a macro to move earlier email in a conversation (sorted by subject) to a subfolder, except the latest conversation in that subject.
Upon receiving a new mail on the same conversation, then move the older email to subfolder.
I found the base to move emails older than 7 days, but not sure how to move older conversations and leave only the latest mail.
Sub MoveAgedMail()
Dim objOutlook As Outlook.Application
Dim objNamespace As Outlook.NameSpace
Dim objSourceFolder As Outlook.MAPIFolder
Dim objDestFolder As Outlook.MAPIFolder
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 objSourceFolder = objNamespace.GetDefaultFolder(olFolderInbox)
Set objSourceFolder = objNamespace.Folders("Online Archive - OTCGROUP#abc.ssmb.com").Folders("Inbox").Folders("DEST1")
' use a subfolder under Inbox
'Set objDestFolder = objSourceFolder.Folders("DEST")
Set objDestFolder = objNamespace.Folders("Online Archive - OTCGROUP2#abc.ssmb.com").Folders("Inbox").Folders("DEST2")
For intCount = objSourceFolder.Items.Count To 1 Step -1
Set objVariant = objSourceFolder.Items.Item(intCount)
DoEvents
If objVariant.Class = olMail Then
intDateDiff = DateDiff("d", objVariant.SentOn, Now)
' I'm using 7 days, adjust as needed.
If intDateDiff > 7 Then
objVariant.Move objDestFolder
'count the # of items moved
lngMovedItems = lngMovedItems + 1
End If
End If
Next
' Display the number of items that were moved.
MsgBox "Moved " & lngMovedItems & " messages(s)."
Set objDestFolder = Nothing
End Sub
Iterating through all items in the folder is not really a good idea:
For intCount = objSourceFolder.Items.Count To 1 Step -1
Set objVariant = objSourceFolder.Items.Item(intCount)
Use the Find/FindNext or Restrict methods of the Items class instead. Read more about these methods in the following articles:
How To: Use Find and FindNext methods to retrieve Outlook mail items from a folder (C#, VB.NET)
How To: Use Restrict method to retrieve Outlook mail items from a folder

How to Add an Appointment to a Shared Calendar in Outlook?

I am attempting to create an appointment taken from a .CSV file with Subject and Date and place this in someone else's shared calendar.
I have full editor's permissions for this shared calendar. By shared calendar I mean, a regular calendar made in the person's Outlook and clicking "Share" and emailing it to others.
Sub ImportAppointments(full_path As String)
'Initialize variables
Dim exlApp As Excel.Application
Dim exlWkb As Workbook
Dim exlSht As Worksheet
Dim rng As Range
Dim itmAppt As Outlook.AppointmentItem
' Create reference to Excel
Set exlApp = New Excel.Application
' Select file path, currently hardcoded to one directory, change as needed
Dim strFilepath As String
'strFilepath = "P:\Holiday Calendar\Holiday_Calendar_Data.csv"
strFilepath = full_path
' Select workbook (the above .csv file) and select the first worksheet as the data sheet
Set exlSht = Excel.Application.Workbooks.Open(strFilepath).Worksheets(1)
' Initialize variables
Dim iRow As Integer
Dim iCol As Integer
Dim oNs As Namespace
Dim olFldr As Outlook.MAPIFolder
Dim objOwner As Outlook.Recipient
' Allow accessing data stored in the user's mail stores in Outlook
Set oNs = Outlook.GetNamespace("MAPI")
' Set share calender owner
Set objOwner = oNs.CreateRecipient("calvin#xyz.ca")
objOwner.Resolve
If objOwner.Resolved Then
' Set up non-default share folder location
Set olFldr = oNs.GetSharedDefaultFolder(objOwner, olFolderCalendar).Folders("Holiday Calendar")
End If
' Start point
iRow = 2
iCol = 1
' Loop through each calendar entry
While exlSht.Cells(iRow, 1) <> ""
Set itmAppt = Outlook.CreateItem(olAppointmentItem)
' Set appointment Subject, ie (Vacation, Sick Day, Half-Day, etc.)
itmAppt.Subject = exlSht.Cells(iRow, 1)
' Set Date of Event
itmAppt.Start = exlSht.Cells(iRow, 2)
' Force All Day Event
itmAppt.AllDayEvent = True
' Save appointment
itmAppt.Save
' Advance pointer to next row
iRow = iRow + 1
' Transfer appointment into shared calendar folder
itmAppt.Move olFldr
Wend
' Close everything
Excel.Application.Workbooks.Close
exlApp.Quit
Set exlApp = Nothing
Set olFldr = Nothing
Set itmAppt = Nothing
End Sub
My code fails to find the "Holiday Calendar" if I try to insert at someone else's calendar with
Set olFldr = oNs.GetSharedDefaultFolder(objOwner, olFolderCalendar).Folders("Holiday Calendar")
Instead of calling Application.CreateItem / AppointmentItem.Move, create the item directly using olFldr.Items.Add.
This line of code is slightly off if the calendar you are writing to is at the same folder level as the default calendar:
Set olFldr = oNs.GetSharedDefaultFolder(objOwner, olFolderCalendar).Folders("Holiday Calendar")
Instead, you need to specify .Parent before the .Folders property
Set olFldr = oNs.GetSharedDefaultFolder(objOwner, olFolderCalendar).Parent.Folders("Holiday Calendar")
I derived this answer from: https://www.slipstick.com/developer/working-vba-nondefault-outlook-folders/
Sharing this as it took me ages to come up with a solution to add a calendar meeting request from an Exchange Shared Mailbox.
This code creates, displays and pre-fills an appointment which will be saved in the Shared Mailbox, and if sent to other recipients will appear to the recipient as being sent from the shared mailbox account!
Sub SendEmailFromSharedMailbox()
Dim olApp As Outlook.Application
Set olApp = Outlook.Application
Dim olNS As Outlook.Namespace
Dim objOwner As Outlook.Recipient
Set olNS = olApp.GetNamespace("MAPI")
Set objOwner = olNS.CreateRecipient("Shared Mailbox Name")
objOwner.Resolve
If objOwner.Resolved Then
MsgBox objOwner.Name
Set newCalFolder = olNS.GetSharedDefaultFolder(objOwner, olFolderCalendar)
'Now create the email
Set olAppt = newCalFolder.Items.Add(olAppointmentItem)
With olAppt
'Define calendar item properties
.Start = "19/9/2019 2:00 PM"
.End = "19/9/2019 2:30 PM"
.Subject = "Appointment Subject Here"
.Recipients.Add ("someone#email.com")
'Add more variables as required, eg reminder, importance, etc
.Display
End With
End If
End Sub

Moving Emails to Public Folder using Dynamic Paths

In our Corporate environment we have a Mailbox (not the default inbox) with many sub folders. We also have a Public Folder which is an exact mirror of the Mailbox folder structure.
I am trying to detect the path of a selected email and move that email to its mirrored folder in the Public Folders.
I would say 95% of this code is correct but I am left with an Outlook error message "Can't move the items."
The code is supposed to do the following:
1. detects the current folder of the selected email(s)
2. converts the MAPIFolder into a path string
3. shortens the string to remove the root Mailbox directory structure
4. adds the remaining string onto the root directory structure of the public folder
5. converts the resulting path back into a MAPIFolder
6. move the selected email(s) to the mirrored folder in the Public Folders
Sub PublicFolderAutoArchive()
Dim olApp As Object
Dim currentNameSpace As NameSpace
Dim wipFolder As MAPIFolder
Dim objFolder As MAPIFolder
Dim pubFolder As String
Dim wipFolderString As String
Dim Messages As Selection
Dim itm As Object
Dim Msg As MailItem
Dim Proceed As VbMsgBoxResult
Set olApp = Application
Set currentNameSpace = olApp.GetNamespace("MAPI")
Set wipFolder = Application.ActiveExplorer.CurrentFolder
Set Messages = ActiveExplorer.Selection
' Destination root directory'
' Tried with both "\\Public Folders" and "Public Folders" .. neither worked
pubFolder = "\\Public Folders\All Public Folders\InboxMirror"
' wipFolder.FolderPath Could be any folder in our mailbox such as:
' "\\Mailbox - Corporate Account\Inbox\SubFolder1\SubFolder2"
' however, the \\Mailbox - Corporate Account\Inbox\" part is
' static and never changes so the variable below removes the static
' section, then the remainder of the path is added onto the root
' of the public folder path which is an exact mirror of the inbox.
' This is to allow a dynamic Archive system where the destination
'path matches the source path except for the root directory.
wipFolderString = Right(wipFolder.FolderPath, Len(wipFolder.FolderPath) - 35)
' tried with and without the & "\" ... neither worked
Set objFolder = GetFolder(pubFolder & wipFolderString & "\")
If Messages.Count = 0 Then
Exit Sub
End If
For Each itm In Messages
If itm.Class = olMail Then
Proceed = MsgBox("Are you sure you want archive the message to the Public Folder?", _
vbYesNo + vbQuestion, "Confirm Archive")
If Proceed = vbYes Then
Set Msg = itm
Msg.Move objFolder
End If
End If
Next
End Sub
Public Function GetFolder(strFolderPath As String) As MAPIFolder
' strFolderPath needs to be something like
' "Public Folders\All Public Folders\Company\Sales" or
' "Personal Folders\Inbox\My Folder"
Dim objApp As Outlook.Application
Dim objNS As Outlook.NameSpace
Dim colFolders As Outlook.Folders
Dim objFolder As Outlook.MAPIFolder
Dim arrFolders() As String
Dim I As Long
On Error Resume Next
strFolderPath = Replace(strFolderPath, "/", "\")
arrFolders() = Split(strFolderPath, "\")
Set objApp = Application
Set objNS = objApp.GetNamespace("MAPI")
Set objFolder = objNS.Folders.Item(arrFolders(0))
If Not objFolder Is Nothing Then
For I = 1 To UBound(arrFolders)
Set colFolders = objFolder.Folders
Set objFolder = Nothing
Set objFolder = colFolders.Item(arrFolders(I))
If objFolder Is Nothing Then
Exit For
End If
Next
End If
Set GetFolder = objFolder
Set colFolders = Nothing
Set objNS = Nothing
Set objApp = Nothing
End Function
Note: The mailbox above is just an example and is not the actual mailbox name. I used MsgBox to confirm the path string was being joined correctly with all appropriate back slashes and that the Right() function was getting what I needed from the source path.
I'm not sure, but should be something like?
set objApp = New Outlook.Application
instead of
set objApp = Application
From glancing at the code, it appears that your GetFolder() implementation doesn't like the double-backslash you're giving at the start of the path. There's even a comment indicating this at the start of the function. Try removing those two chars from the front of pubFolder.
Alternatively, you could alter GetFolder to permit them. A few lines like this should do the trick.
If Left(strFolderPath, 2) = "\\" Then
strFolderPath = Right(strFolderPath, Len(strFolderPath) - 2)
End If