Searching in shared folder limited to 250 in Outlook - vba

At work we are using Outlook 2016 and we have a shared folder. I am trying to count those emails in a subfolder of this shared folder which have a specified text in their body. I got one solution, but that is too slow (there is thousands of emails in one month).
My first solution, which works:
Sub SearchBody()
Dim myItems As Outlook.Items
Dim ShareInbox As Outlook.MAPIFolder
Dim myNamespace As Outlook.NameSpace
Dim myRecipient As Outlook.Recipient
Dim SubFolder As Object
Dim i As Integer
Dim myRestrictItems As Outlook.Items
Dim myItem As Object
Dim z As Integer
Dim dateStart As Date
i = 0
dateStart = DateTime.now
Set myNamespace = Application.GetNamespace("MAPI")
Set myRecipient = myNamespace.CreateRecipient("email#email.com")
Set ShareInbox = myNamespace.GetSharedDefaultFolder(myRecipient, olFolderInbox)
Set SubFolder = ShareInbox.Parent.Folders("SomeSubFolder")
Set myItems = SubFolder.Items
Set myRestrictItems = myItems.Restrict("[SentOn]>='2/1/2018' AND [SentOn]<'3/1/2018'")
For z = myRestrictItems.Count To 1 Step -1
If InStr(1, myRestrictItems(z).Body, "SomeStringToSearch") > 0 Then
i = i + 1
End If
Next
MsgBox i & vbNewLine & Format(DateTime.now - dateStart, "hh:mm:ss")
End Sub
So it works, but too slow (7-10 minutes).
My next code is:
Sub SearchBody2()
Dim table As Outlook.table
Dim filter As String
Dim myNamespace As Outlook.NameSpace
Dim myRecipient As Outlook.Recipient
Dim ShareInbox As Outlook.MAPIFolder
Dim SubFolder As Object
Dim row As Outlook.row
Dim myRestrictItems As Outlook.Items
Dim myItems As Outlook.Items
filter = "#SQL=" & Chr(34) & "urn:schemas:httpmail:textdescription" & Chr(34) & " like '%SomeStringToSearch%'"
Set myNamespace = Application.GetNamespace("MAPI")
Set myRecipient = myNamespace.CreateRecipient("email#email.com")
Set ShareInbox = myNamespace.GetSharedDefaultFolder(myRecipient, olFolderInbox)
Set SubFolder = ShareInbox.Parent.Folders("SomeSubFolder")
Set table = SubFolder.GetTable(filter, Outlook.OlTableContents.olUserItems)
MsgBox table.GetRowCount
End Sub
(I know that in this code there is no filter for date like in the first)
This works too, until it reaches 250 hits: it stops then.
Is there any solution to avoid the stop of the search? I am not admin of this shared folder, so I have no rights for settings.
Folder tree:

Your SubFolder Should be Set SubFolder = ShareInbox.folders("SomeSubFolder")
To add Date to your filter then example would be
filter = "#SQL=" & Chr(34) & "urn:schemas:httpmail:datereceived" & _
Chr(34) & " >= '02/01/2018' And " & _
Chr(34) & "urn:schemas:httpmail:datereceived" & _
Chr(34) & " < '02/28/2018' And " & _
Chr(34) & "urn:schemas:httpmail:textdescription" & _
Chr(34) & "Like '%SomeStringToSearch%'"
If your having trouble working with shared folder then you can use CurrentFolder Property which represents the current folder displayed in the explorer
Below example has loop just for testing- deleted if not need it
Option Explicit
Public Sub Example()
Dim TargetFolder As Outlook.MAPIFolder
Dim Items As Outlook.Items
Dim i As Long
If TargetFolder Is Nothing Then Set TargetFolder = ActiveExplorer.CurrentFolder
Debug.Print TargetFolder.Name
Dim Filter As String
Filter = "#SQL=" & Chr(34) & "urn:schemas:httpmail:datereceived" & _
Chr(34) & " >= '02/01/2018' AND " & _
Chr(34) & "urn:schemas:httpmail:datereceived" & _
Chr(34) & " < '02/28/2018' AND " & _
Chr(34) & "urn:schemas:httpmail:textdescription" & _
Chr(34) & "Like '%SomeStringToSearch%'"
Set Items = TargetFolder.Items.Restrict(Filter)
MsgBox (Items.Count & " Items in " & TargetFolder.Name)
Debug.Print Items.Count & " Items in " & TargetFolder.Name
For i = Items.Count To 1 Step -1
DoEvents
Debug.Print Items(i).Subject 'Immediate Window
Next
End Sub

Related

Get only today's appointments through Outlook VBA

I am extracting all appointments across all Outlook accounts for today.
I am experiencing the same issue encountered in this post here, but I am trying to do this through VBA.
Originally I managed to get the appointments for today, but it would also return reoccurring meetings that are not taking place today (like in the linked question).
I do not understand how the Powershell code, in the answer, manages to filter out the reoccurring appointments, because in my VBA attempt I get the whole week of appointments.
This is my attempt. I've included the filter where I get the appointments for today as well the reoccurring appointments which do not take place today.
Sub GetAllCalendarAppointmentsForToday()
Dim olApplication As Outlook.Application
Dim olNamespace As NameSpace
Dim olAccounts As Accounts
Dim olStore As Outlook.Store
Dim olCalendarFolder As Outlook.Folder
Dim olCalendarItems As Outlook.Items
Dim olTodayCalendarItems As Outlook.Items
Dim strFilter As String
Dim strFilter2 As String
Set olApplication = CreateObject("Outlook.Application")
Set olNamespace = olApplication.Session
Set olAccounts = olNamespace.Accounts
Debug.Print olAccounts.Count
For Each oAccount In olAccounts
Debug.Print oAccount
Set olStore = oAccount.DeliveryStore
Set olCalendarFolder = olStore.GetDefaultFolder(olFolderCalendar)
Set olCalendarItems = olCalendarFolder.Items
olCalendarItems.Sort "[Start]", True
olCalendarItems.IncludeRecurrences = True
Debug.Print olCalendarItems.Count
'Find your today's appointments
strFilter = Format(Now, "ddddd")
strFilter2 = Format(DateAdd("d", 7, Now), "ddddd")
Debug.Print strFilter
Debug.Print strFilter2
'strFilter = "[Start] > " & Chr(34) & strFilter & " 00:00" & Chr(34) & " AND [Start] < " & Chr(34) & strFilter & " 00:00" & Chr(34)
strFilter = "[Start] > " & Chr(34) & strFilter & " 00:00" & Chr(34) & " AND [Start] < " & Chr(34) & strFilter2 & " 00:00" & Chr(34)
Debug.Print strFilter
Set olTodayCalendarItems = olCalendarItems.Restrict(strFilter)
Debug.Print olTodayCalendarItems.Count
Debug.Print "Begin Print of Appointments"
For Each objAppointment In olTodayCalendarItems
Counter = Counter + 1
Debug.Print Counter & ":" & objAppointment.Subject & " " & objAppointment.Location & " [" & objAppointment.Start & "|" & objAppointment.End & "]"
Next
Debug.Print vbNewLine
Next
End Sub
Edit #1:
As per Eugene's answer, I updated the strFilter to be this to no avail
strFilter = [Start] <= '07/15/2020 11:59 PM' AND [End] >= '07/15/2020 12:00 AM'
In addition, I put IncludeReccurence first as well and no change in the results
Edit #2
Replaced the for each loop to use GetFirst() and GetNext() to no avail
Set olTodayCalendarItems = olCalendarItems.Restrict(strFilter)
Set olItem = olTodayCalendarItems.GetFirst()
Do While Not olItem Is Nothing
Set olAppointment = olItem
counter = counter + 1
Debug.Print counter & ":" & olAppointment.Subject & " " & olAppointment.Location & " [" & olAppointment.Start & "|" & olAppointment.End & "]"
Set olItem = olTodayCalendarItems.GetNext()
Loop
Edit #3:
I created a VB.NET application where I used the function, provided in the link in the answer, verbatim and it worked as expected. So maybe there is a issue in VBA (unlikely) or I missed something small in my VBA script?
Edit #4:
The problem was in my logic all along. Items needed to be sorted in ascending. Thank you to both Eugene and niton
The OP left a comment to indicate Restrict is valid.
" ... the link to the docs on IncludeRecurrences ... mentioned that .Sort needs to be done in ascending order"
It is possible .Restrict is not appropriate for this task.
An example using .Find.
Items.IncludeRecurrences property(Outlook) https://learn.microsoft.com/en-us/office/vba/api/outlook.items.includerecurrences
Sub DemoFindNext()
' https://learn.microsoft.com/en-us/office/vba/api/outlook.items.includerecurrences
Dim myNameSpace As Outlook.NameSpace
Dim tdystart As Date
Dim tdyend As Date
Dim myAppointments As Outlook.Items
Dim currentAppointment As Outlook.AppointmentItem
Set myNameSpace = Application.GetNamespace("MAPI")
tdystart = VBA.Format(Now, "Short Date")
tdyend = VBA.Format(Now + 1, "Short Date")
Set myAppointments = myNameSpace.GetDefaultFolder(olFolderCalendar).Items
myAppointments.Sort "[Start]"
myAppointments.IncludeRecurrences = True
Set currentAppointment = myAppointments.Find("[Start] >= """ & tdystart & """ and [Start] <= """ & tdyend & """")
While TypeName(currentAppointment) <> "Nothing"
Debug.Print currentAppointment.Subject
' MsgBox currentAppointment.Subject
Set currentAppointment = myAppointments.FindNext
Wend
End Sub
Microsoft doesn’t recommend using the Count property in case you set the IncludeRecurrences property. The Count property may return unexpected results and cause an infinite loop. Read more about that in the How To: Use Restrict method in Outlook to get calendar items article.
Here is a sample VB.NET code where you can see how you can filter appointment items properly:
Imports System.Text
Imports System.Diagnostics
' ...
Private Sub RestrictCalendarItems(folder As Outlook.MAPIFolder)
Dim dtEnd As DateTime = New DateTime(DateTime.Now.Year, DateTime.Now.Month, _
DateTime.Now.Day, 23, 59, 0, 0)
Dim restrictCriteria As String = "[Start]<=""" + dtEnd.ToString("g") + """" + _
" AND [End]>=""" + DateTime.Now.ToString("g") + """"
Dim strBuilder As StringBuilder = Nothing
Dim folderItems As Outlook.Items = Nothing
Dim resultItems As Outlook.Items = Nothing
Dim appItem As Outlook._AppointmentItem = Nothing
Dim counter As Integer = 0
Dim item As Object = Nothing
Try
strBuilder = New StringBuilder()
folderItems = folder.Items
folderItems.IncludeRecurrences = True
folderItems.Sort("[Start]")
resultItems = folderItems.Restrict(restrictCriteria)
item = resultItems.GetFirst()
Do
If Not IsNothing(item) Then
If (TypeOf (item) Is Outlook._AppointmentItem) Then
counter = counter + 1
appItem = item
strBuilder.AppendLine("#" + counter.ToString() + _
" Start: " + appItem.Start.ToString() + _
" Subject: " + appItem.Subject + _
" Location: " + appItem.Location)
End If
Marshal.ReleaseComObject(item)
item = resultItems.GetNext()
End If
Loop Until IsNothing(item)
If (strBuilder.Length > 0) Then
Debug.WriteLine(strBuilder.ToString())
Else
Debug.WriteLine("There is no match in the " _
+ folder.Name + " folder.")
End If
catch ex As Exception
System.Windows.Forms.MessageBox.Show(ex.Message)
Finally
If Not IsNothing(folderItems) Then Marshal.ReleaseComObject(folderItems)
If Not IsNothing(resultItems) Then Marshal.ReleaseComObject(resultItems)
End Try
End Sub

Restrict Outlook Items to today's date - VBA

I've written some code that scans my default Outlook inbox for emails received today with a specific subject.
I then download the attachment for Outlook items that meet my criteria. I am having trouble designating the Restrict method to pull back items received today.
Here is what I have:
Sub DownloadAttachmentFirstUnreadEmail()
Dim oOlAp As Object, oOlns As Object, oOlInb As Object
Dim oOlItm As Object, oOlAtch As Object
Dim sFilter As String
Dim NewFileName As String
NewFileName = "C:\Temp\" & "CHG_Daily_Extract_" & Format(Date, "MM-DD-YYYY") & ".csv"
'~~> Get Outlook instance
Set oOlAp = GetObject(, "Outlook.application")
Set oOlns = oOlAp.GetNamespace("MAPI")
Set oOlInb = oOlns.GetDefaultFolder(olFolderInbox)
'Declare email item restriction
sFilter = "[ReceivedTime] = '" & Format(Date, "DDDDD HH:NN") & "'"
'Catch
If oOlInb.Items.Restrict(sFilter).Count > 0 Then
'~~> Loop thru today's emails
For Each oOlItm In oOlInb.Items.Restrict(sFilter)
'~> Check if the email subject matches
If oOlItm = "ASG CDAS Daily CHG Report" Then
'~~> Download the attachment
For Each oOlAtch In oOlItm.Attachments
oOlAtch.SaveAsFile NewFileName
Exit For
Next
End If
Exit For
Next
'Display if no emails today
Else: MsgBox "No items"
End If
End Sub
When I run the code, I consistently receive my catch message of "No items".
Please let me know if I am using the Restrict method incorrectly. Thank you so much for the help.
How about the following-
Filter = "#SQL=" & "%today(" & Chr(34) & ("urn:schemas:httpmail:datereceived") & _
Chr(34) & ")%
Or with Attachment
Filter = "#SQL=" & "%today(" & Chr(34) & ("urn:schemas:httpmail:datereceived") & _
Chr(34) & ")% AND " & _
Chr(34) & "urn:schemas:httpmail:hasattachment" & _
Chr(34) & "=1"
Example
Option Explicit
Private Sub Examples()
Dim olNs As Outlook.NameSpace
Dim Inbox As Outlook.MAPIFolder
Dim Items As Outlook.Items
Dim Msg As String
Dim i As Long
Dim Filter As String
Set olNs = Application.GetNamespace("MAPI")
Set Inbox = olNs.GetDefaultFolder(olFolderInbox)
Filter = "#SQL=" & "%today(" & Chr(34) & ("urn:schemas:httpmail:datereceived") & _
Chr(34) & ")%"
Set Items = Inbox.Items.Restrict(Filter)
Msg = Items.Count & " Items in " & Inbox.Name
If MsgBox(Msg, vbYesNo) = vbYes Then
For i = Items.Count To 1 Step -1
Debug.Print Items(i) 'Immediate Window
Next
End If
End Sub
Filtering Items Using a Date-time Comparison MSDN
Outlook Date-time Macros
The date macros listed below return filter strings that compare the value of a given date-time property with a specified date in UTC; SchemaName is any valid date-time property referenced by namespace.
Note Outlook date-time macros can be used only in DASL queries.
Macro Syntax Description
today %today(" SchemaName")% Restricts for items with SchemaName
property value equal to today
More Examples Here

Folder on root, not under Inbox generates error: The attempted operation failed. An Object Could not be found [duplicate]

This question already has answers here:
Reference a folder not under the default inbox
(2 answers)
Closed 4 years ago.
I have created a folder on root, not under Inbox. What is the syntax to move to root folder?
I'm getting error:
The attempted operation failed
An Object Could not be found
Debug points to the below line myRestrictItems(i).Move myFolder.folders("Business")
Option Explicit
Public Sub Example()
Dim myNamespace As Outlook.NameSpace
Dim myFolder As Outlook.MAPIFolder
Dim myRestrictItems As Outlook.Items
Dim myItems As Outlook.Items
Dim myItem As Object
Dim i As Long
Dim Filter As String
Dim Msg As String
Set myNamespace = Application.GetNamespace("MAPI")
Set myFolder = myNamespace.GetDefaultFolder(olFolderInbox)
Set myItems = myFolder.Items
Filter = "#SQL=" & Chr(34) & "urn:schemas:httpmail:datereceived" & _
Chr(34) & " >= '01/01/2018' And " & _
Chr(34) & "urn:schemas:httpmail:datereceived" & _
Chr(34) & " < '23/03/2018' And " & _
Chr(34) & "urn:schemas:httpmail:fromname" & _
Chr(34) & "Like '%Jayakumar Krishnamoorthy%'"
Set myRestrictItems = myItems.Restrict(Filter)
For i = myRestrictItems.Count To 1 Step -1
myRestrictItems(i).Move myFolder.folders("Business")
'Msg = myRestrictItems.Count & " Items in " & myFolder.Name & " Folder"
'MsgBox (Msg)
Next
End Sub
The correct syntax should be
myRestrictItems(i).Move myNamespace.Folders("Business")
Also Move you msgbox outside the loop, Example
Set myRestrictItems = myItems.Restrict(Filter)
Msg = myRestrictItems.Count & " Items in " & myFolder.Name & " Folder, Move it?"
If MsgBox(Msg, vbYesNo) = vbYes Then
For i = myRestrictItems.Count To 1 Step -1
myRestrictItems(i).Move myNamespace.Folders("Business")
Next
End If
Run a quick loop through the folders to debug.print their names and any other properties you might find useful. The displayed name and internal name may not be the same.

Download attachments from From UnRead Items and are from specific sender

I want to download all attachments from emails which are both unread and received from the specific sender in MS Outlook.
I found a code, which downloads all attachments from all unread emails.
Downloading Attachments from Unread Emails of MS Outlook and tried to adapt it.
However, filter is not working properly. It shows that there are no such e-mails.
Filter = "[Unread] = True And [SenderEmailAddress] = 'yrybchuk#gmail.com'"
Below is the entire code:
Option Explicit
Public Sub Example()
Dim oOlAp As Object
Dim olNs As Outlook.Namespace
Dim Inbox As Outlook.MAPIFolder
Dim Items As Outlook.Items
Dim Item As Outlook.MailItem
Dim Atmt As Attachment
Dim Filter As String
Dim FilePath As String
Dim AtmtName As String
Dim i As Long
'// Set Inbox Reference
Set oOlAp = GetObject(, "Outlook.application")
Set olNs = oOlAp.GetNamespace("MAPI")
Set Inbox = olNs.GetDefaultFolder(olFolderInbox)
FilePath = "C:\Users\irybchuk\Documents\"
Filter = "[Unread] = True And [SenderEmailAddress] = 'yrybchuk#gmail.com'"
Set Items = Inbox.Items.Restrict(Filter)
'// Loop through backwards
For i = Items.Count To 1 Step -1
Set Item = Items.Item(i)
DoEvents
If Item.Class = olMail Then
Debug.Print Item.Subject ' Immediate Window
For Each Atmt In Item.Attachments
AtmtName = FilePath & Atmt.FileName
Atmt.SaveAsFile AtmtName
Next
End If
Next
Set Inbox = Nothing
Set Items = Nothing
Set Item = Nothing
Set Atmt = Nothing
Set olNs = Nothing
End Sub
I believe that here: How to filter items sendername from Items_ItemAdd Events? could be described possible solution how to change filter line. However, I couldn't do it.
Your filter seems to work for me but here is different one SQL DASL syntax you can use
Filter = "#SQL=" & Chr(34) & "urn:schemas:httpmail:fromname" & _
Chr(34) & " Like '%yrybchuk#gmail.com%' AND " & _
Chr(34) & "urn:schemas:httpmail:read" & _
Chr(34) & "=0"
Or better yet one with the attachment Restricted Filter to improve your loop
Filter = "#SQL=" & Chr(34) & "urn:schemas:httpmail:fromname" & _
Chr(34) & " Like '%yrybchuk#gmail.com%' AND " & _
Chr(34) & "urn:schemas:httpmail:hasattachment" & _
Chr(34) & "=1 AND " & _
Chr(34) & "urn:schemas:httpmail:read" & _
Chr(34) & "=0"
remember to update %yrybchuk#gmail.com%
FYI
If code is being run from Outlook then you don't need
oOlAp = GetObject(, "Outlook.application")

how to apply filter only on outlook messages using vba

The following code which get all uncategorised items from outlook however it returns all the items including appointments and meetings. I need a code which returns only messages which are not categorised.
Sub NullCategoryRestriction()
Dim oFolder As Outlook.Folder
Dim oItems As Outlook.Items
Dim Filter As String
'DASL Filter can test for null property.
'This will return all items that have no category.
Filter = "#SQL=" & Chr(34) & _
"urn:schemas-microsoft-com:office:office#Keywords" & _
Chr(34) & " is null"
Set oFolder = Application.ActiveExplorer.CurrentFolder
Set oItems = oFolder.Items.Restrict(Filter)
Debug.Print oItems.Count
End Sub
You need to include the MessageClass property check to the filter as well. The property returns a string representing the message class for the Outlook item.
The following code worked for me.
Filter = "#SQL=" & Chr(34) & _
"urn:schemas-microsoft-com:office:office#Keywords" & _
Chr(34) & " is null"
Set ml = ml.Items.Restrict(Filter)
For i = ml.Count To 1 Step -1
If TypeOf ml(i) Is MailItem Then
End if
Next
There may be no noticeable gain in efficiency but you could apply a second restrict rather than checking each item with If TypeOf ml(i) Is MailItem Then.
Option Explicit
Sub NullCategoryRestriction_MailItems()
Dim oFolder As Folder
Dim oItems As Items
Dim ml As Items
Dim i As Long
Dim oFilter As String
Dim oFilter2 As String
Debug.Print
'DASL Filter can test for null property.
'This will return all items that have no category.
' https://learn.microsoft.com/en-us/office/vba/outlook/How-to/Search-and-Filter/filter-items-that-do-not-have-categories
oFilter = "#SQL=" & Chr(34) & _
"urn:schemas-microsoft-com:office:office#Keywords" & _
Chr(34) & " is null"
Debug.Print " " & oFilter
Set oFolder = ActiveExplorer.CurrentFolder
Set oItems = oFolder.Items.Restrict(oFilter)
Debug.Print " oItems.Count: " & oItems.Count
'This will return mailitems
' https://learn.microsoft.com/en-us/office/vba/outlook/concepts/forms/item-types-and-message-classes
oFilter2 = "[MessageClass] = 'IPM.Note'"
Debug.Print " " & oFilter2
Set ml = oItems.Restrict(oFilter2)
Debug.Print " ml.Count: " & ml.Count
For i = ml.Count To 1 Step -1
' If TypeOf ml(i) Is mailItem Then
Debug.Print ml(i).MessageClass & ": " & ml(i).subject
'End If
Next
End Sub
The TypeOf test is no longer necessary.