Today's macro let's you say things like "Send email to Rob", or "Send email to Rob Chambers", and as long as I'm a contact in your Outlook Contacts, you can send me mail! It also allows you to say "Send email to Rob Chambers about That cool outlook macro", it'll open up Outlook, create a new email, put me as the recipient, and it'll set the subject to "That cool outlook macro". Neat, eh?

Today's macro was inspired by Brad, over in the ms-speech Yahoo! Group, who asked me if WSR Macros could dynamically create rule content last week. Well, Brad, yes it can! Here's an example.

The most interesting part of today's macro, is the ruleScript element that allows you to define a rule programmatically. The key to this script is that it will find content to add to the rule by hooking up to Outlook's object model (using Create Object("Outlook.Application")), and then call the Rule.Items.AddItem method for each email address it finds.

That ruleScript looks like this:

  <ruleScript name="OutlookContact" propname="EmailAddr" language="VBScript">
    <![CDATA[
      Call AddOutlookContacts

      Sub AddOutlookContacts

        REM Debug.DebugBreak
        Debug.Trace chr(13) & "Adding OutlookContacts..." & chr(13)

        Const olFolderContacts = 10
        Const olMSG = 3

        Set objOutlook = CreateObject("Outlook.Application")
        Set objNamespace = objOutlook.GetNamespace("MAPI")

        Set colContacts = objNamespace.GetDefaultFolder(olFolderContacts).Items

        For Each objContact in colContacts
          If TypeName(objContact) = "ContactItem" Then
            If objContact.FullName <> "" Then
              If objContact.Email1Address <> "" Then Rule.Items.AddItem objContact.FullName, objContact.Email1Address, True
              If objContact.Email2Address <> "" Then Rule.Items.AddItem objContact.FullName, objContact.Email2Address, True
              If objContact.Email3Address <> "" Then Rule.Items.AddItem objContact.FullName, objContact.Email3Address, True
            End If
          End If
        Next
        For Each objRuleItem in Rule.Items
          Debug.Trace objRuleItem.Phrase & " (" & objRuleItem.Property & ")" & chr(13)
        Next
        Debug.Trace "--" & chr(13) & "Added " & Rule.Items.Count & " items!" & chr(13)

      End Sub     
    ]]>
  </ruleScript>

There are a couple other interesting things in today's macro:

  1. I used a Debug.DebugBreak method (currently commented out above), to allow me to debug the macro interactively in Microsoft Visual Studio Express. This is a handy way of single stepping over each and every line in the code. If you have VS installed, when the macro hits that line (if you uncomment it), you'll be asked what debugger to use to debug the macro's script. You pick VS, and then you have F10 single-step control over the macro as it executes. You can do fun things like inspect variables, change flow, etc... All really cool stuff that developers using Microsoft Development tools have grown accustomed to doing.
  2. I also used Debug.Trace to output to VS what's going on in the macro, so even if I'm not single step debugging it, I can see what contacts got added.
  3. I used the disambiguate tag to allow the user to disambiguate what email address to use if it's ambiguous. So, for example, if I have 3 people named Rob in my contacts, it'll allow me to pick which one I wanted to send email to. In fact, it'll even show me the email addresses in parenthesis after the person's full name.

Here's the entire macro:

<speechMacros>

  <command priority="2">
    <listenFor>send email to [OutlookContact]</listenFor>
    <listenFor>send email to [OutlookContact] about [subject...]</listenFor>
    <disambiguate title="Send email to whom?" prompt="Who would you like to send email to?" timeout="30" propname="OutlookContact"/>
    <script language="VBScript">
      <![CDATA[
        Set outlookApp = CreateObject("Outlook.Application")

        olMailItem = 0
        Set newMessage = outlookApp.CreateItem(olMailItem)

        newMessage.Recipients.Add("{[OutlookContact.EmailAddr]}")
        newMessage.Subject = "{[subject...]}"
        newMessage.Display
      ]]>
    </script>
  </command>

  <command priority="1">
    <listenFor>send email</listenFor>
    <listenFor>send email to *</listenFor>
    <listenFor>send email to * about [subject...]</listenFor>
    <script language="VBScript">
      <![CDATA[
        Set contacts = CommandSet.RuleGenerators("OutlookContact")
        For Each item in contacts.Rule.Items
          ChooseFromList.Items.AddItem item.Phrase, item.Property, True
        Next
        ChooseFromList.Items.Sort
        chose = ChooseFromList.Choose("Send email to whom?", "Who would you like to send email to?")
        If chose > 0 Then
          Set outlookApp = CreateObject("Outlook.Application")

          olMailItem = 0
          Set newMessage = outlookApp.CreateItem(olMailItem)
          newMessage.Recipients.Add(ChooseFromList.Items(chose).Property)
          newMessage.Subject = "{[subject...]}"
          newMessage.Display
        End If   
      ]]>
    </script>
  </command>
  <command>
    <listenFor>Refresh ?Outlook Email Contacts</listenFor>
    <listenFor>Refresh Outlook ?Email Contacts</listenFor>
    <script language="VBScript">
      <![CDATA[
        Set contacts = CommandSet.RuleGenerators("OutlookContact")
        contacts.Rule.Items.RemoveAll
        contacts.Script.AddOutlookContacts
        contacts.Rule.Commit
      ]]>
    </script>
  </command>

  <ruleScript name="OutlookContact" propname="EmailAddr" language="VBScript">
    <![CDATA[
      Call AddOutlookContacts

      Sub AddOutlookContacts

        REM Debug.DebugBreak
        Debug.Trace chr(13) & "Adding OutlookContacts..." & chr(13)

        Const olFolderContacts = 10
        Const olMSG = 3

        Set objOutlook = CreateObject("Outlook.Application")
        Set objNamespace = objOutlook.GetNamespace("MAPI")

        Set colContacts = objNamespace.GetDefaultFolder(olFolderContacts).Items

        For Each objContact in colContacts
          If TypeName(objContact) = "ContactItem" Then
            If objContact.FullName <> "" Then
              If objContact.Email1Address <> "" Then Rule.Items.AddItem objContact.FullName, objContact.Email1Address, True
              If objContact.Email2Address <> "" Then Rule.Items.AddItem objContact.FullName, objContact.Email2Address, True
              If objContact.Email3Address <> "" Then Rule.Items.AddItem objContact.FullName, objContact.Email3Address, True
            End If
          End If
        Next
        For Each objRuleItem in Rule.Items
          Debug.Trace objRuleItem.Phrase & " (" & objRuleItem.Property & ")" & chr(13)
        Next
        Debug.Trace "--" & chr(13) & "Added " & Rule.Items.Count & " items!" & chr(13)

      End Sub     
    ]]>
  </ruleScript>

</speechMacros>