Free Lessons
Courses
Seminars
TechHelp
Fast Tips
Templates
Topic Index
Forum
ABCD
 
Home   Courses   TechHelp   Help   Contact   Merch   Join   Order   Logon   Forums   
 
Back to Access Forum    Comments List
Upload Images   @Reply   Bookmark    Link   Email   Next Unseen 
Importing Appointments and Tasks
Kenneth A Thomas 
       
3 days ago
I currently have appointments and tasks stored in Google (related to personal email address) and Outlook (related to my work email).  Can someone direct me to a video that would explain how to import these items to an Access Table and advice for setting up the table?  Thank you.
A Toykan  @Reply  
      
3 days ago
Yes, this can be done. I wasn't sure if Richard had videos specifically on these topics, and unfortunately, I couldn't find any clear results in his channel search.
When I started writing to explain what approach I could take, I realized it was a bit too long, so I asked ChatGPT to break down my answer into important subheadings without losing context and summarize them in a more understandable way. Since the text is a bit more organized, I'm sharing it now. I would have liked to explain it with a video example, but for now, we can ask our dear Richard to address this as a topic for a TechHelp video.

Outlook / Google Calendar and Tasks → Microsoft Access

We have appointments and tasks in two different places:
Appointments and tasks are in Microsoft Outlook
Personal appointments are in Google Calendar

We would like to bring these into Microsoft Access so that we can work with all of them from one database, just want Access to keep a local copy of our appointments and tasks and update them when necessary.

1. Access Tables

I think it is better to use two separate tables rather than putting everything into one table.
AppointmentT

| Field         | Type       | Purpose                                |
| ------------- | ---------- | -------------------------------------- |
| AppointmentID | AutoNumber | Primary Key                            |
| Source        | Short Text | OUTLOOK or GOOGLE                      |
| SourceID      | Short Text | ID of the original appointment         |
| Subject       | Short Text | Appointment title                      |
| StartDateTime | Date/Time  | Start date and time                    |
| EndDateTime   | Date/Time  | End date and time                      |
| AllDay        | Yes/No     | All-day appointment                    |
| Location      | Short Text | Location                               |
| Description   | Long Text  | Notes/details                          |
| Organizer     | Short Text | Organizer                              |
| IsRecurring   | Yes/No     | Recurring appointment                  |
| LastModified  | Date/Time  | Last modification                      |
| ImportedAt    | Date/Time  | When Access imported it                |
| IsDeleted     | Yes/No     | Used when the original item is deleted |

TaskT

| Field           | Type       | Purpose                                |
| --------------- | ---------- | -------------------------------------- |
| TaskID          | AutoNumber | Primary Key                            |
| Source          | Short Text | OUTLOOK or GOOGLE                      |
| SourceID        | Short Text | ID of the original task                |
| Subject         | Short Text | Task description                       |
| StartDate       | Date/Time  | Start date                             |
| DueDate         | Date/Time  | Due date                               |
| Completed       | Yes/No     | Completed or not                       |
| PercentComplete | Integer    | Completion percentage                  |
| Priority        | Integer    | Task priority                          |
| Status          | Short Text | Current status                         |
| Description     | Long Text  | Notes/details                          |
| LastModified    | Date/Time  | Last modification                      |
| ImportedAt      | Date/Time  | When Access imported it                |
| IsDeleted       | Yes/No     | Used when the original item is deleted |

2. Why do we need Source and SourceID?

This is important. For example, Access may receive the same Outlook appointment every time we run the import. we don't want Access to create another copy every time. So we keep 'Source = OUTLOOK' and the original Outlook item's unique ID in 'SourceID'

The same applies to Google, 'Source = GOOGLE'and its Google event ID in 'SourceID'.

This allows Access to say:
"I already have this appointment, so update it instead of creating another one."

I would also create a unique index on Source + SourceID.

3. Getting appointments from Outlook
For Outlook, we would use VBA inside Access. The basic idea is:

Access opens Outlook in the background and goes to the user's Calendar folder. Something like:

Access
   ↓
Outlook
   ↓
Calendar
   ↓
Appointment Items
   ↓
AppointmentT

For every appointment, Access reads the information such as:

* Subject
* Start time
* End time
* Location
* Description
* Organizer
* Last modified date

and then puts that information into AppointmentT.

The important point is that we are not manually exporting an Excel file from Outlook every time. Access will read the Outlook Calendar directly.

4. Getting Tasks from Outlook
Tasks work in almost exactly the same way. Access connects to Outlook and opens the Tasks folder:

Access
   ↓
Outlook
   ↓
Tasks
   ↓
Task Items
   ↓
TaskT

For each task, Access reads things such as:

* Subject
* Start Date
* Due Date
* Completed
* Percent Complete
* Priority
* Notes

and stores them in TaskT.

5. What about Google Calendar?
Google is slightly different. We cannot use the Outlook VBA method for Google. For Google Calendar, the better approach is to use the Google Calendar API. The basic idea is:

Google Calendar
      ↓
Google Calendar API
      ↓
Access VBA
      ↓
AppointmentT

The Google event ID becomes the SourceID, and Source is simply GOOGLE. So Access does not really care where the appointment came from. It can have:

OUTLOOK | Meeting with John
OUTLOOK | Sales meeting
GOOGLE  | Personal appointment
GOOGLE  | Family event

all in the same AppointmentT table.

6. The final idea
Put a simple button in Access such as "Sync Outlook & Google" and, when we click it, Access checks both sources. It looks for:

* New appointments
* Changed appointments
* Deleted appointments
* New tasks
* Changed tasks
* Deleted tasks

and updates the Access tables. So Access becomes the central database, while Outlook and Google remain the original sources.
A Toykan  @Reply  
      
2 days ago
The summary lacks code snippets, so I'm providing these to give you a head start. Here's an example for Outlook Appointments

DetailsPublic Sub SyncOutlookAppointments()

    Dim olApp As Object, olNS As Object, olCalendar As Object, olItems As Object, appt As Object
    Dim rs As DAO.Recordset, rsFind As DAO.Recordset
    Dim sql As String

    Set olApp = CreateObject("Outlook.Application")
    Set olNS = olApp.GetNamespace("MAPI")

    ' Outlook Calendar
    Set olCalendar = olNS.GetDefaultFolder(9)   ' 9 states Calendar
    Set olItems = olCalendar.Items

    olItems.Sort "[Start]"

    Set rs = CurrentDb.OpenRecordset("AppointmentT", dbOpenDynaset)

    For Each appt In olItems

        If appt.Class = 26 Then

            ' Is there any record with Source + SourceID?
            sql = "SELECT * FROM AppointmentT " & _
                  "WHERE Source='OUTLOOK' " & _
                  "AND SourceID='" & Replace(appt.EntryID, "'", "''") & "'"

            Set rsFind = CurrentDb.OpenRecordset(sql, dbOpenDynaset)

            If rsFind.EOF Then

                ' If Not › INSERT
                rs.AddNew

                rs!Source = "OUTLOOK"
                rs!SourceID = appt.EntryID
                rs!Subject = Nz(appt.Subject, "")
                rs!StartDateTime = appt.Start
                rs!EndDateTime = appt.End
                rs!AllDay = appt.AllDayEvent
                rs!Location = Nz(appt.Location, "")
                rs!Description = Nz(appt.Body, "")
                rs!IsRecurring = appt.IsRecurring
                rs!LastModified = appt.LastModificationTime
                rs!ImportedAt = Now()
                rs!IsDeleted = False

                rs.Update

            Else

                ' If there is › UPDATE
                rsFind.Edit

                rsFind!Subject = Nz(appt.Subject, "")
                rsFind!StartDateTime = appt.Start
                rsFind!EndDateTime = appt.End
                rsFind!AllDay = appt.AllDayEvent
                rsFind!Location = Nz(appt.Location, "")
                rsFind!Description = Nz(appt.Body, "")
                rsFind!IsRecurring = appt.IsRecurring
                rsFind!LastModified = appt.LastModificationTime
                rsFind!ImportedAt = Now()
                rsFind!IsDeleted = False

                rsFind.Update

            End If

            rsFind.Close
            Set rsFind = Nothing

        End If

    Next appt

    rs.Close

    Set rsFind = Nothing
    Set rs = Nothing
    Set olItems = Nothing
    Set olCalendar = Nothing
    Set olNS = Nothing
    Set olApp = Nothing

    MsgBox "Outlook appointments synchronized successfully.", vbInformation

End Sub
A Toykan  @Reply  
      
2 days ago
Here's an example for Outlook Tasks, completely same approach:

DetailsPublic Sub SyncOutlookTasks()

    Dim olApp As Object, olNS As Object, olTasks As Object, olItems As Object, task As Object
    Dim rs As DAO.Recordset, rsFind As DAO.Recordset
    Dim sql As String

    Set olApp = CreateObject("Outlook.Application")
    Set olNS = olApp.GetNamespace("MAPI")

    Set olTasks = olNS.GetDefaultFolder(13)   ' 13 states Tasks
    Set olItems = olTasks.Items

    Set rs = CurrentDb.OpenRecordset("TaskT", dbOpenDynaset)

    For Each task In olItems

        If task.Class = 48 Then

            sql = "SELECT * FROM TaskT " & _
                  "WHERE Source='OUTLOOK' " & _
                  "AND SourceID='" & Replace(task.EntryID, "'", "''") & "'"

            Set rsFind = CurrentDb.OpenRecordset(sql, dbOpenDynaset)

            If rsFind.EOF Then

                rs.AddNew

                rs!Source = "OUTLOOK"
                rs!SourceID = task.EntryID
                rs!Subject = Nz(task.Subject, "")
                rs!StartDate = task.StartDate
                rs!DueDate = task.DueDate
                rs!Completed = task.Complete
                rs!PercentComplete = task.PercentComplete
                rs!Priority = task.Importance
                rs!Status = Nz(task.Status, "")
                rs!Description = Nz(task.Body, "")
                rs!LastModified = task.LastModificationTime
                rs!ImportedAt = Now()
                rs!IsDeleted = False

                rs.Update

            Else

                rsFind.Edit

                rsFind!Subject = Nz(task.Subject, "")
                rsFind!StartDate = task.StartDate
                rsFind!DueDate = task.DueDate
                rsFind!Completed = task.Complete
                rsFind!PercentComplete = task.PercentComplete
                rsFind!Priority = task.Importance
                rsFind!Status = Nz(task.Status, "")
                rsFind!Description = Nz(task.Body, "")
                rsFind!LastModified = task.LastModificationTime
                rsFind!ImportedAt = Now()
                rsFind!IsDeleted = False

                rsFind.Update

            End If

            rsFind.Close
            Set rsFind = Nothing

        End If

    Next task

    rs.Close

    Set rsFind = Nothing
    Set rs = Nothing
    Set olItems = Nothing
    Set olTasks = Nothing
    Set olNS = Nothing
    Set olApp = Nothing

    MsgBox "Outlook tasks synchronized successfully.", vbInformation

End Sub


A Toykan  @Reply  
      
2 days ago
The logic of these codes is

Access connects to Outlook and reads the Calendar oro Tasks items.
For each appointment/task, it gets the unique Outlook EntryID.
Access checks whether the same Source + SourceID already exists in the Access table.
If it does not exist -> INSERT a new record.
If it already exists -> UPDATE the existing record with the latest Outlook information.
LastModified and ImportedAt are also updated.
This prevents duplicate records every time the sync is run.
A Toykan  @Reply  
      
2 days ago
Google approach is slightly different. The API call itself is actually quite simple. The more important part is OAuth 2.0 authentication and token management. Getting the user's permission, storing the refresh token securely, refreshing the access token when necessary, and then using that token for the API requests. Once OAuth is handled, the basic process is Google Clader -> OAuth -> Access token -> Calendar API -> JSOn response -> Access VBA and parsing json -> AppointmentT

DetailsPublic Sub ImportGoogleCalendar()

    Dim http As Object
    Dim url As String, accessToken As String, json As String

    accessToken = GetGoogleAccessToken()

    Set http = CreateObject("MSXML2.XMLHTTP")

    url = "https://www.googleapis.com/calendar/v3/calendars/primary/events" & _
          "?singleEvents=true&orderBy=startTime"

    http.Open "GET", url, False
    http.setRequestHeader "Authorization", "Bearer " & accessToken
    http.send

    If http.Status = 200 Then

        json = http.responseText

        ' Read events in JSON
        ' id
        ' summary
        ' start
        ' end
        ' location
        ' description
        ' updated
        '
        ' Then AppointmentT table
        ' Source = "GOOGLE"
        ' SourceID = event id
        ' INSERT / UPDATE

    Else
        MsgBox "Google Calendar error: " & http.Status
    End If

End Sub


If I remember correctly, Richard's Weather API video also gives some useful hints about working with an external API and parsing JSON responses from within Access/VBA. So that video may be useful as a starting point for this part.
A Toykan  @Reply  
      
2 days ago
I intentionally didn't use Early Binding in the code. That way, you won't need to manually check Tools/References/Microsoft Outlook xx.x Object Library in Access VBA.
Kenneth A Thomas OP  @Reply  
       
2 days ago
Thank you, A Toykan.  This is a lot of information to process and us, so I am printing out this thread.
Richard Rost  @Reply  
           
2 days ago
That's a lot of helpful code. Thank you, A Toykan, for helping Kenneth out like that. That's truly going above and beyond.

Kenneth, printing it out and taking it one piece at a time is exactly the right approach. In fact, when I was a kid, one of the ways that I learned programming was going from printouts in books and magazines and literally typing the code in line by line. For some reason, it just sticks better in your brain than copying and pasting it.

I'd start with the table design and the Outlook side first, since Outlook is the simpler of the two. Google Calendar requires OAuth authentication and token management, which is a whole separate project.

Also, treat Outlook and Google as the master sources, and Access as the local copy for reporting, searching, and whatever else you want to do with the data. That makes the synchronization rules much easier to manage.
Kenneth A Thomas OP  @Reply  
       
2 days ago
OK, thank you Richard.
A Toykan, I was doing good until I got to the section that starts with
If appt.Class = 26 Then    Please see the issues below:

sql = "SELECT * FROM AppointmentT "&_
            "WHERE Source='Outlook'" &_
            "AND SourceID='" & Replace(appt.EntryID, ""',""') & ""'
A Toykan  @Reply  
      
2 days ago
sql = "SELECT * FROM AppointmentT " & _
      "WHERE Source='OUTLOOK' " & _
      "AND SourceID='" & Replace(appt.EntryID, "'", "''") & "'"

You need to pay close attention to line continuation and string concatenation. I think it would be helpful to review Richard’s video on this topic again.
Kenneth A Thomas OP  @Reply  
       
2 days ago
This happens to me every time I use and Underscore "_"
Stefan Weidenhaun  @Reply  
    
6 hours ago
A I would like to give you an enlighted feedback of your appointment code example. I adopted it with minor adjustments to my needs and found it very inspiring. It saves me a lot of time as it replaces a procedure that retrieved appointments from Outlook every time I needed one. Outlook takes about 30 sec to find the right one as it parses sometimes several years to find it. As the appointments are now in my table, the request is answered in a fraction of a second.
Very inspiring!
Add a Reply Upload an Image
Next Unseen

 
 
What's This?

 

The following is a paid advertisement
Computer Learning Zone is not responsible for any content shown or offers made by these ads.
 

Learn
 
Access - index
Excel - index
Word - index
Windows - index
PowerPoint - index
Photoshop - index
Visual Basic - index
ASP - index
Seminars
More...
Customers
 
Login
My Account
My Courses
Lost Password
Memberships
Student Databases
Change Email
Info
 
Latest News
New Releases
User Forums
Topic Glossary
Tips & Tricks
Search The Site
Code Vault
Collapse Menus
Help
 
Customer Support
Web Site Tour
FAQs
TechHelp
Consulting Services
About
 
Background
Testimonials
Jobs
Affiliate Program
Richard Rost
Free Lessons
Mailing List
PCResale.NET
Order
 
Video Tutorials
Handbooks
Memberships
Learning Connection
Idiot's Guide to Excel
Volume Discounts
Payment Info
Shipping
Terms of Sale
Contact
 
Contact Info
Support Policy
Mailing Address
Phone Number
Fax Number
Course Survey
Email Richard
[email protected]
Blog RSS Feed    YouTube Channel

LinkedIn
Copyright 2026 by Computer Learning Zone, Amicron, and Richard Rost. All Rights Reserved. Current Time: 9/5/2026 10:56:00 AM. PLT: 0s