Ty Anderson

Outlook forms: How to create a custom Outlook form using VBA

Because it is composed of different windows, panes, and form regions, the Outlook UI presents a complex UI model to the developer. Despite these options, a common customization request is for custom forms to display the various Outlook items. Today, we’ll take a look at Outlook forms and how you can customize them.

 

What are Outlook forms?

Outlook forms the UI elements used to collect and display item information in Outlook. By items, I mean Outlook “data” types:

  • Mail
  • Appointments
  • Contacts
  • Tasks
  • Notes
  • Posts
  • Etc.

Each of these have their own, built-in (or standard) form. Built-in forms handle greater than 82% of all user needs (approximately… based on my own, non-scientific analysis).

For 15% of the remaining needs, you can create custom forms that display data and process logic according to your needs. The other 3%? Nothing can be done.

Built-in forms vs. custom Outlook forms

Built-in forms are the forms Outlook provides out-of-the-box. They include standard behaviors and are the forms you already know as a user of Outlook.

Custom forms are forms created by you or another developer that:

  1. Modifies or extends the functionality of a built-in form
  2. Is a brand-spanking new creation developed from scratch

The typical scenario for a custom form is to modify and extend a built-in form.

How to create a custom Outlook form

Outlook provides a tool called the Outlook form designer. In this example, I’ll show you how to use a built-in form as the starting point for a custom form. I’ll assume you have Outlook open already. Just follow these steps and we’ll knock this out together:

  1. Right click the Outlook ribbon and select Customize the Ribbon. Click OK.
  2. Click the Developer ribbon tab. In the Custom Form button group, click the Design a Form button. In the Design Form dialog, select the Contact form and click Open to open the form in the Outlook Form Designer.
  3. We’ll add a new page to the standard Contact form. Click the tab labeled (P.2).
  4. In the Form
    Designer
    ribbon, find the Tools group and click the Control Toolbox.
  5. Add the following controls to the form (use the Property Sheet to change properties):
    1. Label
    2. TextBox
    3. Button
  6. In the Tools group click the Field Chooser button. Now in the Field Chooser, find the Notes field and add to the new page (P.2). Your Outlook custom form should look like this (or close to it).

Outlook custom form

  1. Last step. Click Publish in the form designer ribbon. In the Publish Form dialog box, select Personal Forms Library. Enter My Contact Form as the Display Name and MyContactForm as the Form name. Click Publish. Close the form designer. Click No and do not save your changes.

To utilize the form, you need to navigate to the Contacts (or People) folder, access the Developer tab, and click the Choose Form button. From here, you can select the My Contact Form to create a new contact.

How to enumerate/access user forms

You can enumerate and access an Outlook form using Collaborative Data Objects (CDO). The following is VBA that uses CDO 1.21 to enumerate all forms in a specified Outlook folder.

Sub ListForms(fld As Outlook.MAPIFolder)
    'From http://www.outlookcode.com/codedetail.aspx?id=1683
    Dim strList As String
    ' requires reference to Collaboration Data Objects library
    '   (CDO 1.21)
    Dim cdoSession As MAPI.Session
    Dim cdoFolder As MAPI.folder
    Dim cdoFilter As MAPI.MessageFilter
    Dim cdoMessages As MAPI.Messages
    Dim cdoMessage As MAPI.Message
    Const CdoPR_Form_Name = &H6800001E
    On Error Resume Next
 
    Set cdoSession = CreateObject("MAPI.Session")
    cdoSession.Logon "", "", False, False
 
    Set cdoFolder = cdoSession.GetFolder(fld.EntryID, fld.storeID)
    Set cdoMessages = cdoFolder.HiddenMessages
    For Each cdoMessage In cdoMessages
        If cdoMessage.Type = _
          "IPM.Microsoft.FolderDesign.FormsDescription" Then
            strList = strList & vbCrLf & _
              cdoMessage.Fields(CdoPR_Form_Name).Value
        End If
    Next
    If Len(strList) > 0 Then
        strList = Mid(strList, 2)
    Else
        strList = "No forms found in folder"
    End If
    MsgBox strList, vbInformation, "Forms in " & fld.Name & " folder"
 
    cdoSession.Logoff
    Set cdoSession = Nothing
    Set cdoFolder = Nothing
    Set cdoMessage = Nothing
    Set cdoMessages = Nothing
End Sub

How to remove custom items

Once again, we’ll need to utilize CDO to handle this task. The trick is that personal forms are stored with a message class value of “IPM.Microsoft.FolderDesign.FormsDescription”. So, let’s find items with this message class and delete them.

Public Sub DeleteForms
  'From microsoft.public.outlook.program_vba (Ken Slovak)
  'https://groups.google.com/forum/?hl=en&fromgroups=
  '#!topic/microsoft.public.outlook.program_vba/NWjL2UpcNJ8

  Dim oSession As MAPI.Session
  Dim oInbox As MAPI.Folder
  Dim oRoot As MAPI.Folder
  Dim oStore As MAPI.InfoStore
  Dim oViews As MAPI.Folder
  Dim oMessage As MAPI.Message
  Dim oFolders As MAPI.Folders
  Dim oMessages As MAPI.Messages
  Dim sMessageClass As String
  Set oSession = CreateObject("MAPI.Session")
  oSession.Logon "", "", False, False
  Set oInbox = oSession.Inbox
  Set oStore = oSession.GetInfoStore(oInbox.StoreID)
  Set oRoot = oStore.RootFolder
  Set oFolders = oRoot.Folders
  'for Outlook 2003 use "IPM_Common_Views" instead
  Set oView = oFolders.Item("Common Views")
  Set oMessages = oView.HiddenMessages
  For Each oMessage In oMessages
    If oMessage.Type = "IPM.Microsoft.FolderDesign.FormsDescription" Them
        sMessageClass = oMessage.Fields(&H6800001E)
        If sMessageClass = "IPM.Note.xxx" Then
        oMessage.Delete
        Exit For
    End If
  Next
  oSession.Logoff
 'now set all objects = Nothing
End Sub

Useful events to work with Outlook forms

In a custom Outlook form, you program against the form object and its events. You don’t have access to the Outlook application and events.

Click

When you use a custom form, Outlook only supports the Click event for controls. This is a natural choice for buttons but not optimal for controls like the combo box. You write the code by inserting it into a form’s VBScript editor. You need to have the Outlook form open in the Form Designer and click the View Code button found in the Form group of the Developer tab.

Here is the natural choice for a code sample of button control.

Sub CommandButton1_Click()
  msgbox "Hello World"
End Sub

PropertyChange

If you want to respond to changes of Outlook properties, you can do it. You need to create a method that responds to the form item’s PropertyChange event. The event receives the name of the Outlook property that changed. You must check the value to determine if it is the property you want and respond accordingly.

Sub Item_PropertyChange(ByVal Name)
  Select Case Name
    Case "Subject"
      ' your code goes here, for example:
      MsgBox Item.Subject, , "The subject is ..."
    Case "Categories"
      ' more code goes here, for example:
      MsgBox Item.Categories, , "The categories are..."
      ' continue with Case statements for other properties
      ' whose values you want to monitor
  End Select
End Sub

CustomPropertyChange

Outlook lets you create custom properties to support your custom data needs. You can respond to changes to custom properties in the same manner as you do with standard properties. The only difference is the two properties reside in separate collections. Thus, they have separate change events.

Sub Item_CustomPropertyChange(ByVal Name)
  Select Case Name
    Case "MyProp1"
      strMyProp1 = Item.UserProperties("MyProp1")
      Select Case strMyProp1
        Case "Text1"
          ' code to react to the MyProp1
          ' string property having a value of "Text1"
        Case "Text2"
          ' code to react to the MyProp1
          ' string property having a value of "Text2"
        Case Else
          ' code to handle other values of MyProp1
        End Select
    Case "MyProp2"
      ' code to handle a change in MyProp2 goes here

      ' continue with Case statements for other properties
      ' whose values you want to monitor
    End Select
End Sub

You can learn more about each these events here.

How to access form items (edit boxes, combos, memos, etc.)

Within the form’s VBScript, you can access form pages and controls by name.

Text Boxes

Text Boxes reside within a form page’s Controls collection. First, reference the page, then call the controls section and pass the text box name.

Sub CommandButton1_Click()
  Set Page = Item.GetInspector.ModifiedFormPages
  Set Cntl = oPage("P.2").Controls("TextBox1")
  Cntl.SetFocus   
  Cntl.Text = "Hello World!"
  Set Cntl = Nothing
  Set Page = Nothing
End Sub

Combo Boxes

Combo Boxes are accessed in the same manner as text boxes. But, maybe the best place to access them is the Form’s Open event (ah, and you thought maybe I forgot about this useful event!)

Sub Item_Open()
 Set FormPage = Item.GetInspector.ModifiedFormPages("P.2")
 Set Control = FormPage.Controls("ListBox1")
 Control.PossibleValues = " Bono;Edge;Adam;Larry"
End Sub

Memo Field

The memo field of an Outlook item is known as the Body to code. You can access it and change its value easily.

Sub CommandButton1_Click()
  Item.Body = Item.Body & vbCrLf & "I was clicked at ::" & now()
End Sub

Outlook forms – Available for solutions but…

I didn’t editorialize as I went along because I think it is obvious. Outlook forms exist and have been around for a long time. But, easier and more powerful options exist. I recommend using this for quick and dirty solutions limited to a small set of users. Maybe 1, or zero.

 

Outlook 2013 add-in development in Visual Studio 2012 for beginners

You may also be interested in:

4 Comments

  • http://0.gravatar.com/avatar/c401f036bd9a1771fcb5b8fe564a4460?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G CC says:

    So frustrated, please help. Attachments re-arrange themselves EVERY TIME I assign an Outlook task to someone else!! We have found the custom form to be very useful and every new task we create in Outlook is via the custom form. We assign this task back and forth between employees every day. Each “task” is a client file with information typed and attachments inserted into different parts below relevant lines of text (could be PDFs, JPGs, emails, or other docs). WELL, ever since switching to Outlook 2013, when we go to “Assign Task,” it immediately drops any and all attachments (which, again, we have pasted purposefully in specific parts of the task) TO A ROW ALL TOGETHER AT THE BOTTOM OF THE PAGE!! Why is this happening?!? THIS DID NOT HAPPEN IN OUTLOOK 2010 using the same custom form! We are on an exchange server. Please help if you have any suggestions, thanks!

  • http://0.gravatar.com/avatar/c68f03884efb33fd95bcfbd9f1078c07?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G Ty Anderson says:

    Hi CC

    I really don’t know why this occurs in Outlook 2013. If it is possible to see your code, maybe I can offer some assistance.

    Ty

  • http://0.gravatar.com/avatar/ad516503a11cd5ca435acc9bb6523536?s=32 RM says:

    Hi,
    I am trying to send bunch of meeting invite to different users from Public Calendar. Everything is working fine but I have a problem of reminder. I want all the recipients will get reminder but not me (meaning organizer). I have tried different code but nothing is working.
    Enclosed please find my code:
    ————————————————————-
    Sub Macro1()

    ‘ Macro1 Macro

    Dim olApp As Outlook.Application
    Dim olNS As Namespace
    Dim olFolder As MAPIFolder
    Dim olApt As AppointmentItem
    Dim objAttendees As Outlook.Recipients

    Set olApp = CreateObject(“Outlook.Application”)
    Set olNS = olApp.GetNamespace(“MAPI”)
    Set olFolder = olNS.GetDefaultFolder(olFolderCalendar).Folders(“WDS”)

    Dim imyMailItem As Outlook.MailItem
    Dim myOlApp As Outlook.Application
    Set myOlApp = Outlook.Application

    Dim r As Long

    ‘ late bound constants
    Const olAppointmentItem = 1
    ‘Const olBusy = 2
    Const olMeeting = 1

    ‘ Create the Outlook session
    ‘Set myoutlook = CreateObject(“Outlook.Application”)

    ‘ Start at row 2
    r = 2

    Do Until Trim$(Cells(r, 1).Value) = “”

    ‘ Create the AppointmentItem
    ‘Set myapt = myoutlook.CreateItem(olAppointmentItem)
    Set olApt = olApp.CreateItem(olAppointmentItem)
    Set olApt = olApt.Move(olFolder)
    Set imyMailItem = olApp.CreateItem(olMailItem)
    ‘ Set the appointment properties

    With olApt

    .Subject = Cells(r, 1).Value
    .Start = Cells(r, 2).Value
    .End = Cells(r, 4).Value
    .RequiredAttendees = Cells(r, 9).Value
    Set objAttendees = .Recipients
    .MeetingStatus = olMeeting
    ‘ not necessary if recipients are email addresses
    ‘ myapt.Recipients.ResolveAll
    .AllDayEvent = Cells(r, 7).Value

    For x = 1 To objAttendees.Count
    If objAttendees(x) .Organizer Then

    If Cells(r, 6).Value 0 Then
    .ReminderSet = True
    .ReminderMinutesBeforeStart = Cells(r, 6).Value
    Else
    .ReminderSet = False
    End If
    Else
    .ReminderSet = False
    End If
    Next
    ‘End If

    .Body = Cells(r, 1).Value
    .Save
    r = r + 1
    On Error Resume Next
    .Send
    .Save
    End With

    Loop

    End Sub

    ————————————————————–

    Any suggestion or help will be greatly appreciated.
    Thanks in advance!!

  • http://0.gravatar.com/avatar/c68f03884efb33fd95bcfbd9f1078c07?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G Ty Anderson says:

    What if, after sending the appointment to other users, you edit your copy of the appointment?
    You can remove the reminder and save it.

    Maybe something like this:


    On Error Resume Next

    .Send
    .ReminderSet = False

    .Save
    End With

    ??

Post a comment

Have any questions? Ask us right now!