Developing Web Applications With ® Microsoft Exchange
Tom Rizzo
: thomriz@microsoft.com
Objectives
Understand the tools available for collaborative development Understand the infrastructure requirements for web-based apps Learn how to build collaborative applications using Exchange/Outlook/IIS Demos, Demos, Demos, Code, Code, Code
The three T‟s
Technologies
OWA CDO/COM Components Outlook HTML Form Converter Routing/Workflow Directory Integration
Outlook VID/FrontPage
Tools
Techniques
Demo: Some Web Apps
Job Candidates Helpdesk Calendar of Events News Expense Reporting Project Management Directory Management
Technologies: OWA
Outlook Web Access is your best tool Code examples, best practices Steal portions for your own applications Provides both anonymous and authenticated access
Architecture
Browser Exchange Server
CDO & CDOHTML
Internet Information Server
Active Server Pages
Upload Lang
OWA Scripts
Architecture
Script Directory Structure
exchsrvr\webdata
Global.asa
FRN
USA
JPN
constant.inc
inbox
contacts
calendar
forms ipm
finduser
help
images
lib
report
schedule note contact document post Custom and converted forms
dr ndr ipnnrn ipnrn
Setup/Authentication
Setting up Exchange for your Intranet is easy, depending on your authentication needs Two types of authentication:
Basic:
Clear text authentication Can use SSL for encryption All web browers support it Encrypted
Can use SSL for further encryption Requires IE
NT Challenge/Response:
Setup/Authentication
Depending on authentication, machine configuration varies:
Basic: Exchange Server and IIS can be on separate machines or same machine. NT Challenge/Response: Exchange Server and IIS are required to be on the same machine. Windows 2000 will support separate machines.
You may be wondering why this is necessary. . . . . .
Anonymous Web pages
Web Browser IIS Server NT Server
(separate or same machine)
1
Browser connects to IIS by requesting a web page.
2
IIS automatically is logged on as IUSR_Machin eName account.
3
The IUSR_MachineName account is used to retrieve web page.
Basic Authentication
Web Browser IIS Server NT Server
(separate or same machine)
1
Browser connects to IIS by requesting a web page.
2
IIS automatically is logged on as IUSR_Machin eName account.
3
The NT Account specified is used to retrieve web page.
NTLM Authentication
Web Browser IIS Server NT Server (must
be same machine)
You cannot proxy the authentication
1
Browser connects to IIS by requesting a web page.
2
IIS automatically is logged on as IUSR_Machin eName account.
3
The NT Account specified is used to retrieve web page.
How authentication works
For Basic or NTLM:
IIS is always initially logged in as IUSR_MACHINENAME This account has no permissions to your Exchange Server accounts by default If you do not change this authentication in your application, you will get either a Logon failed error or a FailOneProvider error
Changing permissions
In order for secure access, your application needs to check the server variables to see if the client is authenticated If not, your application needs to send back 401 Unauthorized This will prompt the browser to force authentication For NTLM, no screen appears For Basic, username/password logon appears
From Outlook Web Access
Public Function BAuthenticateUser On Error Resume Next BAuthenticateUser = False
bstrAT = Request.ServerVariables("AUTH_TYPE")
If InStr(1, bstrAuthTypesAccepted, bstrAT, vbTextCompare) < 2 Then Response.Buffer = TRUE Response.Status = ("401 Unauthorized") Response.End Else BAuthenticateUser = True End If End
CDO Object Model
Session Inbox… Outbox… InfoStores RootFolder Messages Attachments Address lists
Object and collection Object only
AddressEntries Fields AddressEntryFilter Fields
MessageFilter
Fields
Fields Recipients Fields
Fields Folders…
CDO Rendering Objects
RenderingApplication ContainerRenderer Formats Format Patterns Pattern Views TableView ObjectRenderer Formats Format Patterns
Pattern
Object and collection Object only
There are two classes of view objects - TableView - CalendarView
Columns
Column
Code Walkthrough
Let‟s a look at the code for all of them!
Outlook HTML Form Conv.
Provides conversion between Outlook Forms and ASP Shipped with SP1/SP2 Works with Netscape and Internet Explorer
Client System Requirements
Outlook 8.03, Outlook 98/2000
Used by the converter to obtain custom fields off the forms Used to access form descriptions
FM20.DLL
Windows 95 or Windows NT Workstation/Server
You do not need to run the converter on the Exchange Server
Server Requirements
IIS 3.0 with ASP 1.0b or IIS 4.0 Outlook Web Access installed Share out the webdata directory under the Exchange directory. Eg. C:\exchsrv\webdata
What‟s Supported?
Forms can be converted from a number of places:
Outlook template files (OFT files) Organizational Forms Registry Folder Forms Registry Personal Forms Registry
Multiple forms can be converted at once
How Do I Find The Form?
Copied to the OWA directory structure
Default directory where Web services files are stored Multilanguage support
Form-specific scripts All Post Forms derive from here When you create a custom message class, the directory hierarchy replicates the structure
IPM.Post.Project
Folder Names
Netscape does not support folders that have spaces in the name
Eg. IPM.Post.While you were out
This will try to create a folder under the IPM/Post directory tree named While you were out The Form Converter automatically converts spaces to %20 so Netscape can access the forms
Architecture Of Conversion
Components
Wizard OFT-HTML Converter Templates Template Processor Installshield setup
Conversion Details
Frmroot.asp
Entry point into the form Includes script and HTML frameset that houses the rest of the components Title.asp - Title page PageN.asp - swapped into frame by title.asp where N is the page # commands.asp - hidden commands
Three Frames
Movement Between Tabs
Data is submitted to command.asp and copied into the cached message object on the IIS server Data is retrieved for the new page from the message object The new page is swapped into the frameset and sent to the browser
Commands.asp
Hidden form Detects custom and built-in field values when pages are submitted to the web server The on_send, on_reply, on_replyall, on_save, on_forward as well as custom action handlers are implemented here
Form.ini
Contains one section called Description Has friendly name of form and whether it is a hidden form OWA dynamically generates list of custom forms based on form.ini
[Description] DisplayName=Project Management Application Hidden=0
What‟s Supported?
Certain types of forms are supported
IPM.Note - Mail Message IPM.Post - Post Form IPM.Contact - Contact Form
Task and Appointment forms are not supported
Work around to get UI converted, copy controls to a supported form type
Forms must have their own message class cannot be named default Outlook forms e.g., IPM.Contact
To-Do‟s
To-do‟s are generated if the form encounters certain conditions To-do‟s are displayed at the end of the conversion and also saved with the form in its OWA folder
What‟s supported?
Most Outlook controls are supported:
Label, textbox, combobox , listbox, checkbox, optionbutton, frame, commandbutton, multipage, and image control Some controls are limited in conversion due to HTML limitations Image controls are converted to gifs
Initial values, required fields, datatype validation, separate read and compose forms, hidden controls and pages are all supported
Advanced Services
Routing/Workflow Directory integration and management Full-text Indexing and Search
Look at my session from Sunday
Routing/Workflow
Exchange 5.5 included the Event Scripting Agent Exchange 5.5 SP1 included the Routing Objects technology Both technologies have object models that you can program against
Architecture Overview
Outlook 97 8.03 Outlook 98
Event sinks
Visual Interdev 1.0 Visual Interdev 98
Intrinsic Objects:
Custom Handlers
Java
Visual Basic/ C++
Script agent (scripto.dll) Script sink (ss.dll)
EventDetails.Session EventDetails.MessageID EventDetails.FolderID
EVENTS.EXE
NT Service
CDO Session uses mailbox identity of last script author
Exchange Server store
Event source
Event Architecture
Exchange store
Application folder
Docs
Change list
Notify
Event service
ICS
ICS (Incremental Change Synchronization) Events not missed, even if server is offline New, changed, deleted, scheduled event (timer)
Event handler (agent)
Exchange Routing Objects
RouteDetails ProcInstance Map Log Participant
VoteTable
Row
WorkItem
Exchange Routing Engine
Requires Exchange 5.5 SP1 Implemented as Custom Handler on top of Event Service Uses OnMessage_Created event to create Process Instance Each Process Instance Message (PIM) executes its defined Map Process Map controls routing execution by invoking actions
Creating A Process Instance
Folder
New Item
Map
Folder Script Default Folder Map
Agent Binding Message (Hidden)
Item
Map Item
Map Item
Map Item
New Process Instance
Existing Process Instances
Process Definition Map
ActivityIDActivity Flags Parameter 1 Parameter 2 Parameter 3 Parameter 4 Parameter 5 Parameter 6 1000 Send 2 Bob Smith IPM.Note Please review this… TRUE FALSE FALSE 1010 Wait 0 10080 1020 ORSplit 0 IsTimeout 1030 Goto 0 5000 1040 Receive 2 FALSE 1050 Consolidate 2 FALSE 1060 goto 0 10000 5000 CustomExpiry 2 Manager IPM.Alert Item not processed… TRUE 10000 Terminate 0
Default map stored in folder Copied onto new process instance messages OnNew and OnTimer folder events update state
Hub And Spoke Topology
Logical Route View Start=>
A
B
C
Physical Route View
User instantiates process by submitting item to hub folder Hub sends item to A who advances route by replying to hub
A
Start=>
Hub containing Process Definition
B
Hub sends item to B who advances route by replying to hub
Hub sends item to C C completes process by replying to hub
C
Some Demos. . .
Custom Routing Applications Deployment Tools
Let‟s look at the code!
COM Components
3 New COM Components
ACL Rule AcctCrt
Wrap the most common requested features Part of the Platform SDK (PDC Version or posted to msdn.microsoft.com)
Directory Integration And Management
For Collab apps, the directory is a key component
Find people, resources Dynamically resolve roles Store custom attributes Store organizational information
ADSI is the key object model to use to access directory information in Exchange
Some Demos. . .
Directory management Querying the directory Let‟s look at the code!
What Resources Are Available?
Exchange Developer‟s Forum
http://www.microsoft.com/exchange/ developers http://www.microsoft.com/exchange/ appfarm http://msdn.microsoft.com
Exchange appfarm
Platform SDK (includes EDK)
Resources
CDO Community resources
www.slipstick.com www.cdolive.com www.outlookexchange.com Exchange Listserver New whitepaper and KB article: Q125329 support.microsoft.com/support/exchang e/content/whitepapers/owa_tshoot.asp
OWA Deployment / Troubleshooting
Resources
Tip #1
Avoid the authentication trap “Failed to get inbox message”
Make sure to implement authentication correctly Remember NTLM means same machine When creating CDO apps, IIS is running under the context of IUSER_MACHINENAME, you need to force the browser to authenticate
Tip #2
Use early binding in Visual Basic®
Better compile time syntax checking Generates faster code Very simple to do
' Late bound Dim objSession As Object Dim objNewsgroup As Object Dim objPostItem As Object
‟ Early bound Dim objSession As MAPI.Session Dim objNewsgroup As Folder Dim objPostItem As Message
Tip #3
Avoid the “GetNext” trap
Temporary collection objects always point to first item
' error: collection returns the same message both times MsgBox("first message: " & inboxObj.Messages.GetFirst.Subject) MsgBox("next message: " & inboxObj.Messages.GetNext.Subject)
Create intermediary objects
objMessages = inboxObj.Messages MsgBox("first message: " & objMessages.GetFirst.Subject) MsgBox("next message: " & objMessages.GetNext.Subject)
Tip #4
Use “with” statements
Object creation is expensive Internal object created for each period that appears in the statement Reuse objects whenever possible
' warning: do not code this way; this is inefficient MsgBox "Text: " & objSession.Inbox.Messages.GetFirst.Text MsgBox "Subj: " & objSession.Inbox.Messages.GetFirst.Subject
With objSession.Inbox.Messages.GetFirst MsgBox "Text: " & .Text MsgBox "Subj: " & .Subject End With
Tip #5
Accessing the root public folder
Set objInfoStores = objSession.InfoStores For i = 1 To objInfoStores.Count If objInfoStores.Item(i)= "Public Folders" Then Set objInfoStore=objInfoStores.Item(i) Exit For End If Next bstrPublicRootID = objInfoStore.Fields.Item( _ &H66310102 ).Value 'PR_IPM_PUBLIC_FOLDERS_ENTRYID Set objTopFolder = objSession.GetFolder _ (bstrPublicRootID,objInfoStore.ID)
Tip #6
Deferred sending and delivery
Deferred sending
Message waits in user‟s outbox Property: &H3FEF0040 Message waits in MTA queue Property: &H000F0040
Deferred delivery
WITH objMessage.Fields .Add &H3FEF0040, CDate(”6/1/98 3:00:00 AM") .Add &HF0040, CDATE(“6/1/98 12:00:00 PM”) END WITH
Tip #7
Checking Access Rights
PR_ACCESS (&H0FF40003) Applies to folders and messages
Dim folderAccess as Long Dim canReadItems, canCreateItems, canDeleteFolder, _ canModifyFolder, canCreateFolders as Boolean ... folderAccess = objFolder.Fields (&H0FF40003) canReadItems = folderAccess AND &H00000002 canCreateItems = folderAccess AND &H00000010 canDeleteFolder = folderAccess AND &H00000004 canModifyFolder = folderAccess AND &H00000001 canCreateSubFolders = folderAccess AND &H00000008
Tip #8
Making outlook views accessible to the Web
Only applies to table views In Outlook, edit folder properties
Set „Automatically Generate Microsoft Exchange Views‟
Refresh ContainerRenderer object‟s view collection
Tip #9
Filtering appointments by date
CdoPR_START_DATE (&H00600040) CdoPR_END_DATE (&H00610040)
Set objCalendarFolder = objSession.GetDefaultFolder _ (CdoDefaultFolderCalendar) Set objAppointments = objCalendarFolder.Messages Set objAppointmentFilter = objAppointments.Filter WITH objMessageFilter.Fields .Add CdoPR_START_DATE,CDate("12/18/98 5:00:00 PM") .Add CdoPR_END_DATE,CDate("12/18/98 9:00:00 AM") END WITH
Tip #10
Retrieving a user‟s proxy addresses
Set objRecip = objMessage.Recipients(1) Debug.Print "Display Name: " & objRecip.Name Debug.Print "Default Address: " & objRecip.Address Set objAddrEntry = objRecip.AddressEntry Set objField = AddressEntry.Fields(&H800F101E) 'PR_EMS_AB_PROXY_ADDRESSES For Each v In objField.Value Debug.Print "Foreign System Address: " & v Next v
Tip #11
Setting the „from‟ field on posted items
Useful for anonymous postings
WITH objMessage.Fields .Add CdoPR_SENT_REPRESENTING_NAME, “John Doe”) „&H0042001F .Add CdoPR_SENT_REPRESENTING_ADDRTYPE, “SMTP”) „&H0064001F .Add CdoPR_SENT_REPRESENTING_EMAIL_ADDRESS, _ “JDoe@company.com”) „&H0065001F END WITH
Tip #12
Accessing direct reports in the directory
Reports stored in multi-valued string
PR_EMS_AB_REPORTS_T (&H800E101E)
See org. chart example on App farm
Dim objManager, objPerson as MAPI.AddressEntry Dim objDirectReports as OrgChart.Reports Set objDirectReports = CreateObject("OrgChart.Reports") Set objDirectReports.DataSource = myManager For idx = 1 to objDirectReports.Count set objPerson = objSession.GetAddressEntry _ (objDirectReports.Item(idx)) Debug.Print objPerson.Name Next
Tip #14
Setting reply-to
Example only supports one recipient Reply-to names (&H0050001E) Reply-to EntryIDs (&H004F0102)
Function SetReplyTo (objMessage as MAPI.Message, _ objReplyToMe As MAPI.AddressEntry) Dim entryblob, lengthStr, flatEntry As String lengthStr = CStr(Hex(Len(objReplyToMe.ID)/2)) flatEntry = lengthStr & "000000" & objReplyToMe.ID structLength = Hex(Len(flatEntry) / 2) entryblob = "01000000" & structLength & "000000" & flatEntry objMessage.Fields.Add &H0050001E, objReplyToMe.Name objMessage.Fields.Add &H004F0102, entryblob
Questions?