Why Does MailItem.ReceivedTime Error on the Second Pass? [duplicate] - excel

I wanted to develop VBA code that:
Loops through all email items in mailbox
If there are any type of other items say "Calendar Invitation" skips that item.
Finds out the emails with attachments
If attached file has ".xml" extension and a specific title in it, saves it to a directory, if not it keeps searching
Puts all email includes .xml attachments to "Deleted Items" folder after doing step 4 and deletes all emails in that folder by looping.
Code works perfect EXCEPT;
For example
There are 8 email received with ".xml" file attached to each one of them in your mailbox.
run the code
you will see only 4 of the 8 items are processed successfully, other 4 remain in their positions.
If you run the code again, now there would be 2 items processed successfully and other 2 remain in your mailbox.
Problem: After running the code, it is supposed to process all files and deletes them all not the half of them in each run. I want it to process all items at a single run.
BTW, this code runs every time I open the Outlook.
Private Sub Application_Startup()
'Initializing Application_Startup forces the macros to be accessible from other offic apps
'Process XML emails
Dim InboxMsg As Object
Dim DeletedItems As Outlook.Folder
Dim MsgAttachment As Outlook.Attachment
Dim ns As Outlook.NameSpace
Dim Inbox As Outlook.Folder
Dim fPathTemp As String
Dim fPathXML_SEM As String
Dim fPathEmail_SEM As String
Dim i As Long
Dim xmlDoc As New MSXML2.DOMDocument60
Dim xmlTitle As MSXML2.IXMLDOMNode
Dim xmlSupNum As MSXML2.IXMLDOMNode
'Specify the folder where the attachments will be saved
fPathTemp = "some directory, doesn't matter"
fPathXML_SEM = "some directory, doesn't matter"
fPathEmail_SEM = "some directory, doesn't matter"
'Setup Outlook
Set ns = GetNamespace("MAPI")
Set Inbox = ns.Folders.Item("mailbox-name").Folders("Inbox")
Set DeletedItems = ns.Folders.Item("mailbox-name").Folders("Deleted Items")
'Loop through all Items in Inbox, find the xml attachements and process if they are the matching reponses
'On Error Resume Next
For Each InboxMsg In Inbox.Items
If InboxMsg.Class = olMail Then 'if it is a mail item
'Check for xml attachement
For Each MsgAttachment In InboxMsg.Attachments
If Right(MsgAttachment.DisplayName, 3) = "xml" Then
'Load XML and test for the title of the file
MsgAttachment.SaveAsFile fPathTemp & MsgAttachment.FileName
xmlDoc.Load fPathTemp & MsgAttachment.FileName
Set xmlTitle = xmlDoc.SelectSingleNode("//title")
Select Case xmlTitle.Text
Case "specific title"
'Get supplier number
Set xmlSupNum = xmlDoc.SelectSingleNode("//supplierNum")
'Save the XML to the correct folder
MsgAttachment.SaveAsFile fPathXML_SEM & xmlSupNum.Text & "_" & Format(Date, "yyyy-mm-dd") & ".xml"
'Save the email to the correct folder
InboxMsg.SaveAs fPathEmail_SEM & xmlSupNum.Text & "_" & Format(Date, "yyyy-mm-dd") & ".msg"
'Delete the message
InboxMsg.Move DeletedItems
Case Else
End Select
'Delete the temp file
On Error Resume Next
Kill fPathTemp & MsgAttachment.FileName
On Error GoTo 0
'Unload xmldoc
Set xmlDoc = Nothing
Set xmlTitle = Nothing
Set xmlSupNum = Nothing
End If
Next
End If
Next
'Loop through deleted items and delete
For Each InboxMsg In DeletedItems.Items
InboxMsg.Delete
Next
'Clean-up
Set InboxMsg = Nothing
Set DeletedItems = Nothing
Set MsgAttachment = Nothing
Set ns = Nothing
Set Inbox = Nothing
i = 0
End Sub

Likely cause: When you do this InboxMsg.Move, all of the messages in your inbox after the one that was moved are bumped up by one position in the list. So you end up skipping some of them. This is a major annoyance with VBA's For Each construct (and it doesn't seem to be consistent either).
Likely solution: Replace
For Each InboxMsg In Inbox.Items
with
For i = Inbox.Items.Count To 1 Step -1 'Iterates from the end backwards
Set InboxMsg = Inbox.Items(i)
This way you iterate backward from the end of the list. When you move a message to deleted items, then it doesn't matter when the following items in the list are bumped up by one, because you've already processed them anyway.

It's often not a good idea to modify the contents of a (sub)set of items while looping over them. You could modify your code so that it first identifies all of the items that need to be processed, and adds them to a Collection. Then process all the items in that collection.
Basically you shouldn't be removing items from the Inbox while you're looping through its contents. First collect all the items you want to process (in your Inbox loop), then when you're done looping, process that collection of items.
Here's some pseudo-code which demonstrates this:
Private Sub Application_Startup()
Dim collItems As New Collection
'Start by identifying messages of interest and add them to a collection
For Each InboxMsg In Inbox.Items
If InboxMsg.Class = olMail Then 'if it is a mail item
For Each MsgAttachment In InboxMsg.Attachments
If Right(MsgAttachment.DisplayName, 3) = "xml" Then
collItems.Add InboxMsg
Exit For
End If
Next
End If
Next
'now deal with the identified messages
For Each InboxMsg In collItems
ProcessMessage InboxMsg
Next InboxMsg
'Loop through deleted items and delete
For Each InboxMsg In DeletedItems.Items
InboxMsg.Delete
Next
End Sub
Sub ProcessMessage(InboxMsg As Object)
'deal with attachment(s) and delete message
End Sub

Related

Find Outlook Email with keywords in Subject & attachment using Excel VBA

I am trying to search Outlook for the most recent email with "Blue Recruit Req Data" in the Subject line.
There will be additional words in the subject line.
When an email is found I need to verify that it has an attachment.
I want to store the subject & the received date in variables and compare them to previous subject & date stored in the Excel file running the macro.
If the subject lines don't match & the date of the email is after the date last stored in the Excel file, then I want to save that attachment in a folder.
It is not finding emails that contain "Blue Recruit Req Data" in the subject.
Sub CheckEmail_BlueRecruit()
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Dim olAp As Object, olns As Object, olInb As Object
Dim olItm As Object, olAtch As Object, olMail As Object
'Outlook Variables for email
Dim sSubj As String, dtRecvd As String
Dim oldSubj As String, olddtRecvd As String
Sheets("Job Mapping").Visible = True
Sheets("CC Mapping").Visible = True
Sheets("Site Mapping").Visible = True
Sheets("Historical Blue Recruit Data").Visible = True
Sheets("Historical HRT Data").Visible = False
Sheets("Combined Attrition Data").Visible = True
Sheets.Add Before:=Sheets(1)
'Designate ECP Facilities Model file as FNAME
myPath = ThisWorkbook.Path
MainWorkbook = ThisWorkbook.Name
Range("A1").Select
ActiveCell.FormulaR1C1 = myPath
'designate file path for Attrition Files
FacModPath = Cells(1, 1).Value
Sheets(1).Delete
'Get Outlook Instance
Set olAp = GetObject(, "Outlook.application")
Set olns = olAp.GetNamespace("MAPI")
Set olInb = olns.GetDefaultFolder(6)
Set olMail = olInb.Items.Restrict("[Subject] = ""*Blue Recruit Req Data*""")
'Chec if there are any matching emails
If Not (olMail Is Nothing) Then
For Each olItm In olMail
If myItem.Attachments.Count <> 0 Then
dtRecvd = olItm.ReceivedTime
sSubj = olItm.Subject
oldSubj = Sheets("CC Mapping").Range("M2").Value
olddtRecvd = Sheets("CC Mapping").Range("M3").Value
If sSubj = oldSubj Or dtRecvd <= olddtRecvd Then
MsgBox "No new Blue Recruit data files to load."
Exit Sub
Else
Range("M2").Select
ActiveCell.FormulaR1C1 = sSubj
Range("M3").Select
ActiveCell.FormulaR1C1 = dtRecvd
For Each myAttachment In myItem.Attachments
If InStr(myAttachment.DisplayName, ".xlsx") Then
I = I + 1
myAttachment.SaveAs Filename:=FacModPath & "\" & myAttachment.DisplayName
Exit For
Else
MsgBox "No attachment found."
Exit For
End If
Next
End If
End If
Next
Else
MsgBox "No emails found."
Exit Sub
End If
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub
A separate, but related question. I want to search for emails that are in the Outlook Archive folder, or even a subfolder of Inbox. Do I need to format this line of code any differently?
Set olInb = olns.GetDefaultFolder(6)
Of course, iterating over all items in a folder is not really a good and right idea. You need to use the Restrict or Find/FindNext methods of the Items class to get only items that correspond to your conditions. 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
In the code posted above I've noticed the following line:
Set olMail = olInb.Items.Restrict("[Subject] = ""*Blue Recruit Req Data*""")
Be aware, the Restrict methods return an instance of the Items class which contains a collection of items that correspond to your condition, not a single item as you could think. For example:
Sub MoveItems()
Dim myNamespace As Outlook.NameSpace
Dim myFolder As Outlook.Folder
Dim myItems As Outlook.Items
Dim myRestrictItems As Outlook.Items
Dim myItem As Outlook.MailItem
Set myNamespace = Application.GetNamespace("MAPI")
Set myFolder = _
myNamespace.GetDefaultFolder(olFolderInbox)
Set myItems = myFolder.Items
Set myRestrictItems = myItems.Restrict("[Subject] = ""*Blue Recruit Req Data*""")
For i = myRestrictItems.Count To 1 Step -1
myRestrictItems(i).Move myFolder.Folders("Business")
Next
End Sub
Also, I'd change the filter string to include entries that may contain the passed substring:
filter = "#SQL=" & Chr(34) & "urn:schemas:httpmail:subject" & Chr(34) & " LIKE '%" & wordsInSubject & " %'"
To get items ordered, i.e. start from the recent or oldest ones you need to sort the collection by using the Sort methods of the Items class:
Items.Sort("[ReceivedTime]")
Finally, you may also find the AdvancedSearch method of the Application class helpful. The key benefits of using the AdvancedSearch method in Outlook are:
The search is performed in another thread. You don’t need to run another thread manually since the AdvancedSearch method runs it automatically in the background.
Possibility to search for any item types: mail, appointment, calendar, notes etc. in any location, i.e. beyond the scope of a certain folder. The Restrict and Find/FindNext methods can be applied to a particular Items collection (see the Items property of the Folder class in Outlook).
Full support for DASL queries (custom properties can be used for searching too). You can read more about this in the Filtering article in MSDN. To improve the search performance, Instant Search keywords can be used if Instant Search is enabled for the store (see the IsInstantSearchEnabled property of the Store class).
You can stop the search process at any moment using the Stop method of the Search class.
Read more about the AdvancedSearch method and find the sample code in the Advanced search in Outlook programmatically: C#, VB.NET article.
I have refactored some of your code so you can take advantage of calling procedures and organize your logic.
I didn't include all of your code though, but as I can see, you have enough knowledge to make it work.
A couple of suggestions:
1- Use option explicit at the top of your modules
2- Try to define your variables to something meaningful (use names anybody can understand)
3- Try to indent your code consistently (you could use RubberDuck
Before pasting your code:
Use early binding to set the reference to Outlook object library and take advantage of intellisense and other benefits
1) Click on tools | References
2) Check the Microsoft Outlook XXX Object Library
Here is the refactored code:
Execute it using F8 key and adjust it to fit your needs
Public Sub CheckEmail_BlueRecruit()
' Declare objects
Dim outlookApp As Outlook.Application
Dim outlookNamespace As Outlook.Namespace
Dim outlookFolder As Outlook.MAPIFolder
' Declare other variables
Dim filterKeywords As String
Dim filter As String
' Init objects
Set outlookApp = New Outlook.Application
Set outlookNamespace = Outlook.GetNamespace("MAPI")
Set outlookFolder = outlookNamespace.GetDefaultFolder(olFolderInbox)
' Init other variables
filterKeywords = "financial"
filter = "#SQL=" & Chr(34) & "urn:schemas:httpmail:subject" & Chr(34) & " LIKE '%" & filterKeywords & " %'"
' Loop through folders
LoopFolders outlookFolder, filter
End Sub
Private Sub LoopFolders(ByVal outlookFolder As Outlook.MAPIFolder, ByVal filter As String)
' DeclareObjects
Dim outlookSubFolder As Outlook.MAPIFolder
Dim outlookMail As Outlook.MailItem
ProcessFolder outlookFolder, filter
If outlookFolder.Folders.Count > 0 Then
For Each outlookSubFolder In outlookFolder.Folders
LoopFolders outlookSubFolder, filter
Next
End If
End Sub
Private Sub ProcessFolder(ByVal outlookFolder As Outlook.MAPIFolder, ByVal filter As String)
Dim outlookItems As Outlook.Items
Dim outlookMail As Outlook.MailItem
' Filter folder
Set outlookItems = outlookFolder.Items.Restrict(filter)
If Not outlookItems Is Nothing Then
For Each outlookMail In outlookItems
If outlookMail.Attachments.Count <> 0 Then
Debug.Print outlookMail.Subject
End If
Next outlookMail
End If
End Sub
Let me know if it works and you need any more help

How do I save Excel attachments in new mail based on both time received and subject line?

I'm fairly new to coding. I would like to know how to save particular Excel attachments in Outlook inbox ("Morning Emails") using subject line keywords and the times received.
I receive five new emails each day, with Excel attachments to save to the same drive folder.
The time received can be either last night or early this morning.
The names of all five files and times received are different.
The inbox does not empty. I don't want to save what I saved yesterday or 2 weeks ago.
Sub SaveAttachments()
Dim ol As Outlook.Application
Dim ns As Outlook.Namespace
Dim fol As Outlook.Folder
Dim i As Object
Dim mi As Outlook.MailItem
Dim at As Outlook.Attachment
Set ol = New Outlook.Application
Set ns = ol.GetNamespace("MAPI")
Set fol = ns.Folders(1).Folders("Morning Emails")
For Each i In fol.Items
If i.Class = olMail Then
Set mi = i
If mi.Attachments.Count > 0 Then
For Each at In mi.Attachments
at.SaveAsFile "C:\Users\nader\OneDrive\Documents\" & _
at.Filename & Format(mi.ReceivedTime, " MM-DD-YYYY")
Next at
End If
End If
Next i
End Sub
"Attempted operation failed; object could not be found" for line: Set fol = ns.Folders(1).Folders("Morning Emails"), even though I have created that sub-folder under my Outlook inbox.
Set ol = New Outlook.Application
There is no need to create a new Outlook Application instance in the code. Use the Application property to get the host application instance in Outlook VBA macros.
I'd recommend handling the NewMailEx event of the Application class. This event fires once for every received item that is processed by Microsoft Outlook. The item can be one of several different item types, for example, MailItem, MeetingItem, or SharingItem. The EntryIDsCollection string contains the Entry ID that corresponds to that item.
The NewMailEx event fires when a new message arrives in the Inbox and before client rule processing occurs. You can use the Entry ID returned in the EntryIDCollection array to call the NameSpace.GetItemFromID method and process the item.
Private Sub outApp_NewMailEx(ByVal EntryIDCollection As String)
Dim itm as Object
Set itm = NS.GetItemFromID(EntryIDCollection)
Debug.Print "mail received"
If itm.Class = olMail Then
Dim it as Outlook.MailItem
Set it = itm
if it.Subject = "your subject" then
If it.Attachments.Count > 0 Then
For Each at In mi.Attachments
at.SaveAsFile "C:\Users\nader\OneDrive\Documents\" & _
at.Filename & Format(mi.ReceivedTime, " MM-DD-YYYY")
Next at
End If
End If
End If
End Sub

For loop not looping through all items in Outlook email folder [duplicate]

I wanted to develop VBA code that:
Loops through all email items in mailbox
If there are any type of other items say "Calendar Invitation" skips that item.
Finds out the emails with attachments
If attached file has ".xml" extension and a specific title in it, saves it to a directory, if not it keeps searching
Puts all email includes .xml attachments to "Deleted Items" folder after doing step 4 and deletes all emails in that folder by looping.
Code works perfect EXCEPT;
For example
There are 8 email received with ".xml" file attached to each one of them in your mailbox.
run the code
you will see only 4 of the 8 items are processed successfully, other 4 remain in their positions.
If you run the code again, now there would be 2 items processed successfully and other 2 remain in your mailbox.
Problem: After running the code, it is supposed to process all files and deletes them all not the half of them in each run. I want it to process all items at a single run.
BTW, this code runs every time I open the Outlook.
Private Sub Application_Startup()
'Initializing Application_Startup forces the macros to be accessible from other offic apps
'Process XML emails
Dim InboxMsg As Object
Dim DeletedItems As Outlook.Folder
Dim MsgAttachment As Outlook.Attachment
Dim ns As Outlook.NameSpace
Dim Inbox As Outlook.Folder
Dim fPathTemp As String
Dim fPathXML_SEM As String
Dim fPathEmail_SEM As String
Dim i As Long
Dim xmlDoc As New MSXML2.DOMDocument60
Dim xmlTitle As MSXML2.IXMLDOMNode
Dim xmlSupNum As MSXML2.IXMLDOMNode
'Specify the folder where the attachments will be saved
fPathTemp = "some directory, doesn't matter"
fPathXML_SEM = "some directory, doesn't matter"
fPathEmail_SEM = "some directory, doesn't matter"
'Setup Outlook
Set ns = GetNamespace("MAPI")
Set Inbox = ns.Folders.Item("mailbox-name").Folders("Inbox")
Set DeletedItems = ns.Folders.Item("mailbox-name").Folders("Deleted Items")
'Loop through all Items in Inbox, find the xml attachements and process if they are the matching reponses
'On Error Resume Next
For Each InboxMsg In Inbox.Items
If InboxMsg.Class = olMail Then 'if it is a mail item
'Check for xml attachement
For Each MsgAttachment In InboxMsg.Attachments
If Right(MsgAttachment.DisplayName, 3) = "xml" Then
'Load XML and test for the title of the file
MsgAttachment.SaveAsFile fPathTemp & MsgAttachment.FileName
xmlDoc.Load fPathTemp & MsgAttachment.FileName
Set xmlTitle = xmlDoc.SelectSingleNode("//title")
Select Case xmlTitle.Text
Case "specific title"
'Get supplier number
Set xmlSupNum = xmlDoc.SelectSingleNode("//supplierNum")
'Save the XML to the correct folder
MsgAttachment.SaveAsFile fPathXML_SEM & xmlSupNum.Text & "_" & Format(Date, "yyyy-mm-dd") & ".xml"
'Save the email to the correct folder
InboxMsg.SaveAs fPathEmail_SEM & xmlSupNum.Text & "_" & Format(Date, "yyyy-mm-dd") & ".msg"
'Delete the message
InboxMsg.Move DeletedItems
Case Else
End Select
'Delete the temp file
On Error Resume Next
Kill fPathTemp & MsgAttachment.FileName
On Error GoTo 0
'Unload xmldoc
Set xmlDoc = Nothing
Set xmlTitle = Nothing
Set xmlSupNum = Nothing
End If
Next
End If
Next
'Loop through deleted items and delete
For Each InboxMsg In DeletedItems.Items
InboxMsg.Delete
Next
'Clean-up
Set InboxMsg = Nothing
Set DeletedItems = Nothing
Set MsgAttachment = Nothing
Set ns = Nothing
Set Inbox = Nothing
i = 0
End Sub
Likely cause: When you do this InboxMsg.Move, all of the messages in your inbox after the one that was moved are bumped up by one position in the list. So you end up skipping some of them. This is a major annoyance with VBA's For Each construct (and it doesn't seem to be consistent either).
Likely solution: Replace
For Each InboxMsg In Inbox.Items
with
For i = Inbox.Items.Count To 1 Step -1 'Iterates from the end backwards
Set InboxMsg = Inbox.Items(i)
This way you iterate backward from the end of the list. When you move a message to deleted items, then it doesn't matter when the following items in the list are bumped up by one, because you've already processed them anyway.
It's often not a good idea to modify the contents of a (sub)set of items while looping over them. You could modify your code so that it first identifies all of the items that need to be processed, and adds them to a Collection. Then process all the items in that collection.
Basically you shouldn't be removing items from the Inbox while you're looping through its contents. First collect all the items you want to process (in your Inbox loop), then when you're done looping, process that collection of items.
Here's some pseudo-code which demonstrates this:
Private Sub Application_Startup()
Dim collItems As New Collection
'Start by identifying messages of interest and add them to a collection
For Each InboxMsg In Inbox.Items
If InboxMsg.Class = olMail Then 'if it is a mail item
For Each MsgAttachment In InboxMsg.Attachments
If Right(MsgAttachment.DisplayName, 3) = "xml" Then
collItems.Add InboxMsg
Exit For
End If
Next
End If
Next
'now deal with the identified messages
For Each InboxMsg In collItems
ProcessMessage InboxMsg
Next InboxMsg
'Loop through deleted items and delete
For Each InboxMsg In DeletedItems.Items
InboxMsg.Delete
Next
End Sub
Sub ProcessMessage(InboxMsg As Object)
'deal with attachment(s) and delete message
End Sub

Export multiple emails to one csv file

I am trying to export all emails in specific folder "Not actioned DO" to a CSV file then move these emails to another folder "Actioned DO".
I edited code I found.
Only the last email is saved on the csv file.
I need all emails to be in the same CSV file.
Sub PseudoArchive()
Dim objNamespace As Outlook.NameSpace
Dim sourceFolder As Outlook.MAPIFolder
Dim destinationFolder As Outlook.MAPIFolder
Dim Items As Outlook.Items
Dim Item As Object
Dim msg As String
Dim i As Long
Set objNamespace = GetNamespace("MAPI")
Set sourceFolder = objNamespace.Folders("msroumi#hotmail.com").Folders("Inbox").Folders("Not Actioned DO")
Set destinationFolder = objNamespace.Folders("msroumi#hotmail.com").Folders("Inbox").Folders("Actioned DO")
Set Items = sourceFolder.Items
'Move emails in sourceFolder to destinationFolder
msg = Items.Count & " Items in " & sourceFolder.Name & ", Move?"
If MsgBox(msg, vbYesNo) = vbYes Then
For i = Items.Count To 1 Step -1
Set Item = Items.Item(i)
DoEvents
Item.Move destinationFolder
Item.SaveAs "D:\Excel\Learning Excel VBA\Outlook VBA\MyEmail.txt", olTXT
Next
End If
End Sub
Firstly, you are sving the item after it's already been moved (and deleted). Call SaveAs before calling Move. Or use the returned value of the Move function to reset the item: set Item = Item.Move destinationFolder.
Most importantly however, is that you are saving all message with the same file name, continuously overwriting the old files, thus only the last file survives. Make the file name unique - you can ether use the message Subject property for that (make sure you remove all invalid chars, such as ":") or you can do something as simple as adding a counter to te hfile name:
Item.SaveAs "D:\Excel\Learning Excel VBA\Outlook VBA\MyEmail" & i & ".txt", olTXT

Updating shared calendar

I am trying to update a shared calendar from an Excel sheet. The code works for the owner of this shared calendar, but it fails for me. The calendar was shared to me and I have full owner permissions.
I can edit the calendar manually, but the idea is that anyone will be able run the macro from this Excel sheet to update the shared calendar.
The relevant code, up to the failure point:
Sub UpdateSched()
Dim olApp As Outlook.Application
Dim olNameSpace As Outlook.Namespace
Dim olFolder As Outlook.MAPIFolder
Dim olFldrOwner As Outlook.Recipient
On Error Resume Next
' check if Outlook is running
Set olApp = GetObject("Outlook.Application")
If Err <> 0 Then
'if not running, start it
Set olApp = CreateObject("Outlook.Application")
End If
On Error GoTo 0
Set olNameSpace = olApp.GetNamespace("MAPI")
Set olFldrOwner = olNameSpace.CreateRecipient("ownrAlias")
olFldrOwner.Resolve
Set olFolder = Nothing
If olFldrOwner.Resolved Then
Set olFolder = olNameSpace.GetSharedDefaultFolder(olFldrOwner, olFolderCalendar)
' If olFolder Is Nothing Then
' Debug.Print "Nothing"
' Else
' Debug.Print olFolder.Name '<-Error here if the if-block is run
' End If
'******************************
Set olFolder = olFolder.Folders("Transport Sched") '<-Object Not Found Error
'******************************
End If
'Code below updates appointments on the shared calendar
The full error
'The attempted operation failed. An object could not be found'
For testing, I added the commented out block. This made me think that the error might be in the previous line. When this block is un-commented then the code errors out on the line after Else (same error). So the olFolder object is not nothing, but it can't be found.
It's under "Shared Calendars" I get the error. It updates a calendar I created, that's under "My Calendars."
Is it a problem with finding the correct folder for the shared calendar?
The path to the folder shouldn't change, so I could hard-code it so it works for everyone, is that possible?
I came up with a solution to my problem but in a completely different way than I was trying with the code listed in the question. In case anyone else needs it, here is the solution:
Sub ListCalendars()
Dim olApp As Outlook.Application
Dim olPane As Outlook.NavigationPane
Dim olModule As Outlook.CalendarModule
Dim olGroup As Outlook.NavigationGroup
Dim olNavFolder As Outlook.NavigationFolder
Dim olFolder As Folder
Dim i As Integer, j As Integer
On Error Resume Next
' check if Outlook is running
Set olApp = GetObject("Outlook.Application")
If Err <> 0 Then
'if not running, start it
Set olApp = CreateObject("Outlook.Application")
End If
On Error GoTo 0
Set olPane = olApp.ActiveExplorer.NavigationPane
Set olModule = olPane.Modules.GetNavigationModule(olModuleCalendar)
Set olGroup = olModule.NavigationGroups.GetDefaultNavigationGroup(olMyFoldersGroup)
'Dummy Do loop allows exit from within nested For-Next loops
Do
For i = 1 To olModule.NavigationGroups.Count 'Cycle through all Nav Groups
Set olGroup = olModule.NavigationGroups.Item(i)
Debug.Print olGroup.Name
For j = 1 To olGroup.NavigationFolders.Count 'Cycle through all calendars in group
Set olNavFolder = olGroup.NavigationFolders.Item(j)
Debug.Print " - " & olNavFolder.DisplayName
'Un-comment If-block below if searching for a particular calendar:
'CalendarName is the name of the calendar,as listed in your navigation pane
' If olNavFolder.DisplayName = "CalendarName" Then
' Debug.Print "Found it!"
' Set olFolder = olNavFolder.Folder 'To get folder object from NavigationFolder
' Exit Do
' End If
Next
Next
Exit Do 'To prevent endless loop
Loop While True
'If-block below displays results if looking for matching calendar name
'If olFolder Is Nothing Then
' Debug.Print vbNewLine & "No match found"
'Else
' Debug.Print vbNewLine & "Matching calendar found: " & olFolder.Name
'End If
End Sub
This code was modified from this page here. Basically, accessing someone else's calendar folder object directly gave me issues, even if the calendar had been shared. By using the various navigation objects though, I was able to cycle through all the calendars listed in my navigation pane, including all the shared calendars.
As provided this routine merely lists the main folders and one level of subfolders. If the two if-blocks are uncommented then the routine will search for the calendar with a given name(just replace CalendarName) and will display whether or not a match was found.
The dummy Do loop was one way to break out of nested loops. There's multiple other ways to accomplish this listed in this SO question.
One other tricky thing is that NavigationFolder objects are NOT the same as Folder objects. This seemingly inconsequential line:
Set olFolder = olNavFolder.Folder
is actually very important if you want to make changes to the calendar folder, since these two object types have different properties and methods.

Resources