outlook macro advanced search - vba

I would like to create a macro to perform an "Advanced Search" on tasks subject and optionally tasks body. For instance search for "#Cris"
I have copied and modified this code from an example for Excel but it doesnt run. Runtime Error. Appreciate any assistance
Sub AdvancedSearchComplete()
Dim rsts As Outlook.Results
Dim i As Integer
Dim strF As String
Dim strS As String
strS = "Tasks"
StrName = InputBox("Search String?")
strF = InStr(LCase("urn:schemas:tasks:subject"), StrName)
Set sch = Application.AdvancedSearch(strS, strF, , "Search1")
End Sub

You need to specify a valid scope and search criteria. The scope of the search is the folder path of a folder, not a folder name. It is recommended that the folder path is enclosed within single quotes. Otherwise, the search might not return correct results if the folder path contains special characters including Unicode characters. To specify multiple folder paths, enclose each folder path in single quotes and separate the single quoted folder paths with a comma.
The Filter parameter can be any valid DASL query. For additional information on DASL queries, see Filtering Items.
Note, you can use the Chr Function to represent any character in the search criteria.
Sub TestSearchForMultipleFolders()
Dim Scope As String
Dim Filter As String
Dim MySearch As Outlook.Search
Dim MyTable As Outlook.Table
Dim nextRow As Outlook.Row
m_SearchComplete = False
'Establish scope for multiple folders
Scope = "'" & Application.Session.GetDefaultFolder( _
olFolderInbox).FolderPath _
& "','" & Application.Session.GetDefaultFolder( _
olFolderSentMail).FolderPath & "'"
'Establish filter
If Application.Session.DefaultStore.IsInstantSearchEnabled Then
Filter = Chr(34) & "urn:schemas:httpmail:subject" _
& Chr(34) & " ci_phrasematch 'Office'"
Else
Filter = Chr(34) & "urn:schemas:httpmail:subject" _
& Chr(34) & " like '%Office%'"
End If
Set MySearch = Application.AdvancedSearch(Scope, Filter, True, "MySearch")
While m_SearchComplete <> True
DoEvents
Wend
Set MyTable = MySearch.GetTable
Do Until MyTable.EndOfTable
Set nextRow = MyTable.GetNextRow()
Debug.Print nextRow("Subject")
Loop
End Sub
Also you may find the Advanced search in Outlook programmatically: C#, VB.NET article helpful.

Ok, this is what I got to work.
When starting the macro:
It Asks user to enter string
Performs and advance search and search for string in subject (including special characters like #cris)
Creates search folder to display search results
In case it helps anybody else. I don't know how to create an output like when doing a manual search. But this works for me.
Sub AdvSearchForStr()
On Error GoTo Err_SearchFolderForSender
Dim strFrom As String
Dim strTo As String
Dim strSearch As String
strSearch = InputBox("Enter String to AdvSearch", "Advanced Search")
strTo = "Test"
Dim strDASLFilter As String
strDASLFilter = "urn:schemas:httpmail:subject LIKE '%" & strSearch & "%'"
Debug.Print strDASLFilter
Dim strScope As String
strScope = "'Inbox', 'Sent Items', 'Tasks'"
Dim objSearch As Search
Set objSearch = Application.AdvancedSearch(Scope:=strScope, Filter:=strDASLFilter, SearchSubFolders:=True, Tag:="SearchFolder")
'Save the search results to a searchfolder
objSearch.Save (strSearch)
Set objSearch = Nothing
Exit Sub
Err_SearchFolderForSender:
MsgBox "Error # " & Err & " : " & Error(Err)
End Sub

Related

Correct filter for search folder programming in Outlook (AdvancedSearch)

I often need a search for all emails of a specific day. In order not to change the criteria of a search folder every time, I wrote a macro which creates a suitable search folder after asking for a date and displaying this folder.
Works fine, but whereas the search folder created the manual way within Outlook only lists the mails of this day, the programmed version also displays appointments of calendars of colleagues who shared their calendars with me - appointments and meetings which don't relate to me at all but were sent on that specific day.
The second thing, but a not important one is, that when displaying the properties of the created folder in Outlook the button for changing the criteria is disabled.
I think I need some additional filter criteria for method AdvancedSearch, but which ones?
At the moment, my code is as follows:
Sub CreateSearchFolderForDate()
'Creates a search folder for a specific date. Only the primarey exchange mailbox will be considered
'(no offline folders, no shared folders).
'The folder is displayed afterwards
Dim oSearch As Search
Dim oSearchFolder As Object
Dim strScope As String
Dim strFilter As String
Dim strDate1 As String
Dim strDate2 As String
Dim strInput As String
varInput = InputBox("Date?", "Create search order for a specific date", Date)
If Not IsDate(varInput) Then
Exit Sub
End If
'Delete existing folder first, otherwise there is a runtime error
Set oSearchFolder = GetSearchFolderByName("Mails for day X")
If Not oSearchFolder Is Nothing Then
oSearchFolder.Delete
End If
strScope = "'" & Application.Session.GetDefaultFolder(olFolderInbox).Parent.FolderPath & "'"
strFilter = "urn:schemas:mailheader:date >= '" & CDate(varInput) & "' AND urn:schemas:mailheader:date < '" & CDate(varInput) + 1 & "'"
Set oSearch = Application.AdvancedSearch(Scope:=strScope, Filter:=strFilter, SearchSubFolders:=True, Tag:="Mails of a specific date")
oSearch.Save ("Mails for day X")
Set oSearchFolder = GetSearchFolderByName("Mails for day X")
oSearchFolder.Display
End Sub
Function GetSearchFolderByName(strSearchFolderName As String) As Object
'Returns the search folder with the display name specified. Only the primarey exchange mailbox will be considered
'(no offline folders, no shared folders).
Dim oStore As Outlook.Store
Dim oFolder As Outlook.folder
On Error Resume Next
Set GetSearchFolderByName = Nothing
For Each oStore In Application.Session.Stores
If oStore.ExchangeStoreType = olPrimaryExchangeMailbox Then
For Each oFolder In oStore.GetSearchFolders
If oFolder.Name = strSearchFolderName Then
Set GetSearchFolderByName = oFolder
Exit Function
End If
Next
End If
Next
End Function
My idea was to use '''urn:schemas:calendar:dtstart'' as additional AND as for "normal" emails that should be empty and messed around a little bit with it - but either it had no effect or it resulted in a list containing only the undesired elements and no "normal" mails at all.
Attempts like IS NULL or IS NOT NULL in the filter caused VBA runtime errors.
In column "folder" the created search folder displays either the folder/subfolder my mails are stored in or for the unwanted entries a certain common part like Doe, Jane common_part and Doe, John common_part. But I didn't find a property which I could use as part of my filter ('''AND property NOT LIKE %common_part%''').
Any hint would be very much appreciated.
Regards,
Bootes
Update 2023-02-08: Before refactoring my problem using the hints and answers by #niton (thanks a lot for the patience) I will start a few more trys with AdvancedSearch, based on an analysis of a manually created search folder using the Redemption-Tool as developed by #Dmitry Streblechenko and described in his posting in How to get a search folder criteria in Outlook. The tool provided the following SQL-Statement:
((NOT (MessageClass LIKE 'IPM.Appointment%')) AND (NOT (MessageClass LIKE 'IPM.Contact%')) AND (NOT (MessageClass LIKE 'IPM.DistList%')) AND
(NOT (MessageClass LIKE 'IPM.Activity%')) AND
(NOT (MessageClass LIKE 'IPM.StickyNote%')) AND (NOT (MessageClass = 'IPM.Task'))
AND (NOT (MessageClass LIKE 'IPM.Task.%'))) AND
((("http://schemas.microsoft.com/mapi/proptag/0x0E090102" <> EF0000004B1E3AD5164F3F459BFE6A913D00E89042800000')
AND ("http://schemas.microsoft.com/mapi/proptag/0x0E090102" <> EF0000004B1E3AD5164F3F459BFE6A913D00E89022800000'))
AND ((SentOn < '2022-12-20') AND (SentOn >= '2022-12-19')))
I tried to translate this into VBA, but had no real success: If I use just the active lines, there is no effect at all, if I add the last two ones (formatted as comments below), I get error "Runtime error -2147023281 (8007064f) - Error during execution of operation" (re-translated from German to English):
strF = "urn:schemas:mailheader:date >= '" & CDate(strInput) & "' AND urn:schemas:mailheader:date < '" & CDate(strInput) + 1 & "' AND "
strF = strF & "NOT (urn:schemas:mailheader:content-class LIKE 'IPM.Appointment%') AND NOT (urn:schemas:mailheader:content-class LIKE 'IPM.Contact%') AND "
strF = strF & "NOT (urn:schemas:mailheader:content-class LIKE 'IPM.DistList%') AND NOT (urn:schemas:mailheader:content-class LIKE 'IPM.Activity%') AND "
strF = strF & "NOT (urn:schemas:mailheader:content-class LIKE 'IPM.StickyNote%') AND NOT (urn:schemas:mailheader:content-class = 'IPM.Task') AND "
strF = strF & "NOT (urn:schemas:mailheader:content-class LIKE 'IPM.Task.%')" ' AND "
'strF = strF & Chr(34) & "http://schemas.microsoft.com/mapi/proptag/0x0E090102" & Chr(34) & " <> 'EF0000004B1E3AD5164F3F459BFE6A913D00E89042800000'" ' AND "
'strF = strF & "(" & Chr(34) & "http://schemas.microsoft.com/mapi/proptag/0x0E090102" & Chr(34) & " <> 'EF0000004B1E3AD5164F3F459BFE6A913D00E89022800000')) AND "
The second approach could be the folder of the item as the unwanted ones are listed in column "In folder" with the folder name containing the a common part that is not in the folder name of the wanted items.
You can limit the search to the inbox.
strScope = "'" & Application.Session.GetDefaultFolder(olFolderInbox).folderPath & "'"
Advanced search is less capable than say .Restrict.
Delete items in Outlook by 'Type' or 'Message Class'
set restrictedItems = olSearchOlFolder.items.Restrict(" #SQL=""http://schemas.microsoft.com/mapi/proptag/0x001A001F"" LIKE 'IPM.Schedule.Meeting.%' ")
how to apply filter only on outlook messages using vba
oFilter2 = "[MessageClass] = 'IPM.Note'"
This is a theoretical implementation of "urn:schemas:mailheader:content-class", that may be applicable, from https://learn.microsoft.com/en-us/previous-versions/office/developer/exchange-server-2007/aa579702(v=exchg.80)
Private Sub AdvSearch_URN_Test()
Dim strSearch As String
Dim strDASLFilter As String
Dim strScope As String
Dim objSearch As Search
Dim strDASLFilter_option As String
Dim fldrNm As String
strScope = "'" & Session.GetDefaultFolder(olFolderInbox).Parent.folderPath & "'"
Debug.Print strScope
' https://learn.microsoft.com/en-us/previous-versions/office/developer/exchange-server-2007/aa579702(v=exchg.80)
' **** most options do nothing ****
' displayto & fromemail are functional
' search by displayto
strSearch = "to display name"
strDASLFilter_option = "displayto"
' These fail
'strDASLFilter_option = "sender" 'search by Sender
'strDASLFilter_option = "sendername" 'search by senderName
'strDASLFilter_option = "senderemail" 'search by SenderEmail
' search by content-class
' *** This fails ***
strSearch = "IPM.Note"
strDASLFilter_option = "content-class"
strDASLFilter = "urn:schemas:httpmail:" & strDASLFilter_option & " LIKE '%" & strSearch & "%'"
Debug.Print strDASLFilter
Set objSearch = AdvancedSearch(Scope:=strScope, filter:=strDASLFilter, SearchSubFolders:=True, Tag:="SearchFolder")
'Save the search results to a searchfolder
fldrNm = strDASLFilter_option & " " & strSearch
Debug.Print fldrNm
objSearch.Save fldrNm
Debug.Print fldrNm & " saved."
End Sub

More efficient way to write command prompts in VBA?

My macro for Word highlights specific words from a specified list for each document in a folder. At the end of the macro, I would like to append the names of each of these files to include "_Highlight" using the command line. I am not too familiar with using the Command Prompt in VBA, so my code ended up being messy.
I am trying to replicate the following command prompt in VBA.
for %a in (“C:\path\*.docx*”) do ren “%~a” “%~Na_Highlight%~Xa”
For the actual file path, I select a folder in FileDialog and store it in a variable to be used in the command prompt, strShellFldr. I am having some trouble concatenating all pieces of the code, especially with special characters, spaces, and quotation literals.
Here is what I tried:
The code below runs just fine, however it seems quite cumbersome. Is there a more efficient way to write this?
Shell.Run "cmd.exe /c" & "for %a in" & Chr(32) & "(" & Chr(34) & strShellFldr & Chr(34) & ")" & Chr(32) & "do ren" & Chr(32) & Chr(34) & "%~a" & Chr(34) & Chr(32) & Chr(34) & "%~Na_Hilight%~Xa" & Chr(34)
Is there a native VBA function that allows you to append a file name maybe?
Thank you for your help and my apologies for posting some wretched code on here.
This piece of VBA code can loop through a list of files in a given folder as input, and add "_Highlight" at the end of the name, just before the file extension:
example:
MyFile.txt --> MyFile_Hightlight.txt
Public Sub RenameFiles(Folder As String)
Dim oFSO As Scripting.FileSystemObject
Dim oFolder As Scripting.Folder
Dim oFile As Scripting.File
Dim ext As String
Dim Name As String
On Error GoTo ERROR_TRAP
Set oFSO = New Scripting.FileSystemObject
Set oFolder = oFSO.GetFolder(Folder)
For Each oFile In oFolder.Files
ext = Split(oFile.Name, ".")(UBound(Split(oFile.Name, ".")))
Name = Left$(oFile.Path, Len(oFile.Path) - Len(ext) - 1)
oFSO.MoveFile Name & "." & ext, Name & "_Highlight" & "." & ext
Next oFile
Set oFSO = Nothing
Set oFolder = Nothing
Set oFile = Nothing
Exit Sub
ERROR_TRAP:
Debug.Print "ERROR : RenameFiles (" & oFolder.Name & ")"
End Sub
Do not forget to add Microsoft Scripting Runtime reference first in your VB Editor.

Print email attachment

I came across this code, which prints email.
I am trying to print attachments.
This as well should be limited to email sent by senttoprint#test.com for example OR if they have specific subject like WEB ORDER #2345.
Sub PrintEmail()
Dim objItem As Object
Dim objMail As Outlook.MailItem
Dim objWordApp As Word.Application
Dim strTempFolder As String
Dim strMailDocument As String
Dim objMailDocument As Word.Document
Dim strPrinter As String
Select Case Application.ActiveWindow.Class
Case olInspector
Set objItem = ActiveInspector.CurrentItem
Case olExplorer
Set objItem = ActiveExplorer.Selection.Item(1)
End Select
If TypeOf objItem Is MailItem Then
Set objMail = objItem
Set objWordApp = CreateObject("Word.Application")
strTempFolder = CStr(Environ("USERPROFILE")) & "\AppData\Local\Temp"
strMailDocument = strTempFolder & "\" & Format(Now, "yyyymmddssnn") & ".doc"
objMail.SaveAs strMailDocument, olDoc
Set objMailDocument = objWordApp.Documents.Open(strMailDocument)
objWordApp.Visible = True
objMailDocument.Activate
strPrinter = objWordApp.ActivePrinter
'Change to the name of specific printer
objWordApp.ActivePrinter = "Specific Printer"
objWordApp.PrintOut Range:=wdPrintAllDocument, Item:=wdPrintDocumentContent
objWordApp.ActivePrinter = strPrinter
objMailDocument.Close False
objWordApp.Quit
Kill strMailDocument
End If
End Sub
It seems you need to find items from a folder that corresponds to your conditions and should be printed. Use the Find/FindNext or Restrict methods of the Items class. The Restrict method is an alternative to using the Find method or FindNext method to iterate over specific items within a collection. The Find or FindNext methods are faster than filtering if there are a small number of items. The Restrict method is significantly faster if there is a large number of items in the collection, especially if only a few items in a large collection are expected to be found.
But if you need to find items from multiple folders I'd recommend using the AdvancedSearch method instead:
Public m_SearchComplete As Boolean
Private Sub Application_AdvancedSearchComplete(ByVal SearchObject As Search)
If SearchObject.Tag = "MySearch" Then
m_SearchComplete = True
End If
End Sub
Sub TestSearchForMultipleFolders()
Dim Scope As String
Dim Filter As String
Dim MySearch As Outlook.Search
Dim MyTable As Outlook.Table
Dim nextRow As Outlook.Row
m_SearchComplete = False
'Establish scope for multiple folders
Scope = "'" & Application.Session.GetDefaultFolder( _
olFolderInbox).FolderPath _
& "','" & Application.Session.GetDefaultFolder( _
olFolderSentMail).FolderPath & "'"
'Establish filter
If Application.Session.DefaultStore.IsInstantSearchEnabled Then
Filter = Chr(34) & "urn:schemas:httpmail:subject" _
& Chr(34) & " ci_phrasematch 'Office'"
Else
Filter = Chr(34) & "urn:schemas:httpmail:subject" _
& Chr(34) & " like '%Office%'"
End If
Set MySearch = Application.AdvancedSearch( _
Scope, Filter, True, "MySearch")
While m_SearchComplete <> True
DoEvents
Wend
Set MyTable = MySearch.GetTable
Do Until MyTable.EndOfTable
Set nextRow = MyTable.GetNextRow()
Debug.Print nextRow("Subject")
Loop
End Sub

MS Access - VBA: Sending Email Using Email Addresses in Tables

Using MS Access VBA. Setup is as follows:
tblUsers contains UserID, UserName, UserSecurityLevel, UserEmail
tblStewards contains AreaID, AreaName, Stewards where Stewards is set to be a Combo Box from a Lookup Query "SELECT tblUsers.ID, tblUsers.UserName FROM tblUsers" and I allow multiple values (e.g., each area has multiple stewards); the Stewards field has a data type of short text
frmStewardRequest has Record Source tblStewards and is designed for a user to request that the area stewards add a new item; it contains cmbAreaName, txtStewards which autopopulates based on cmbAreaName with Control Source Stewards, some open text fields for supplying the requested item, and a btnSubmitRequest
for btnSubmitRequest, I have an On Click event that generates an email to the area stewards using this VBA code:
Dim strEmailTo As String
Dim strTxtBody As String
strEmailTo = DLookup("[UserEmail]", "tblUsers", "ID = " & Me.txtSteward)
strTxtBody = "I need a new item in " & Me.cmbAreaName & "..."
DoCmd.SendObject , , acFormatTXT, strEmailTo, , , "New Item Request", strTxtBody, False
There is a problem with getting the email addresses for the area stewards: it doesn't seem this is a string. How can I get the email addresses so this will send properly? (Less important question, is there a way to prevent the pop-up box to Accept the risk of sending this email?)
This is how I do it.
Option Compare Database
Option Explicit
' This database and all the code therein is © 1999-2002 Arvin Meyer arvinm#datastrat.com
' You are free to use this code and this database in an application
' as long as you do not publish it without the author's permission.
' Additionally, you are required to include this copyright notice in the application.
Private Sub Form_Open(Cancel As Integer)
On Error GoTo Err_OF
Dim db As Database
Dim i As Integer
Dim contr As Container
Dim strRptList As String
Dim strRptName As String
Dim Length As Integer
Set db = CurrentDb()
Set contr = db.Containers("Reports")
strRptList = ""
For i = 0 To contr.Documents.Count - 1
strRptName = contr.Documents(i).name
If strRptList <> "" Then strRptList = strRptList & "; "
Length = Len(strRptName)
strRptList = strRptList & strRptName
Next i
Me!lstRpt.RowSource = strRptList
Exit_OF:
Exit Sub
Err_OF:
MsgBox Err & " " & Error, , "Report Open"
Resume Exit_OF
End Sub
Private Sub cmdEmail_Click()
On Error GoTo Err_cmdEmail_Click
Dim strDocName As String
Dim strEmail As String
Dim strMailSubject As String
Dim strMsg As String
strDocName = Me.lstRpt
strEmail = Me.txtSelected & vbNullString
strMailSubject = Me.txtMailSubject & vbNullString
strMsg = Me.txtMsg & vbNullString & vbCrLf & vbCrLf & "Your Name" & _
vbCrLf & "MailTo:youremail#nowhere.com"
DoCmd.SendObject objecttype:=acSendReport, _
ObjectName:=strDocName, outputformat:=acFormatHTML, _
To:=strEmail, Subject:=strMailSubject, MessageText:=strMsg
Exit_cmdEmail_Click:
Exit Sub
Err_cmdEmail_Click:
MsgBox Err.Description
Resume Exit_cmdEmail_Click
End Sub
Private Sub Label15_Click()
Dim hplMail As String
hplMail = "#MailTo:email_senate#datastrat.com#"
Application.FollowHyperlink HyperlinkPart(hplMail, acAddress)
End Sub
Private Sub lstRpt_Click()
Me.cmdEmail.Enabled = True
End Sub
Private Sub lstMailTo_Click()
Dim varItem As Variant
Dim strList As String
With Me!lstMailTo
If .MultiSelect = 0 Then
Me!txtSelected = .Value
Else
For Each varItem In .ItemsSelected
strList = strList & .Column(0, varItem) & ";"
Next varItem
strList = Left$(strList, Len(strList) - 1)
Me!txtSelected = strList
End If
End With
End Sub
Table tblStewards Combo Box lookup query SELECT tblUsers.ID, tblUsers.UserName FROM tblUsers needs to be fixed since there is no ID but UserID
Have used the Split function to check for multiple Steward values and then get their email id using Dlookup
I prefer using MultiValued fields especially when lookup list is not huge (nothing wrong to use).
Dim strStewards As Variant
Dim i As Long
Dim strEmailTo As String
Dim strTxtBody As String
strStewards = Split(Me.txtSteward, ",")
For i = LBound(strStewards) To UBound(strStewards)
strEmailTo = strEmailTo & ";" & Nz(DLookup("[UserEmail]", "tblUsers", "UserID=" & strStewards(i)), "")
Next
strTxtBody = "I need a new item in " & Me.cmbAreaName & "..."
DoCmd.SendObject , , acFormatTXT, strEmailTo, , , "New Item Request", strTxtBody, False

Apply Filter to Search Button in MS Access VBA

I'm having trouble getting this code to work. I have a blank form with a simple multi-select list box (GroupList) and a button underneath it (cmdSearch). I'm trying to put code into the button to pull select names from GroupList and display Group Affiliation names (field: [Group Affiliations] from table Group_Affiliations.
Private Sub cmdSearch_Click()
Dim varItem As Variant
Dim strSearch As String
Dim Task As String
For Each varItem In Me!GroupList.ItemsSelected
strSearch = strSearch & "," & Me!GroupList.ItemData(varItem)
Next varItem
MsgBox (strSearch)
If Len(strSearch) = 0 Then
Task = "select * from Group_Affiliations"
Else
strSearch = Right(strSearch, Len(strSearch) - 1)
Task = "select * from Group_Affiliations where ([Group Affiliations] in (" & strSearch & "))"
End If
DoCmd.ApplyFilter Task
End Sub
Please help. I think I'm close but it wants me to set a parameter and then I receive the error:
Error code 2501
I think you will likely get the results you want using the following code:
'Set strSearch to empty string
strSearch = ""
'Loop through as you did applying proper single quotes between items
For Each varItem In Me!GroupList.ItemsSelected
strSearch = strSearch & "'" & Me!GroupList.ItemData(varItem) & "',"
Next varItem
'MsgBox (strSearch) 'commented out as I'm sure this is for your testing
'checking if blank (as you did)
If Len(strSearch) = 0 Then
Task = "select * from Group_Affiliations"
'removing end comma and writing SQL statement
Else
strSearch = Left(strSearch, Len(strSearch) - 1)
Task = "select * from Group_Affiliations where ([Group Affiliations] in (" & strSearch & "))"
End If
DoCmd.ApplyFilter Task
If you inspect Task, you will see that the elements of the IN(... part are not quoted. As they are strings (both in VB and for the database, a text field), you must quote the components:
strSearch = strSearch & "'" & Me!GroupList.ItemData(varItem) & "',"
This worked. Thanks billyhoes and everyone! I did show the msgbox because, in this case, I do need viewers to see what they're searching.
Private Sub cmdSearch_Click()
strSearch = ""
For Each varItem In Me!GroupList.ItemsSelected
strSearch = strSearch & "'" & Me!GroupList.ItemData(varItem) & "',"
Next varItem
MsgBox (strSearch)
If Len(strSearch) = 0 Then
Task = "select * from Group_Affiliations"
Else
strSearch = Left(strSearch, Len(strSearch) - 1)
Task = "select * from Group_Affiliations where ([Group Affiliations] in (" & strSearch & "))"
End If
DoCmd.ApplyFilter Task
End Sub