How to concentrate Input into Url for href - vba

I am very new to VBA (and programming in general) and I am looking to create a simple macro that will call for a few inputs from the user and flash-fill an email. The inputs being ID numbers that I want to concatenate to the end of a static URL and link in the body of the email. Skipping a bit for brevity, here's what I have so far:
`Sub Release()
Dim objMsg As MailItem
Set objMsg = Application.CreateItem(olMailItem)
Dim Obj1 As String
Obj1 = InputBox("Enter ID1", "Input Number Only"
If Obj1 <> ""
With objMsg
strEmailBody = "Hello ___" & "Object #" & Obj1 & "<a href=""http://....id=""&Obj1>(link)</a>"
.HTMLBody = strEmailBody`
Everything seems to perform well except the link, which is the static URL and does not concatenate in the input number as I'd like it to. Please advise!
I tried changing around the quotation marks and changing the whole URL to a variable, but I cannot seem to get more than just the string as typed to appear in the hyperlink.

It seems you just need to concatenate strings in VBA correctly:
strEmailBody = "Hello ___" & "Object #" & Obj1 & "(link)"
Note, you can use the Chr function for inserting double quotes where necessary.

strEmailBody = "Hello ___" & "Object #" & Obj1 & _
"(link)"
or a little simpler using single quotes for the href attribute value:
strEmailBody = "Hello ___" & "Object #" & Obj1 & _
"<a href='http://....id=" & Obj1 & "'>(link)</a>"

Related

Advanced Search of Messages for Multiple Words in Outlook 2016

I would like to do an Advanced Search of messages for multiple words without having to do each one manually/separately.
If I could record a macro in Outlook 2016, which as I understand it I cannot do, these are the commands I would do:
Record Macro
Click on Search Current Mailbox.
Click on Search Tools.
Click Advanced Search.
For the drop-down after “In:” choose “frequently-used text fields”.
Type into “Search for the word(s):” the text to find.
(Entering multiple words there means to find one string of all the words, not to find each word individually.)
Click Find Now.
Stop recording macro.
Edit the VBA code produced to:
Specify the rest of the words to find
Specify case-insensitive
Then do the Find Now.
Then I would like to display them all.
Preferably sorted, but not necessary if will make it more complicated code.
From piecing together code found online, I have the code below.
Subject is the only value I can use debug.print on. The others give errors:
"Run-time error '5': Invalid procedure call or argument".
I only know how to search on Subject.
I do not know how to display the list of what I have found (not in Immediate window).
' Test VBA for Multiple-Word Search in Outlook - 3
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 folder
Scope = "'" & Application.Session.GetDefaultFolder(olFolderInbox).FolderPath & "'"
Debug.Print Scope
'Establish filter
If Application.Session.DefaultStore.IsInstantSearchEnabled Then
Filter = Chr(34) & "urn:schemas:httpmail:subject" & Chr(34) & " ci_phrasematch 'Office'"
Debug.Print Filter
Filter = Chr(34) & "urn:schemas:httpmail:subject" & Chr(34) & " ci_phrasematch 'rent'" _
& " OR ""urn:schemas:httpmail:subject" & Chr(34) & " ci_phrasematch 'breaking'"
'(subject:invoice OR body:invoice) AND hasattachments:yes NOT from:Amazon
Else
Filter = Chr(34) & "urn:schemas:httpmail:subject" & Chr(34) & " like '%Office%'"
End If
Debug.Print Filter
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("SentOnBehalfOf")
' Debug.Print nextRow("From")
' Debug.Print nextRow("ReceivedTime")
Debug.Print nextRow("Subject")
Loop
End Sub
Outlook doesn't provide a macro recorder like Word or Excel. You need to create a VBA macro manually in Outlook.
The Advanced search in Outlook programmatically: C#, VB.NET article explains how to use the AdvancedSearch method in Outlook.
The Outlook Object Model also provides the AdvancedSearchStopped event. The signatures of the AdvancedSearchStopped and AdvanvedSearchComplete event handlers are the same. The AdvancedSearchStopped event is triggered when the Stop method is called on the Search object to cancel searching. However, the AdvancedSearchComplete is called afterwards anyway.
Admittedly, the Search class allows you to save the results of searching in a search folder (actually, it doesn’t contain any items, only references to items from the scope folders). You just need to call the Save method on the Search object in the AdvanvedSearchComplete event handler.
For example, in VBA you can define the AdvanvedSearchComplete event handler in the following way:
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

Error on trying to get textbox text in Word VBA

I have some code in VBA on Microsoft Word, I just want to save some text as a file in a specific folder.
Here's the relevant part of code (not including the rest as its all spaghetti code that doesn't even reference TextBox3 at all):
Dim foldername As String
foldername = TextBox3.Text
Dim Fileout As Object
Set Fileout = fso.CreateTextFile("C:\Users\JaneDoe\Desktop\" & foldername & "\" & myValue & ".html", True, True)
Fileout.Write finaltext
Fileout.Close
This code ONLY doesn't work when it references TextBox3.Text, if I change that to "testing123" it works perfectly, but I need to use the text from TextBox3
The error I'm getting is:
Run-time error '424':
Object required
And it references this line:
foldername = TextBox3.Text
Any and all help is greatly appreciated, do keep in mind I'm a bit of a noob to VBA though so yeah :)

VBA HTML Object Library is not parsing Outlook MailItem HTMLBody

I am trying to merge mails by extracting the last message in the a conversation thread. I want to keep the formatting intact so i am trying to get the last message along with the html. I am referencing Microsoft HTML Object Library like this
Dim mi As MailItem
Set mi = ActiveExplorer.Selection.Item(1)
Dim bhtml As HTMLBody
Set bhtml = mi.HTMLBody
This is giving a type mismatch error.
MailItem.HTMLBody property returns a string, not an HTLBody object.
I used Regex to extract the last message from the string returned by oMailitem.body property. Here is the pattern (.*(?=(From:.*\nSent:.*\nTo:))) it is a +ve look ahead i used the first item in match collection and set it in a match object than i extracted the last message like with left function like this lastmessage = Left(oMailItem.body,oMatch.firstindex)
Than i wrapped it up in html like this
Dim vResult, vLine, sResult As String
vResult = Split(lastMessage, vbCrLf)
For Each vLine In vResult
sResult = sResult & "</p><p>" & CStr(vLine)
Next
styledLastMessage = "<p>" & sResult & "</p>"
And finally appended to the mail i wanted to merge it with like this
Dim miBody() As String
miBody = Split(oMailItem.HTMLBody, "<div class=WordSection1>")
miBody(1) = "<p>" & styledLastMessage & "</p>" & "-------" & vbCrLf & miBody(1)
oMailItem.HTMLBody = Join(miBody, "<div class=WordSection1>")
Note: After <div class=WordSection1> the first message begins.

Using the .Restrict method in Outlook VBA to filter on single recipient email address

I have code in Access that gets all emails in the user's Inbox that are sent by an individual email address. This code (simplified, below) works fine:
Dim outItems as Outlook.Items
Dim strEMAddress as string
Dim outFolder as Outlook.MAPIFolder
Set outFolder = outNS.GetDefaultFolder(olFolderInbox)
Set outItems = outFolder.Items
str="my#email.com"
Set outItems = outItems.Restrict("[SenderEmailAddress] = " & "'" & strEMAddress & "'")
I am looking for something that will do likewise on the SentMails folder, restricting the items to those sent to a specific email address.
I know this is complicated by the fact that .Recipients is a collection (as items can/do have more than one recipient). I am hoping there is a way to return a list of items that contain the email address I am looking for in any of the sent fields (To/CC/bcc - but happy with just To if this is easier).
I have searched online and found .To is no good (is not the email address) and I can't get pseudo code such as this work:
Set outItems = outItems.Restrict("[Recipients] = " & "'" & strEMAddress & "'")
You can use the DASL query as the filter string in your items.restrict method.
For example to find all mails i sent to Ali Raza i use the following
str_fltr = "#SQL=""urn:schemas:httpmail:displayto"" ci_phrasematch '%Ali Raza%'"
The good thing about the above DASL query is that it returns matches with multiple recepients whether if you use the jet syntax for searching resultx will only contain items with one recipient. Jet syntax is the one that you are currently using. You should use the [To] property rather than [Recipients]
Here https://msdn.microsoft.com/en-us/library/cc513841%28v=office.12%29.aspx#SearchingOutlookData_Overview is good place where you can learn almost everything about searching in outlook.
Here http://www.msoffice.us/Outlook/PDF/%28Outlook%202010%29%20Common%20DASL%20Property%20Tags.pdf is a list of common DASL tags which will come in handy if you get a grip on DASL syntax.
For multiple [TO/CC/BCC] filter example would be...
Option Explicit
Public Sub Example()
Dim olNs As Outlook.NameSpace
Dim Folder As Outlook.MAPIFolder
Dim Items As Outlook.Items
Dim Filter As String
Dim Msg As String
Dim i As Long
Set olNs = Application.GetNamespace("MAPI")
Set Folder = olNs.GetDefaultFolder(olFolderSentMail)
Filter = "#SQL=" & "urn:schemas:httpmail:displayto" & _
" Like '%John Doe%' Or " & _
"urn:schemas:httpmail:displaycc" & _
" Like '%John Doe%' Or " & _
"urn:schemas:httpmail:displaybcc" & _
" Like '%John Doe%'"
Set Items = Folder.Items.Restrict(Filter)
Msg = Items.Count & " Items in " & Folder.Name & " Folder"
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
now remember if the display name is John.Doe#Email.com then filter should be %John.Doe#Email.com% else use %John Doe%
If using Redemption is an option (I am its author), you can use RDOFolder.Items.Restrict - unlike Outlook Object Model, it does expand To/CC/BCC queries into recipient sub restrictions on PR_DISPLAY_NAME and PR_EMAIL_ADDRESS properties on each recipient (RES_SUBRESTRICTION / PR_MESSAGE_RECIPIENTS / RES_OR / PR_DISPLAY_NAME | PR_EMAIL_ADDRESS).
set Session = CreateObject("Redemption.RDOSession")
Session.MAPIOBJECT = Application.Session.MAPIOBJECT
set Folder = Session.GetFolderFromID(Application.ActiveExplorer.CurrentFolder.EntryID)
set restrItems = Folder.Items.Restrict(" TO = 'user#domain.demo' ")
You can also specify Recipients property in the SQL query - it will be matched against recipients of all types (to/cc/bb):
set restrItems = Folder.Items.Restrict(" Recipients = 'user#domain.demo' ")

Outlook VBA Script on incoming messages

I have tried to make a script to pick up emails as they come in, reformat them and then forward on to the email in the body but I cannot work out how to read the email body. I currently have:
Sub Confirmation()
myMessage = "You recently made a request on the IT website, the details of your
request can be seen below:" & vbCr & vbCr & "Thank you, " & vbCr & "IT Support"
Dim itmOld As MailItem, itmNew As MailItem
Set itmOld = ActiveInspector.CurrentItem
Set itmNew = itmOld.Forward
itmNew.Body = myMessage & vbCr & vbCr & itmOld.Body
itmNew.Subject = "IT Web Request Confirmation"
itmNew.Display
Set itmOld = Nothing
Set itmNew = Nothing
End Sub
This opens the email adds some text to it and forwards it on.
I would like the script to open the email, read an email address from the body, use that as the to field and reformat the existing email to a nicer format.
This is the HTML from the email:
<html><body><br /><br /><table><tr><td><b>Fullname: </b></td><td>Alex Carter</td></tr><tr><td><b>OPS_Access: </b></td><td>Yes</td></tr><tr><td><b>Email_Account_Required: </b></td><td>Yes</td></tr><tr><td><b>Office_Email_Required: </b></td><td>Yes</td></tr><tr><td><b>Website_Access_Required: </b></td><td>Yes</td></tr><tr><td><b>Web_Access_Level: </b></td><td>Staff</td></tr><tr><td><b>Forum_Access_Required: </b></td><td>Yes</td></tr><tr><td><b>Date_Account_Required: </b></td><td>03/08/2013</td></tr><tr><td><b>Requested_By: </b></td><td>Alex Carter</td></tr><tr><td><b>Requestee_Email: </b></td><td>alex.carter#cars.co.uk</td></tr><tr><td><b>Office_Requesting: </b></td><td>Swindon</td></tr></table></body></html>
This shows that the email to go into the to field is in the 10th row of the table but I am not too sure how to go about selecting this from the body?
How would I go about reading the body, reformatting it and then selecting the requestee email and using it as the to field?
Thanks in advance!
This should help you get started (modifying your code), though you'll have to be more specific with regard to what formatting improvements you would like to see...:
Sub Confirmation()
myMessage = "You recently made a request on the IT website, the details of your request can be seen below:" & vbCr & vbCr & "Thank you, " & vbCr & "IT Support"
Dim sAddress As String ' Well need this to store the address
Dim itmOld As MailItem, itmNew As MailItem
Set itmOld = ActiveInspector.CurrentItem
Set itmNew = itmOld.Forward
sAddress = GetAddressFromMessage(itmOld) ' This is our new function
If Len(sAddress) > 0 Then
itmNew.To = sAddress ' If our new function found a value apply it to the To: field.
'!!! This should be checked as a valid address before continuing !!!
End If
itmNew.Body = myMessage & vbCr & vbCr & itmOld.Body
itmNew.Subject = "IT Web Request Confirmation"
itmNew.Display
Set itmOld = Nothing
Set itmNew = Nothing
End Sub
Private Function GetAddressFromMessage(msg As MailItem) As String
' Grabs the email from the standard HTML form described in the SO question.
Dim lStart As Long
Dim lStop As Long
Dim sItemBody As String
Const sSearchStart As String = "Requestee_Email: </b></td><td>" ' We will look for these tags to determine where the address can be found.
Const sSearchStop As String = "</td>"
sItemBody = msg.HTMLBody ' Read the body of the message as HTML to retain TAG info.
lStart = InStr(sItemBody, sSearchStart) + Len(sSearchStart)
If lStart > 0 Then ' Make sure we found the first TAG.
lStop = InStr(lStart, sItemBody, sSearchStop)
End If
GetAddressFromMessage = vbNullString
If lStop > 0 And lStart > 0 Then ' Make sure we really did find a valid field.
GetAddressFromMessage = Mid(sItemBody, lStart, lStop - lStart)
End If
End Function