Back in the days before email viruses changed the game, the Microsoft Office applications were amazing extensibility platforms. All the way back to wordbasic and the excel macro language, and then certainly with VBA in the core office apps. Now finally after years of maturity with the security features and A/V precauations in place, I thought it would be fun to show an example of how you can still solve little problems and add helper features with this powerful area.
Finding an email address by last name is a bit of a challenge in Outlook. Suppose your last name is Jones and you have 5 brothers stored in various address books in your Outlook configuration. You also are using Exchange so you have a Global Address List (GAL) that has 25 different "Jones" in the list.
You create a new email and type in "Jone" hoping the Outlook will autocomplete from the last time you mailed one of your brothers. No such luck as the autocomplete feature does not trigger on last name.
Next you tab away or hit the check names button, and you get the ANR (Ambiguous Name Resolution) dialog. Unfortanately, since there are many Jones entries in the GAL, and the GAL is the first address list in order of searching, you only see the names from that last. None of your brothers are visible.
At this point you can try to use the Find feature, or manually change the address list context, but you get the point. It is too hard to find the recipient by last name.
Outlook provides enough extensibility through its object model to get to all the entries in the address list. We just need to cook up some UI to accept a search term, present the results, and allow you to insert the found address into a message.
I have attached two example solutions to this post. One is a VBA sample that you would import into Outlook itself and use. This would allow you to provide a button on the inspector ribbon to launch the macro, and make the extended address lookup seem more "integrated" into outlook. I also included a standalone VB.NET project that shows a sample of how to have a separate EXE "always running" that you would use to do the search and mail creation.
Both the samples, do the bare minimum to show a proof of concept of the ideas here, which are to
- Use the object model to access the address lists that are available.
- Loop through "more than one" of them trying to find the search term.
The "search" here is a basic string comparision against the Display Name. That happens to work for a last name search becuase the last name is typically part of the display name. For a real solution, the search code would be smarter and allow for more agresssive or different matching.
Also note, that you have to configure outlook to allow use of the object model.
Basic Code Review
The code in these samples essentially does this:
- Loop through each address list (address book) that is configured in Outlook.
- Loop through each entry (one address) within the address list
- Check to see if the search term matches, and if so, add it to the list.
For Each onelist In mysession.AddressLists
' Only process entries from Contact Folder based address books (and the GAL if really want to)
' Change abfake to abGAL to include GAL in the list but that would be really slow
If onelist.AddressListType = abfake Or onelist.AddressListType = abOutlook Then
' Give a little status on the progress
lblstatus.Caption = "Searching " + onelist.Name
' Setup vars for item progress
itotal = onelist.AddressEntries.Count
i = 1
' Loop through every entry in the address list
For Each oneentry In onelist.AddressEntries
lblstatus.Caption = "Checking entry " + Str(i) + " of " + Str(itotal) + " from " + onelist.Name
' This is the current sum total of the "find". It just matches the passed in string to the
' name property from the address entry. This could be made as complicated as you want by adding
' logic to test agaist other fields, etc
r = InStr(1, oneentry.Name, strstarttext, vbTextCompare)
' r not equal to 0 means you found a match, so add it to the list
If r <> 0 Then
.ColumnCount = 3
.ColumnWidths = "150;150;150"
.List(listresults.ListCount - 1, 0) = oneentry.Name
.List(listresults.ListCount - 1, 1) = oneentry.Address
.List(listresults.ListCount - 1, 2) = onelist.Name
i = i + 1