I met Nathan Elson for the first time yesterday when I responded to one of his tweets. In his tweet Nathan asked if some twitterverse resident knew of a way to modify Outlook and “create a toolbar button that assigns a category”. He explained that he would rather add or remove categories from his emails by clicking a single toolbar button rather than having to click Outlook’s Categories button and select from the resulting pull down menu. Two clicks versus one unless of course the category Nathan wants doesn’t appear on the pull down list. When that happens he’ll have to click All Categories from the pull down menu and then choose a category from the Color Categories dialog-box. That drives the click count to three and introduces the possibility of scrolling the list in order to find the category he’s looking for. While I might debate the logic of building a new toolbar to save a single click the toolbar could actually save two clicks and possibly prevent the need to scroll too. The discussion wouldn’t be complete without mentioning that Nathan could eliminate all clicks and the need for a toolbar by assigning a shortcut key to each category. Of course he’d have to remember the shortcut key and Outlook allows a limited set of shortcut keys, enough for just 11 categories. If he has more than that, then he’s out of luck.
Fortunately for Nathan it’s very simple to add a toolbar to Outlook. Toolbars can be added manually or via a script. In Nathan’s case the solution is to use a script. Why a script? There are a couple of reasons. First, Outlook doesn’t have a built-in toolbar button for adding/removing categories. It does offer the same Categories toolbar button that appears on Outlook’s built-in menu which is exactly what Nathan wants to move away from. Second, even if it were possible to add a toolbar button for a specific category, then Nathan would have to edit the toolbar each time he adds/removes a category since toolbars do not have an autoupdate capability. The ideal solution is one that would detect when categories have been added/deleted and update the toolbar on its own. Unfortunately that’s not possible because Outlook’s Categories object has no events. A script can’t react to a change if the change isn’t detectable. The script is still a better solution though because Nathan won’t have to add/remove buttons manually. All he’ll have to do is restart Outlook.
At less than 100 lines of code the script for this is surprisingly simple when you consider what it has to do. The script starts by building the toolbar. To do that it creates a toolbar, populates it with a button for each of Nathan’s categories, then displays the toolbar on screen. When Nathan clicks one of the buttons on the toolbar the script checks to see if the category associated with that button is already assigned to the currently selected item. If that category is not assigned to the item, then it adds it. If instead it finds that the category is already assigned, then it removes it. In other words the button is a toggle. The script works with all Outlook item types.
Before I present the code there are a couple of caveats I need to mention.
- This solution only works with Outlook 2007. It will not work with any other version of Outlook. Outlook 2003 and earlier used a completely different approach to categories and is therefore incompatible. Outlook 2010 uses the same categories system as Outlook 2007 but it has eliminated toolbars in favor of the ribbon system used by the other Microsoft Office products. The ribbon is inaccessible by scripts.
- The toolbar buttons this script creates are not color coded to match the color of the category each button is associated with. Toolbar buttons support a picture, a caption, or both. They do not support simply coloring the button.
On to the script. It comes in three parts. The first two are class modules, one to implement the toolbar and the other to implement the buttons that go on the toolbar. The third bit of code gets the process started by creating an instance of the toolbar class each Outlook is launched and destroying it each time Outlook closes.
Toolbar Button Class.
Private WithEvents objButton As Office.CommandBarButton Private strThisCat As String Private Sub Class_Terminate() Set objButton = Nothing End Sub Private Sub objButton_Click(ByVal Ctrl As Office.CommandBarButton, CancelDefault As Boolean) Dim olkItm As Object, arrCats As Variant, varCat As Variant, bolFound As Boolean, intCnt As Integer, strNewCat As String Select Case TypeName(Outlook.Application.ActiveWindow) Case "Explorer" Set olkItm = Outlook.Application.ActiveExplorer.Selection(1) Case "Inspector" Set olkItm = Outlook.Application.ActiveInspector.CurrentItem End Select arrCats = Split(olkItm.Categories, ", ") For Each varCat In arrCats If varCat = strThisCat Then bolFound = True Else strNewCat = strNewCat & ", " & varCat End If Next If Not bolFound Then strNewCat = strNewCat & ", " & strThisCat End If olkItm.Categories = strNewCat olkItm.Save Set olkItm = Nothing End Sub Public Sub Init(ByRef ofcParentBar As Office.CommandBar, ByVal strCatNum As String, strTipText As String) Set objButton = ofcParentBar.Controls.Add(msoControlButton) With objButton .Caption = strCatNum .Style = msoButtonCaption .TooltipText = strTipText End With strThisCat = strTipText End Sub
Instructions. Follow these instructions to add the code to Outlook.
- Start Outlook
- Click Tools > Macro > Visual Basic Editor
- If not already expanded, expand Microsoft Office Outlook Objects
- Right-click on Class Modules, select Insert > Class Module
- In the Properties panel click on Name and enter CatBtn
- Copy the code and paste it into the right-hand pane of Outlook’s VB Editor window
- Click the diskette icon on the toolbar to save the changes
- Close the VB Editor
Toolbar Class.
'--- On the next line change True to False if you do not want the categories sorted ---' Private Const SORT_CATS = True Enum intSortType dicSortKey = 1 dicSortItem = 2 End Enum Private ofcBar As Office.CommandBar Private colBtns As Collection Private Sub Class_Initialize() Set colBtns = New Collection CreateCATBar Outlook.Application.ActiveExplorer End Sub Private Sub Class_Terminate() Set colBtns = Nothing Set ofcBar = Nothing End Sub Private Sub CreateCATBar(olkWindow As Object) Dim objCatBtn As CatBtn, olkCat As Outlook.Category, objDict As Object, intCnt As Integer, arrKeys As Variant, varKey As Variant On Error Resume Next Set ofcBar = Outlook.Application.ActiveExplorer.CommandBars("CAT") On Error GoTo 0 If TypeName(ofcBar) = "Nothing" Then 'Create the toolbar Set ofcBar = olkWindow.CommandBars.Add("CAT", msoBarTop, False, True) 'Create the buttons Set ofcButton = ofcBar.Controls.Add(msoControlButton) With ofcButton .Caption = "CAT" .Enabled = False .Style = msoButtonCaption End With 'Create the category buttons Set objDict = CreateObject("Scripting.Dictionary") For Each olkCat In Outlook.Application.Session.Categories objDict.Add olkCat.Name, olkCat.Name Next If SORT_CATS Then Set objDict = SortDictionary(objDict, dicSortKey) End If arrKeys = objDict.keys intCnt = 1 For Each varKey In arrKeys Set olkCat = Outlook.Application.Session.Categories.Item(varKey) Set objCatBtn = New CatBtn objCatBtn.Init ofcBar, intCnt, olkCat.Name colBtns.Add objCatBtn Set olkCat = Nothing intCnt = intCnt + 1 Next ofcBar.Visible = True End If End Sub Private Function SortDictionary(ByVal objDict, ByVal intSort As intSortType) As Object '--- This function is from the Microsoft KB article: http://support.microsoft.com/kb/246067 ---' ' declare constants Const dictKey = 1 Const dictItem = 2 ' declare our variables Dim strDict() Dim objKey Dim strKey, strItem Dim x, y, z ' get the dictionary count z = objDict.count ' we need more than one item to warrant sorting If z > 1 Then ' create an array to store dictionary information ReDim strDict(z, 2) x = 0 ' populate the string array For Each objKey In objDict strDict(x, dictKey) = CStr(objKey) strDict(x, dictItem) = CStr(objDict(objKey)) x = x + 1 Next ' perform a a shell sort of the string array For x = 0 To (z - 2) For y = x To (z - 1) If StrComp(strDict(x, intSort), strDict(y, intSort), vbTextCompare) > 0 Then strKey = strDict(x, dictKey) strItem = strDict(x, dictItem) strDict(x, dictKey) = strDict(y, dictKey) strDict(x, dictItem) = strDict(y, dictItem) strDict(y, dictKey) = strKey strDict(y, dictItem) = strItem End If Next Next ' erase the contents of the dictionary object objDict.RemoveAll ' repopulate the dictionary with the sorted information For x = 0 To (z - 1) objDict.Add strDict(x, dictKey), strDict(x, dictItem) Next End If Set SortDictionary = objDict End Function
Instructions. Follow these instructions to add the code to Outlook.
- Start Outlook
- Click Tools > Macro > Visual Basic Editor
- If not already expanded, expand Microsoft Office Outlook Objects
- Right-click on Class Modules, select Insert> Class Module
- In the Properties panel click on Name and enter CatBar
- Copy the code and paste it into the right-hand pane of Outlook’s VB Editor window
- Click the diskette icon on the toolbar to save the changes
- Close the VB Editor
Startup/Shutdown Code.
Dim objCatBar As CatBar Private Sub Application_Quit() Set objCatBar = Nothing End Sub Private Sub Application_Startup() Set objCatBar = New CatBar End Sub
Instructions.
- Start Outlook
- Click Tools > Macro > Visual Basic Editor
- If not already expanded, expand Microsoft Office Outlook Objects and click on ThisOutlookSession
- Copy the code and paste it into the right-hand pane of Outlook’s VB Editor window
- Click the diskette icon on the toolbar to save the changes
- Close the VB Editor
- Click Tools > Trust Center
- Click Macro Security
- Set Macro Security to “Warnings for all macros“
- Click OK
- Close Outlook
- Start Outlook. Outlook will display a dialog-box warning that ThisOutlookSession contains macros and asking if you want to allow them to run. Say yes.
Putting it All Together.
Once Nathan has added this code and restarted Outlook he should see a new toolbar that looks something like this.
Is I noted earlier, toolbar buttons can have a picture, a caption, or both. I’ve used the caption in this solution. The caption on each button is a number representing the button’s position on the toolbar. When Nathan moves the mouse pointer over a button the category associated with that button will appear as a tool tip.
When Nathan wants to add/remove a category to/from an item all he as to do is select the item and click the toolbar button for the desired category.
Enhancements.
Here are two enhancements Nathan may want to consider.
- Colored icons. Nathan could make a set of icons matching Outlook’s category colors. He could then change the button style (line 36 of the Toolbar Button Class code) to use an icon instead of a caption.
- Show Item Categories. Perhaps Nathan would like to see the categories already applied to the currently selected item. To do that he’d have to write code that is triggered each time he selects an item. That code would check the item’s categories and depress the corresponding toolbar button(s).
It’s time to send Nathan a link to this post. I hope he finds the code useful. Here’s hoping that you do too.
Pingback: gtd – the elson way | Nathan R. Elson
David,
Will this be possible to do in Outlook 2010 as well. Is the code the same.
Second question, with regards to subsets of categories, if i name the categories with a prefix like 0-, 1- for the different subsets, can I also make a category button toolbar for each subcategory with a filter in the script to only include categories with the specific prefix.
Regards Dag
Dag,
No, it won’t be possible to use that code in Outlook 2010 and later versions. Microsoft eliminated toolbars in favor of the ribbon beginning with Outlook 2010. Implementing something like this would now require an add-in, a custom form, or a form region, all of which are more complicated and cannot be done with a script alone.
Yes, you could make multiple category toolbars by prefixing the category names with some sort of code.
David,
I found a solution utilizing NEOplus. It allows for easy add categories and have very good functionality.
Thank you for your time.
Dag
ASA Slickline Sales Manager
Located in Jakarta
� HP: +62 811 191729
•: dhenriksen@slb.com
“It is amazing what you can accomplish if you do not care who gets the credit.”
Harry S. Truman
Dag,
Thanks for sharing that with me. Glad you have a solution.
Cheers!
Hi David, I’m new to your blog (fascinating by the way) and found this by a categories google search. Apologies if replies such a long time after the last one are welcome or if this is not on topic enough. I don’t know if I am odd in my use of categories but I’ve been using them for 10 to 15? years (for categorizing emails) and was horrified at the clumsy Outlook 2007 implementation I saw after our recent upgrade.
I find it way quicker to type in a few categories than to select from a list, especially as I probably have hundreds that I have used. I think of them as similar to the way the brain works – they have different ‘strengths’ based on how often you use them. Yes I may type the same category differently sometimes but if that happens they generally appear next to each other in emails grouped by category so I can just correct the category then if I need to. And like the brain I might forget a category and have to find the email by search, but then I remember it.
Sorry about the rant, tell me if it is not appropriate, now to the tech. point.
I added a region to the standard Outlook message from and put a textbox populated with the categories field in it. Now in an open email I can immediately type in all the categories I want to give to the email – Bliss!
The limit is that I have to open the email to do it. I’d like to have the same textbox on a toolbar so I can do it for the selected email(s). Is that possible?
Regards
Dave Easey
Hi, Dave.
No worries on the rant.
That might be possible. What version of Outlook are you using?
Pingback: Quora
Hi David,
Thanks for the tip: this should do what I need. However, I got a compilation error I cannot solve by myself…
“Ambiguous name detected: Application_Quit”
Same problem with “Application_Startup”
If I rename these functions, the toolbar doesn’t show up.
Any help welcome!
Vince
Hi, Vince.
The compilation error is saying that procedures named Application_Startup and Application_Quit already exist. You need to combine them into a single Application_Startup and Application_Quit.
Yep, of course… Woke up too early! Now it works fine, thanks!
Another question: Is it possible to replace the button names (1, 2, 3, etc) by the actual category names? I don’t mind about the colors, but names are really key. Can we also limit the buttons to a sublist of categories?
Many thx in advance.
Vince
Yes, both are possible. I used numbers instead of category names for two reasons. In comparison to a number a category name is long which means uneven button sizes and fewer buttons. The latter is a serious issue for anyone who has a moderately long list of categories. Limiting the buttons to a sublist of categories will either require that the category names follow a pattern or you’ll have to actually put the names in the code. The former is more preferable, but either one will work.
David, thanks for sharing your expertise. I had to make the quote and ambersand replacement but it worked like a charm. Might inspire me to learn how to add the icon code.
Hi there, nice peace of code, however I question. How the clicking on buttons is implemented? I never found a .OnClick property of button used and it also does not work for me. Anything I overlooked?
Thanks a lot,
otherwise very usefull feature, wanted to make my own like this.
Rado
Hi, Rado.
Thanks, I’m glad you like it. The action performed when a button is clicked is implemented in the Toolbar Button Class. The click is handled by the objButton_Click subroutine.
I’m not clear on what you mean when you say “… it also does not work from me.” Do you mean the code isn’t working at all? If so, then what version of Outlook are you using and do you have macros enabled?
Would really like to get this working, and your effort is much appreciated. First, I got an undefined variable error (Set ofcButton =)because my editor is set to Option Explicit. I disabled that and got another compile error “Method or data member not found” at objCatBtn.Init in CatBtn. That’s as far as I’m going to get without your help. Am I missing a reference?
Hi, Dave.
Open the VB editor in Outlook and add a reference to “Microsoft Office 12.0 Object Library”. If you aren’t on Office 2007 (which is 12.0), then use the version number for your version (e.g. for Office 2010 it’ll be 14.0). Try the code again once you’ve added the reference.
Excellent work. Much needed toolbar and clear, readable code.
If you could get icons on those it would be absolutely perfect. I’m going to play with this myself to see if I can get that done.
Anyway this is great.
Thanks, Matan! Icons are possible. I didn’t use them for a couple of reasons. First, they’d make each button bigger, so you’d wouldn’t be able to get as many of them on a toolbar. That’s fine if you have a small number of categories, but it’d be a problem if you have a lot of categories. Second, you’re pretty limited in your selection of images to go on the buttons. Outlook’s built-in mechanism for button faces uses a small, predefined set. You can expand on that by switching to a larger predefined set, but there’s no built-in mechanism for adding your own. There might be ways to overcome that, but, frankly, I’ve never explored that to see what’s possible.
Hello David
You gave me some invaluable help earlier this year in sorting the Category toolbar.
Of course now I have an additional question.
The Categories menu option lists the most recent 15 categories used.
Is it possible to create a toolbar which just shows those 15?
Many thanks
Steve
Hi, Steve.
I just moved so it’s going to be a few days before I can respond
I love this functionality but it doesn’t work for me either. I get a syntax error when I try to apply a category to an item. The lines below that I’ve marked with *** are RED in the debugger.
Private Sub objButton_Click(ByVal Ctrl As Office.CommandBarButton, CancelDefault As Boolean)
Dim olkItm As Object, arrCats As Variant, varCat As Variant, bolFound As Boolean, intCnt As Integer, strNewCat As String
Select Case TypeName(Outlook.Application.ActiveWindow)
*** Case “Explorer”
Set olkItm = Outlook.Application.ActiveExplorer.Selection(1)
*** Case “Inspector”
Set olkItm = Outlook.Application.ActiveInspector.CurrentItem
End Select
***arrCats = Split(olkItm.Categories, “, “)
For Each varCat In arrCats
If varCat = strThisCat Then
bolFound = True
Else
***strNewCat = strNewCat & “, ” & varCat
End If
Next
If Not bolFound Then
strNewCat = strNewCat & “, ” & strThisCat
End If
olkItm.Categories = strNewCat
olkItm.Save
Set olkItm = Nothing
End Sub
Interesting. When I pasted the lines into this post they display without the jumble. When I copy them and paste them back into outlook the first two lines now work. There are still errors however with these two:
strNewCat = strNewCat & “, ” & varCat
strNewCat = strNewCat & “, ” & strThisCat
I figured it out. This is AWESOME! Thank you!
You’re welcome, Alan. Glad you find it useful.
Mr. Lee…
I have tried to start this script but it does not seem to work….
I wish I could send you a screen shot of what I am looking at…
Under modules i see nothing..
Only under class modules I have Class 1, 2 and 3….
Wish I knew what I was doing wrong….
This script is very important to me.
marshall at 73 dot com
I’ve sent you an email. Send me a screen shot and I’ll see if I can figure out what’s going wrong.
Great article. Thanks for posting it. This approach to selecting categories is exaclty what I am looking for. The only problem is our company is using 2003… I hope to use it if/when we migrate.
Thanks and you’re welcome.
You’re welcome, Steve.
I think so–when I search for two single quotes side by side, I don’t find any. And when I search for the double quotes, I find what looks like double quotes.
It pasted funny earlier–this is literally what it says
Case ampersand quot semi-colon Explorer ampersand quot semi-colon
I put the two exported class files as
getmike.info\CatBtn.cls and CatBar.cls
darned if I can see the problem
The double quote above should have read ampersand quot semicolon.
I’m back to fiddling with this again.
Now, when I press a button, I get an error at
Private Sub objButton_Click(ByVal Ctrl As Office.CommandBarButton, CancelDefault As Boolean)
Dim olkItm As Object, arrCats As Variant, varCat As Variant, bolFound As Boolean, intCnt As Integer, strNewCat As String
Select Case TypeName(Outlook.Application.ActiveWindow)
Case "Explorer"
the last line I pasted in gives the error. I can’t see any problem with it vis a vis what’s above
Hey, Mike.
Have you replaced the instances of " with actual quotes?
This looks & works great.
Is there any way in which I can sort the categories alphabetically before they get assigned to buttons?
Thanks
Hi, Steve.
That’s a great suggestion. I’ve modified the code to give the option of sorting the categories when the bar is created. By default the categories will be sorted. If you don’t want the categories sorted, then change the constant CAT_SORT to False on line #2 of the code for the Toolbar class.
For anyone who had already installed the code, all you need to do is replace the Toolbar class with the revised version (above).
Thanks David
It works great. Much appreciated.
Steve
Pingback: gtd – the elson way « nathan·r·elson
I’m getting an error, otherwise this looks just great. I put a screenshot where you can see it
any help you could provide is appreciated
Hi, Michael.
The problem is the “"” scattered throughout the code. Those are supposed to be double-quotes. The copy and paste screwed up. If you fix them all, then you should be in good shape.
thank you for the great article. i will try it.
You’re welcome! I hope you find it useful.
David,
The two scripts for the toolbar have the same name and throw up an error for the code. Is there a way we should change the code to make it work?
Dave
Hi, David.
Looks like you found a typo that I missed. Step #5 of the instructions for the Toolbar class should read CatBar not CatBtn.
Thanks for pointing that out to me.
Cheers!