Summary
One of the most important part of managing a software business is keeping
track of all the different jobs, possible jobs and other things that pass your
way. When you are not so busy, your systems for managing these requests can be
on paper, in a database, in a word file and more than likely in your email inbox
or task box. When you are busy, trying to pull all of these things together at
the one time can be a little hit and miss. In this article, Garry and Scott show
how they have integrated Outlook tasks into their Access database so that they
can prepare reports and hook into other related project data. This exercise also
included a voyage into XML exporting from Outlook and attempts to view that
information inside Microsoft Access.
Most of the previous discussions in Smart Access about Outlook have concentrated
on using linked tables to retrieve the data from Outlook. Unfortunately when it
comes to Outlook Tasks, most of the important task fields such as Body and
Subject are invisible to the Outlook linker. So in this case, a more classical
Automation approach was taken to retrieve the information. We hope that you
enjoy the investigation as much as we did.
The Download Database
If you wish to try this Outlook demonstration, you will need a copy of
either Outlook 2000 or Outlook 2002 on your computer. Now you need to setup some
demo Tasks in Outlook (if you haven't already got some). For each task, you need
to allocate a Category. To make this download database easier to understand,
enter an category of "Project 1" or "Project 2" for some of the tasks that you
setup. You will find the Category field on the bottom right hand side of the New
Task form.
The download database is in Access 2000 format. The database will look through
your Outlook tasks and bring across the tasks and store them in a table in the
demonstration database. The software will also generate an XML file of the same
tasks and store that in the same directory as the software.
The download database requires external references as follows
Microsoft Outlook 9.0 Object Library
Microsoft ActiveX Data Objects 2.5
Microsoft DAO 3.51 Object Library
You will need ADOXDB if you are at all interested in the XML exports and
imports. Download the installation kit for this from
http://www.microsoft.com/data/
You probably will not need a DAO reference as I have
commented out all the code that uses DAO. Initially I wrote all the non XML
software using DAO as I am running the software in an Access 97 database. Search
for lines with ' DAO comments and uncomment them. Conversely, comment all the
lines with ' ADO so that you are using the correct recordset handler for the
code. If you are using DAO, then you will want probably want to comment all
lines with "XML File >>" so that XML exporting is turned off.
If you have Microsoft Outlook 97, you must program in VB script rather than vb.
This is not covered in this article.
Microsoft Outlook 2000
When it came to programming Microsoft Outlook, I turned to my co-author
Scott to work out all the tricky bits. Microsoft Outlook programming is not easy
as the number of samples that are around for programming are quite scarce. This
particularly applies to the document model for folders and sub folders and the
different types of data that is stored in the folders. Without going into all
the finer technical details about Outlook , here are some simple suggestions to
making Outlook easier to manage as a programmer. First if you stick to the
standard top level folders, then programming is far easier. By this I mean,
Contacts, Inbox, Calendar, Notes and Tasks. Fortunately for us, these folders
all have special constants to define where they are located. In this article, we
are only interested in the Tasks folder and our initial piece of code start off
as follows
Dim appOutlook As
Outlook.Application
Dim appNS, appTasks
Dim AppItems As Outlook.Items
Set appOutlook = New Outlook.Application
Set appNS = appOutlook.GetNamespace("MAPI")
Set appTasks = appNS.GetDefaultFolder(olFolderTasks)
Set AppItems = appTasks.Items
The above lines of code are the basic code that you need to
hook into the items inside the Outlook folders. The Outlook constant
olFolderTasks defines that we would like to look at the Tasks folder. If you
select the olFolderTasks constant and hit F2, you will open the object browser
to show all the special constants for the important (and unmovable) Outlook
folders. If you are following the code in the sample database, you will find
that I have now jumped to the middle of the subroutine called AddOutlookTasks.
This is because I first want to demonstrate the mechanics of getting the
information from the Tasks folder.
Now we would like to work our way through all the tasks item by item and store
the values for that task into variables. This is handled by first finding out
the total number of tasks and then moving through the collection as follows. As
you can see below, this actually is quite easy. The code is complicated a little
by a number of tests that are performed to limit the tasks that are transferred.
This includes testing if the Task is fully completed (designated by
PercentComplete = 100) and also looking to see if the Task has been deferred.
These are not transferred
ItemCount = AppItems.Count
' set up append query statements for every task
On Error GoTo 0
For i = 1 To ItemCount
itPerComp = AppItems(i).PercentComplete
If itPerComp < 100 And _
AppItems(i).Status <> olTaskDeferred Then
On Error Resume Next
If (Not IsMissing(CatRequired) And _
AppItems(i).Categories = CatRequired) Or _
IsMissing(CatRequired) Then
On Error GoTo 0
DoCmd.Echo True, AppItems(i).Subject
itDateCreated = AppItems(i).CreationTime
itSubject = AppItems(i).Subject
itBody = AppItems(i).Body
itCategory = AppItems(i).Categories
itImportance = AppItems(i).Importance
End If
End If
Next
Set appOutlook = Nothing
Listing 1 – The Outlook code that transfers Task item fields to
variables
If you are a little low in Outlook programming experience
level, here are some tricks to find out important things that you will need to
know in Outlook. Open the Object Explorer (hit F2) and choose Outlook as the
library to search and enter TaskItem to search for TaskItems. This shows you all
the fields that are available in Task Items as well as all the other properties,
methods and events that relate to the TaskItems. Without the object explorer,
finding the actual field names in the collection is next to impossible. If you
wish to program other types of Outlook folders, search for MailItems,
ContactItems, NoteItems and AppointmentItems. Then you can then substitute the
task field name collection field names.
<< Click to expand
Figure 1. The object explorer shows you all the fields in an Outlook task.
That’s all there is to looping through your Outlook
tasks. Setup the collection, loop through it and store the results in
variables or directly into your target table or recordset.
Storing The Results In An Access Database
Now as the Smart Access reader is more than likely going to be storing the
Outlook information in an Access database, I will step back a bit in the sample
code to demonstrate the important visual basic that is required to append the
Outlook Tasks to an Access table. To manage the importation of the Outlook Tasks
into the database, I have setup a subroutine which has two important arguments
that need further description.
Call AddOutlookTasks(User_FX)
Sub AddOutlookTasks(userNameRequired As String, _
Optional CatRequired As Variant)
The first and very important argument is the system username. If you
switch machines or login with different usernames, you or your colleagues are
going to be accessing a different Outlook task list. Importing those
tasks in the database will mean that it will be necessary to identify which task
list is actually going to be imported into the database. To do this, I use
the Environ function that identifies the end user from an environment variable
that is stored on any NT, Win XP or Win 2000 PC. Other
operating systems do not carry this environment variable.
Public Function User_FX() As String
' Assume NT, Win2000 or WinXP User
User_FX = Environ("USERNAME")
If User_FX = "" Then
' Must be Win95 98 user
User_FX = "Unknown"
End If
End Function
If the NT login identifier was FreddyM, then all my tasks
in the Access database would be identified with a FreddyM username.
This allows us to process tasks for more than one person in the same system.
This could be very useful to managers who need to assess user tasks when they
are sick or if they need to be reallocated.
The other argument to the subroutine is that of Category Required.
In some parts of our software, we find it more convenient (faster) to only
update all tasks for a given category. You will see references to the
categoryReq variable in the code that follows.
The first step in the process will more than likely be clearing out any
existing task information allready stored in your database. This is
handled in this subroutine by using an SQL delete statement. There
is an additional where clause in the SQL that I generate which allows the
subroutine to only delete and load Outlook tasks from one category using the
CatRequired field.
Const outlookTbl = "tblOutlookTasks"
Dim qryStr As String
qryStr = "delete from " & outlookTbl & _
" OutlookTasks where systemUserName = '" _
& userNameRequired & "'"
If Not IsMissing(CatRequired) Then
qryStr = qryStr & " and category = '" & CatRequired & "'"
End If
DoCmd.SetWarnings False
DoCmd.RunSQL qryStr
DoCmd.SetWarnings True
Now I will open an ADO recordset so that I can write records to the Access table
that holds all the tasks. This Access table is defined by the outlookTbl
constant and its structure should match that of the Outlook task fields.
Set rstTasks = New ADODB.Recordset
With rstTasks
.ActiveConnection = CurrentProject.Connection
.CursorType = adOpenKeyset
.LockType = adLockOptimistic
.Open outlookTbl, , , , adCmdTable
End With
Now I can return to the Outlook items that were being processed and stored in
the variables. These variables are then added to a new record and
appended to the tasks table in the Access database.
itSubject = AppItems(i).Subject
itBody = AppItems(i).Body
With rstTasks
.AddNew
!DateCreated = itDateCreated
!Subject = itSubject
!Category = itCategory
!Body = itBody
!PercentComplete = itPerComp
!Importance = itImportance
' Add the NT/WinXP/Win2000 username
!SystemUsername = userNameRequired
.Update
End With
Just a quiet word of warning. Constant loading and reloading of Access
tasks into an Access table will bloat your database. You will need
to be vigilant with your compacting of the database. If you are only
storing the tasks to produce reports, you may want to use a temporary database
and link to the tasks using the remote queries that I described in Smart Access
last year.
Integrating Outlook Tasks With The Access Database
As Microsoft Outlook stores its data in a very flat structure, merging
this information into a corporate world will require integration with a
database. To do this, I use the projectID primary key in the Project
table that my Access database as the common key between the Access database and
the Outlook tasks table. In Outlook, the project code is stored in the
Category table. Figure 3 shows how the Outlook items can be viewed
in a sub form below the projects table to view all the tasks for a given
project. The Category field was chosen because all the different Outlook
collections such as Calendar, Inbox and Notes also have a very prominent
Category key. This seemed like an appropriate place to store a project
identifier.
The best way to describe how these 2 separate programs relate to each other is
to look at both the project table and the outlook table that I have imported
using a simple Access relationship. This is shown in Figure 2.

Figure 2 - Relationship diagram showing how Outlook tasks are integrated with
the Access database

Figure 3. Outlook tasks are integrated using the Category field to join with
project ID field
Naturally, all tasks that so not have a Project will end up as orphans in this
model. These can be easily picked up by adding an Orphan project or
simply deleting all Tasks without projects during the import stage.
But the main reason why I do all this integration is to produce a really neat
report that shows details on a individual project along with the tasks for that
project. The report all sorts the tasks from highest priority to lowest
priority. On the top of the form in figure 3, you will see a
hyperlink entitled Task Printout. The click event for this hyperlink fires
the following code to open the report with a project filter. The report
which shows one task per page is shown in figure 4.
DoCmd.OpenReport
"rptProjectsOutlook_A5", _
acPreview, , "ProjectID = '" & Me!ProjectID & "'"

Figure 4 - Shows a single Outlook task per page filtered by project.
As this example is very relevant to programmers, I have found that A5 paper (1/2
size of A4) is a very handy format for jotting down discussions on different
programming tasks. With A5 being relatively small, it is easy to keep all
the tasks apart and sort them into programming order. When I use larger
sheets of paper, I always store multiple tasks on the one sheet and have a bit
of trouble sorting out the jobs. This also applies to allocating the
jobs to my subcontractors.
Using XML Instead Of Access Tables
As mentioned above, I am always a little reluctant to storing temporary data in
an Access database due to the bloat factor. So I decided to look
into other ways to transfer the database from Outlook across to Access. My
initial thoughts were to make either a comma delimited file or a fixed width
text file. This method was quite appealing as Access has a very good
linker for both of these formats of files. Whilst I believe that these are
quite legitimate ways to transfer the data, I decided instead it was time to
refine my skills with XML and see if Access 2002 offered any great improvements
in XML as was promised in the promotional material.
So now I return to my earlier exploits with the Outlook task items to help
describe what I came up for XML creation. Initially as I really like
the simplicity of the ADO save recordset method as a simple way of making an
XML, I setup the following to establish my ADO recordset.
Dim rstXML As New ADODB.Recordset
Dim xmlFile As String
xmlFile = GetDBPath_FX & "tasks.xml"
Now I encountered my first real dilemma which took hours of poring through help
and online help because as I wasn’t using any existing data, I had no query or
recordset upon which to establish my XML file. Then I came across the
Append method of Fields collection in ADO. This allows you to actually
establish the names, types and attributes of fields in a recordset without
actually making a table anywhere. The arguments are field name, type and
length. As you can see in the code snippet below, this is not unlike
a create table SQL statement . One argument that was confusing was field
length as the ADO help indicated this was not required for some field types such
as date but the compiler still required it. Where I have entered a field
length of zero is where the length is not actually relevant but it is needed.
With rstXML.Fields
.Append "DateCreated", adDate, 0
.Append "Subject", adChar, 150
.Append "Body", adLongVarChar, 5000
.Append "Category", adChar, 20
.Append "PercentComplete", adSingle, 0
.Append "Importance", adTinyInt, 0
.Append "SystemUsername", adChar, 50
End With
rstXML.Open