How To Create Outlook Appointments from a LightSwitch Application

How To Create Outlook Appointments from a LightSwitch Application

Rate This
  • Comments 16

Last post I showed how to create email in a couple different ways, one of them being from the LightSwitch UI on the client side that used COM to automate Outlook to create an email. If you missed it here it is:

How To Send HTML Email from a LightSwitch Application

This generated some questions about how to automate Outlook to do other things like add appointments to someone’s calendar. So because of this interest, I’ve decided to continue my series on Office automation from LightSwitch :-). This time I’ll show how to create a client-side helper class that creates and sends appointments through Outlook.

Creating the Outlook Helper Class

We need a helper class on the client so we can call if from a button on our screen. You do this by selecting the “File View” on the Solution Explorer, right-click on the Client project and select Add –> New Class. I named the class “OutlookAppointmentHelper” for this example.

image

This helper class uses COM automation, a feature of Silverlight 4 and higher. So first we need to check if we’re running out-of-browser on a Windows machine by checking the AutomationFactory.IsAvailable property. Next we need to get a reference to Outlook, opening the application if it’s not already open. The rest of the code just creates the appointment and sends it. In the code below, you could also comment out the call to Send and instead call Display to allow the user to modify the appointment first. NOTE: The key piece of code that enables the sending of the appointment to the toAddress is to set the MeetingStatus property to 1 (olMeeting), otherwise the appointment will just stay on the user’s calendar and wont be sent to the recipient.

Imports System.Runtime.InteropServices.Automation

Public Class OutlookAppointmentHelper
    Const olAppointmentItem As Integer = 1
    Const olMeeting As Integer = 1

    Shared Function CreateOutlookAppointment(ByVal toAddress As String,
                                             ByVal subject As String,
                                             ByVal body As String,
                                             ByVal location As String,
                                             ByVal startDateTime As Date,
                                             ByVal endDateTime As Date) As Boolean
        Dim result = False
        Try
            Dim outlook As Object = Nothing

            If AutomationFactory.IsAvailable Then
                Try
                    'Get the reference to the open Outlook App
                    outlook = AutomationFactory.GetObject("Outlook.Application")

                Catch ex As Exception 'If Outlook isn't open, then an error will be thrown.
                    ' Try to open the application
                    outlook = AutomationFactory.CreateObject("Outlook.Application")
                End Try

                If outlook IsNot Nothing Then
                    'Create the Appointment

                    ' Outlook object model (OM) reference: 
                    ' http://msdn.microsoft.com/en-us/library/ff870566.aspx
                    ' Appointment Item members:
                    ' http://msdn.microsoft.com/en-us/library/ff869026.aspx

                    Dim appt = outlook.CreateItem(olAppointmentItem)
                    With appt
                        .Body = body
                        .Subject = subject
                        .Start = startDateTime
                        .End = endDateTime
                        .Location = location
                        .MeetingStatus = olMeeting

                        .Recipients.Add(toAddress)

                        .Save()
                        '.Display()
                        .Send()
                        result = True
                    End With
                End If
            End If

        Catch ex As Exception
            Throw New InvalidOperationException("Failed to create Appointment.", ex)
        End Try
        Return result
    End Function
End Class

Also note that if you want to add multiple recipients to the appointment you could pass in an array or List(Of String) and loop through that calling .Recipients.Add for each one:

Shared Function CreateOutlookAppointment(ByVal toAddress As List(Of String), ...rest of code
.
.
.
Dim appt = outlook.CreateItem(olAppointmentItem) With appt .Body = body .Subject = subject .Start = startDateTime .End = endDateTime
.Location = location
.MeetingStatus = olMeeting
For Each addr In toAddress .Recipients.Add(addr) Next .Save() '.Display() .Send() End With

You can also add required and optional attendees by setting appropriate properties. Take a look at the object model for the Appointment item for more details.

Calling Code from a Button on a Screen

Here’s how you add a command button to a screen.  In the Execute method for the command button is where we add the code to create the appointment. I also want to have the button disabled if AutomationFactory.IsAvailable is False and you check that in the CanExecute method. Here I’m working with an Appointment entity in my data model but the data to feed the appointment can come from anywhere. So here’s the code in my screen:

Private Sub CreateOutlookAppt_CanExecute(ByRef result As Boolean)
    result = System.Runtime.InteropServices.Automation.AutomationFactory.IsAvailable
End Sub
Private Sub CreateOutlookAppt_Execute()
    ' Schedule the appointment via Outlook
    With Me.Appointment
        If .Customer.Email <> "" Then
            If OutlookAppointmentHelper.CreateOutlookAppointment(.Customer.Email,
                                                                 .Subject,
                                                                 .Notes,
                                                                 .Location,
                                                                 .StartTime,
                                                                 .EndTime) Then
                Me.ShowMessageBox("Appointment has been sent.")
            End If
        Else
            Me.ShowMessageBox("This customer does not have an email address",
                              "Missing Email Address",
                              MessageBoxOption.Ok)
        End If
    End With
End Sub

Run this and you will see that when the user clicks the button the appointment is sent and it appears on the user’s calendar.

image

Enjoy!

Leave a Comment
  • Please add 3 and 1 and type the answer here:
  • Post
  • Beth I was wondering if you then change the appointment time and/or date in the application will it also send a request to update the existing appointment for the attendees?

    Thanks for all the great work!

  • Hi dcbarker,

    No this code just generates the appointment one-off. Off-hand I'm thinking there's a couple things you could do. For a client-side solution you could search the appointments folder and find it there. But I think I'd opt for a server-side solution instead. For instance you could send the appointment as a VCAL attachment from the server and store it on the appointment entity. That way you tell if the request needed to be updated.

    I'll play with it and post a follow up. Thanks for the idea :-)

    Cheers,

    -Beth

  • Beth, how is the Office automation via COM is going to get affected when end users might have Office 2005 or office 2007 or office 2010 on their machine? I've never done any Office automation Via COM, but this is always a concern how the code is going to behave if they have older Office or not a full blown office installed.

    Great series as always!

    ..Ben

  • Hi Ben,

    Yes Try..Catch is your friend when working with COM via late binding :-). However this code should work fine in Outlook 2003-2010. The OM for Outlook 2003 is here: msdn.microsoft.com/.../aa210899(office.11).aspx

    HTH,

    -B

  • not sure why, but when AutomationFactory.GetObject("Outlook.Application")

    is called I'll get HRESULT: 0x80004004 (E_ABORT)) in Outlook 2010.

  • Hi Falk,

    I'm not sure either I'm using 2010 as well. You should just be getting a "Failed to create instance" type of error if Outlook isn't open. Are you getting the same message on CreateObject?

    You can also try the experts in the Outlook developer forum:

    social.msdn.microsoft.com/.../threads

    Cheers,

    -B

  • Thx for the reply. It might be some sort of security issue. I’m using Win7-64, Outlook 2010 and pst-file is password protected.

    When GetObject("Outlook.Application") is called in LS then I’ll get „No object was found registered for the specified progID.”. When CreateObject("Outlook.Application") is called from the catch block, then sometimes I’ll get  „No object was found registered for the specified progID.” or I’ll get 0x80004004.

    Vbscript and powershell are working.

    From an OOB SL4 application CreateObject("Outlook.Application") works when Outlook is closed, but not when open.

    GetObject("Outlook.Application") always throws the above mentioned error.

    I'll try to do some further testing.

  • Sry, for high jacking this thread, but I progressed by one step.

    The 0x80004004 error was the result of an empty recipient address.

    GetObject("Outlook.Application") always throws the progID error when called from LS.

    CreateObject("Outlook.Application") works when outlook is closed, but will not save the appointment, although save works without error.

    When I add “outlook.Session.GetDefaultFolder(6).Display()” before creating the appointment, then the appointment gets saved. If I do it thereafter, then nothing is saved.

    If I let the Outlook session from LS open, then GetObject("Outlook.Application") still throws an error. CreateObject("Outlook.Application") works but creates an new session.

    Basically it seems as LS has to create the outlook session and you have to display it.

  • I guess I've solved the problem.

    LS has to create the Outlook session and the session should be kept as a reference so that it can be reused.

    I’ve added the following shared function to the OutlookAppointmentHelper class:

    Public Class OutlookAppointmentHelper

       Const olAppointmentItem As Integer = 1

       Const olMeeting As Integer = 1

       Shared outlook As Object

       Shared IsCreated As Boolean = False

       Shared Function InitializeOutlook() As Boolean

           If AutomationFactory.IsAvailable Then

               Try

                   ' If GetObject throws an exception, then Outlook is

                   ' either not running or is not available.

                   If IsCreated Then                    

                       outlook = AutomationFactory.GetObject("Outlook.Application")

                       Return True                    

                   Else

                       outlook = AutomationFactory.CreateObject("Outlook.Application")

                       outlook.Session.GetDefaultFolder(6).Display() ' 6 = Inbox

                       IsCreated = True

                       Return True

                   End If

               Catch

                   If Not IsCreated Then

                       Throw New InvalidOperationException("Outlook not available. If you have an open Outlook session then close it first.")

                   Else

                       IsCreated = False

                       Throw New InvalidOperationException("Outlook not available. You might have closed your Outlook session. Try again.")

                   End If

               End Try

           Else

               Throw New InvalidOperationException("Automation not available")

           End If

    And when creating the appointment in CreateOutlookAppointment I’ll use first

    If InitializeOutlook() Then

    instead of

    Try

     'Get the reference to the open Outlook App

     outlook = AutomationFactory.GetObject("Outlook.Application")

    Catch ex As Exception 'If Outlook isn't open, then an error will be thrown.

               ' Try to open the application

      outlook = AutomationFactory.CreateObject("Outlook.Application")

    End Try

    If outlook IsNot Nothing Then

  • @Falk Hmmm.... I'll have to play with that and test it to make sure that Outlook is closed properly when the LS app closes.

    I'm working on a server-side solution that I should have posted tomorrow morning that may work better for you. Although it doesn't allow user interaction, it will create ICS meeting requests that most email clients can read.

  • @Beth

    sounds good.

    The above mentioned solution is more a workaround and there is one further issue. When LS created the outlook session and I close and restart the client, then a new outlook session gets created. So all this sums up as follows.

    Outlook open (not created by LS client)

    Createobject and getobject will through an error.

    No Outlook session

    Createobject creates a session  and getobject will get it.

    Outlook open (created with LS client)

    Createobject creates a new session  and getobject will get it.

  • @Falk -- I have been unable to simulate your problem and I'm on Win7 64 as well so it just seems odd. You definitely need to make sure you call GetObject first otherwise another call to CreateObject would create another instance.

    I'll be posting that server-side solution tommorrow morning, I almost have it done.

    Cheers,

    -B

  • Here's the follow up post that shows how to send the appointment as an iCalander attachment from server side business rules:

    blogs.msdn.com/.../how-to-send-automated-appointments-from-a-lightswitch-application.aspx

  • thanks massi........

  • Thank you Beth,

    it works fine!

Page 1 of 2 (16 items) 12