Exporting Appointments from Outlook to Excel


I put this solution together for Allen, who had seen my post demonstrating how to export Outlook messages to Excel and asked if I could create a similar macro to export appointments. Allen went on to explain that his organization uses a shared calendar and that periodically he would like to export its contents to Excel. For each appointment, Allen wants to export the organizer (i.e. the person that added the appointment to the calendar), when the appointment was added, the appointment’s subject, when it starts, and who was invited. To make it a little easier for Allen, I broke “who was invited” down into two groups: required and optional attendees. The solution itself is nearly identical to the one I used to export messages.

Instructions.

Follow these instructions to add the code to Outlook.

  1. Start Outlook
  2. Press ALT + F11 to open the Visual Basic Editor
  3. If not already expanded, expand Microsoft Office Outlook Objects
  4. If not already expanded, expand Modules
  5. Select an existing module (e.g. Module1) by double-clicking on it or create a new module by right-clicking Modules and selecting InsertModule.
  6. Copy the code from the code snippet box and paste it into the right-hand pane of Outlook’s VB Editor window
  7. Click the diskette icon on the toolbar to save the changes
  8. Close the VB Editor
Sub ExportAppointmentsToExcel()
    Const SCRIPT_NAME = "Export Appointments to Excel"
    Dim olkFld As Object, _
        olkLst As Object, _
        olkApt As Object, _
        excApp As Object, _
        excWkb As Object, _
        excWks As Object, _
        lngRow As Long, _
        intCnt As Integer
    Set olkFld = Application.ActiveExplorer.CurrentFolder
    If olkFld.DefaultItemType = olAppointmentItem Then
        strFilename = InputBox("Enter a filename (including path) to save the exported appointments to.", SCRIPT_NAME)
        If strFilename <> "" Then
            Set excApp = CreateObject("Excel.Application")
            Set excWkb = excApp.Workbooks.Add()
            Set excWks = excWkb.Worksheets(1)
            'Write Excel Column Headers
            With excWks
                .Cells(1, 1) = "Organizer"
                .Cells(1, 2) = "Created"
                .Cells(1, 3) = "Subject"
                .Cells(1, 4) = "Start"
                .Cells(1, 5) = "Required"
                .Cells(1, 6) = "Optional"
            End With
            lngRow = 2
            Set olkLst = olkFld.Items
            olkLst.Sort "[Start]"
            olkLst.IncludeRecurrences = True
            'Write appointments to spreadsheet
            For Each olkApt In Application.ActiveExplorer.CurrentFolder.Items
                'Only export appointments
                If olkApt.Class = olAppointment Then
                    'Add a row for each field in the message you want to export
                    excWks.Cells(lngRow, 1) = olkApt.Organizer
                    excWks.Cells(lngRow, 2) = olkApt.CreationTime
                    excWks.Cells(lngRow, 3) = olkApt.Subject
                    excWks.Cells(lngRow, 4) = olkApt.Start
                    excWks.Cells(lngRow, 5) = olkApt.RequiredAttendees
                    excWks.Cells(lngRow, 6) = olkApt.OptionalAttendees
                    lngRow = lngRow + 1
                    intCnt = intCnt + 1
                End If
            Next
            excWks.Columns("A:F").AutoFit
            excWkb.SaveAs strFilename
            excWkb.Close
            MsgBox "Process complete.  A total of " & intCnt & " appointments were exported.", vbInformation + vbOKOnly, SCRIPT_NAME
        End If
    Else
        MsgBox "Operation cancelled.  The selected folder is not a calendar.  You must select a calendar for this macro to work.", vbCritical + vbOKOnly, SCRIPT_NAME
    End If
    Set excWks = Nothing
    Set excWkb = Nothing
    Set excApp = Nothing
    Set olkApt = Nothing
    Set olkLst = Nothing
    Set olkFld = Nothing
End Sub

Using the Code.

  1. With Outlook open select a calendar.
  2. Run the macro.
  3. When prompted, enter a filename to save the export to. You can cancel the export by leaving the file name blank.
  4. The macro will display a dialog-box when it’s finished. The dialog-box includes a count of the number of appointments exported.

Revisions.

1 2 3 4            

Revision 1.

This revision is for Oradev, who asked for two changes to the original script. First, Oradev wants to be able to export appointments falling within a date range. To accomplish this, I’ve added a dialog-box that prompts for the date range. Second, Oradev needs a different set of data from each appointment. Where the original code exports organizer, date created, subject start time, and attendees, this version exports category, subject, start date, end date, start time, end time, the length of the appointment in hours, and attendees. The export is sorted by category and the appointment length column is summed.

Oradev will use the instructions from the original post to add the code to Outlook.

Sub ExportAppointmentsToExcel()
    Const SCRIPT_NAME = "Export Appointments to Excel (Rev 1)"
    Const xlAscending = 1
    Const xlYes = 1
    Dim olkFld As Object, _
        olkLst As Object, _
        olkRes As Object, _
        olkApt As Object, _
        olkRec As Object, _
        excApp As Object, _
        excWkb As Object, _
        excWks As Object, _
        lngRow As Long, _
        lngCnt As Long, _
        strFil As String, _
        strLst As String, _
        strDat As String, _
        datBeg As Date, _
        datEnd As Date, _
        arrTmp As Variant
    Set olkFld = Application.ActiveExplorer.CurrentFolder
    If olkFld.DefaultItemType = olAppointmentItem Then
        strDat = InputBox("Enter the date range of the appointments to export in the form ""mm/dd/yyyy to mm/dd/yyyy""", SCRIPT_NAME, Date & " to " & Date)
        arrTmp = Split(strDat, "to")
        datBeg = IIf(IsDate(arrTmp(0)), arrTmp(0), Date) & " 12:00am"
        datEnd = IIf(IsDate(arrTmp(1)), arrTmp(1), Date) & " 11:59pm"
        strFil = InputBox("Enter a filename (including path) to save the exported appointments to.", SCRIPT_NAME)
        If strFil <> "" Then
            Set excApp = CreateObject("Excel.Application")
            Set excWkb = excApp.Workbooks.Add()
            Set excWks = excWkb.Worksheets(1)
            'Write Excel Column Headers
            With excWks
                .Cells(1, 1) = "Category"
                .Cells(1, 2) = "Subject"
                .Cells(1, 3) = "Starting Date"
                .Cells(1, 4) = "Ending Date"
                .Cells(1, 5) = "Start Time"
                .Cells(1, 6) = "End Time"
                .Cells(1, 7) = "Hours"
                .Cells(1, 8) = "Attendees"
            End With
            lngRow = 2
            Set olkLst = olkFld.Items
            olkLst.Sort "[Start]"
            olkLst.IncludeRecurrences = True
            Set olkRes = olkLst.Restrict("[Start] >= '" & Format(datBeg, "ddddd h:nn AMPM") & "' AND [Start] <= '" & Format(datEnd, "ddddd h:nn AMPM") & "'")
            'Write appointments to spreadsheet
            For Each olkApt In olkRes
                'Only export appointments
                If olkApt.Class = olAppointment Then
                    strLst = ""
                    For Each olkRec In olkApt.Recipients
                        strLst = strLst & olkRec.Name & ", "
                    Next
                    If strLst <> "" Then strLst = Left(strLst, Len(strLst) - 2)
                    'Add a row for each field in the message you want to export
                    excWks.Cells(lngRow, 1) = olkApt.Categories
                    excWks.Cells(lngRow, 2) = olkApt.Subject
                    excWks.Cells(lngRow, 3) = Format(olkApt.Start, "mm/dd/yyyy")
                    excWks.Cells(lngRow, 4) = Format(olkApt.End, "mm/dd/yyyy")
                    excWks.Cells(lngRow, 5) = Format(olkApt.Start, "hh:nn ampm")
                    excWks.Cells(lngRow, 6) = Format(olkApt.End, "hh:nn ampm")
                    excWks.Cells(lngRow, 7) = DateDiff("n", olkApt.Start, olkApt.End) / 60
                    excWks.Cells(lngRow, 7).NumberFormat = "0.00"
                    excWks.Cells(lngRow, 8) = strLst
                    lngRow = lngRow + 1
                    lngCnt = lngCnt + 1
                End If
            Next
            excWks.Columns("A:H").AutoFit
            excWks.Range("A1:H" & lngRow - 1).Sort Key1:="Category", Order1:=xlAscending, Header:=xlYes
            excWks.Cells(lngRow, 7) = "=sum(G2:G" & lngRow - 1 & ")"
            excWkb.SaveAs strFil
            excWkb.Close
            MsgBox "Process complete.  A total of " & lngCnt & " appointments were exported.", vbInformation + vbOKOnly, SCRIPT_NAME
        End If
    Else
        MsgBox "Operation cancelled.  The selected folder is not a calendar.  You must select a calendar for this macro to work.", vbCritical + vbOKOnly, SCRIPT_NAME
    End If
    Set excWks = Nothing
    Set excWkb = Nothing
    Set excApp = Nothing
    Set olkApt = Nothing
    Set olkLst = Nothing
    Set olkFld = Nothing
End Sub

Revision 2.

This revision is for Kimberly. Kimberly asked for a version based on revision 1, with a few changes. Specifically

  1. Export a fixed list of calendars
  2. Include the name of the calendar with each exported appointment
  3. Export to a fixed file name rather than having to enter the file name each time

Kimberly will use the instructions from the original post to add the code to Outlook.

Sub ExportAppointmentsToExcel()
    'On the next line, edit the list of calendars you want to export.  Each entry is the path to a calendar.  Entries are separated by a comma.
    Const CAL_LIST = "Calendar1,Calendar2"
    'On the next line, edit the path to and name of the Excel spreadsheet to export to
    Const EXCEL_FILE = "c:\users\david\documents\testarea\kimberly.xlsx"
    Const SCRIPT_NAME = "Export Appointments to Excel (Rev 2)"
    Const xlAscending = 1
    Const xlYes = 1
    Dim olkFld As Object, _
        olkLst As Object, _
        olkRes As Object, _
        olkApt As Object, _
        olkRec As Object, _
        excApp As Object, _
        excWkb As Object, _
        excWks As Object, _
        lngRow As Long, _
        lngCnt As Long, _
        strFil As String, _
        strLst As String, _
        strDat As String, _
        datBeg As Date, _
        datEnd As Date, _
        arrTmp As Variant, _
        arrCal As Variant, _
        varCal As Variant
    strDat = InputBox("Enter the date range of the appointments to export in the form ""mm/dd/yyyy to mm/dd/yyyy""", SCRIPT_NAME, Date & " to " & Date)
    arrTmp = Split(strDat, "to")
    datBeg = IIf(IsDate(arrTmp(0)), arrTmp(0), Date) & " 12:00am"
    datEnd = IIf(IsDate(arrTmp(1)), arrTmp(1), Date) & " 11:59pm"
    Set excApp = CreateObject("Excel.Application")
    Set excWkb = excApp.Workbooks.Add()
    Set excWks = excWkb.Worksheets(1)
    'Write Excel Column Headers
    With excWks
        .Cells(1, 1) = "Calendar"
        .Cells(1, 2) = "Category"
        .Cells(1, 3) = "Subject"
        .Cells(1, 4) = "Starting Date"
        .Cells(1, 5) = "Ending Date"
        .Cells(1, 6) = "Start Time"
        .Cells(1, 7) = "End Time"
        .Cells(1, 8) = "Hours"
        .Cells(1, 9) = "Attendees"
    End With
    lngRow = 2
    arrCal = Split(CAL_LIST, ",")
    For Each varCal In arrCal
        Set olkFld = OpenOutlookFolder(CStr(varCal))
        If TypeName(olkFld) <> "Nothing" Then
            If olkFld.DefaultItemType = olAppointmentItem Then
                Set olkLst = olkFld.Items
                olkLst.Sort "[Start]"
                olkLst.IncludeRecurrences = True
                Set olkRes = olkLst.Restrict("[Start] >= '" & Format(datBeg, "ddddd h:nn AMPM") & "' AND [Start] <= '" & Format(datEnd, "ddddd h:nn AMPM") & "'")
                'Write appointments to spreadsheet
                For Each olkApt In olkRes
                    'Only export appointments
                    If olkApt.Class = olAppointment Then
                        strLst = ""
                        For Each olkRec In olkApt.Recipients
                            strLst = strLst & olkRec.Name & ", "
                        Next
                        If strLst <> "" Then strLst = Left(strLst, Len(strLst) - 2)
                        'Add a row for each field in the message you want to export
                        excWks.Cells(lngRow, 1) = olkFld.FolderPath
                        excWks.Cells(lngRow, 2) = olkApt.Categories
                        excWks.Cells(lngRow, 3) = olkApt.Subject
                        excWks.Cells(lngRow, 4) = Format(olkApt.Start, "mm/dd/yyyy")
                        excWks.Cells(lngRow, 5) = Format(olkApt.End, "mm/dd/yyyy")
                        excWks.Cells(lngRow, 6) = Format(olkApt.Start, "hh:nn ampm")
                        excWks.Cells(lngRow, 7) = Format(olkApt.End, "hh:nn ampm")
                        excWks.Cells(lngRow, 8) = DateDiff("n", olkApt.Start, olkApt.End) / 60
                        excWks.Cells(lngRow, 8).NumberFormat = "0.00"
                        excWks.Cells(lngRow, 9) = strLst
                        lngRow = lngRow + 1
                        lngCnt = lngCnt + 1
                    End If
                Next
            Else
                MsgBox "Operation cancelled.  The selected folder is not a calendar.  You must select a calendar for this macro to work.", vbCritical + vbOKOnly, SCRIPT_NAME
            End If
        Else
            MsgBox "I could not find a folder named " & varCal & ".  Folder skipped.  I will continue processing the remaining folders.", vbExclamation + vbOKOnly, SCRIPT_NAME
        End If
    Next
    excWks.Columns("A:I").AutoFit
    excWks.Range("A1:I" & lngRow - 1).Sort Key1:="Category", Order1:=xlAscending, Header:=xlYes
    excWks.Cells(lngRow, 8) = "=sum(H2:H" & lngRow - 1 & ")"
    excWkb.SaveAs EXCEL_FILE
    excWkb.Close
    MsgBox "Process complete.  I exported a total of " & lngCnt & " appointments were exported.", vbInformation + vbOKOnly, SCRIPT_NAME
    Set excWks = Nothing
    Set excWkb = Nothing
    Set excApp = Nothing
    Set olkApt = Nothing
    Set olkLst = Nothing
    Set olkFld = Nothing
End Sub

Private Function OpenOutlookFolder(strFolderPath As String) As Outlook.MAPIFolder
    ' Purpose: Opens an Outlook folder from a folder path.
    ' Written: 4/24/2009
    ' Author:  David Lee
    ' Outlook: All versions
    Dim arrFolders As Variant, _
        varFolder As Variant, _
        bolBeyondRoot As Boolean
    On Error Resume Next
    If strFolderPath = "" Then
        Set OpenOutlookFolder = Nothing
    Else
        Do While Left(strFolderPath, 1) = "\"
            strFolderPath = Right(strFolderPath, Len(strFolderPath) - 1)
        Loop
        arrFolders = Split(strFolderPath, "\")
        For Each varFolder In arrFolders
            Select Case bolBeyondRoot
                Case False
                    Set OpenOutlookFolder = Outlook.Session.Folders(varFolder)
                    bolBeyondRoot = True
                Case True
                    Set OpenOutlookFolder = OpenOutlookFolder.Folders(varFolder)
            End Select
            If Err.Number <> 0 Then
                Set OpenOutlookFolder = Nothing
                Exit For
            End If
        Next
    End If
    On Error GoTo 0
End Function

This revision requires a list of calendars to export. The list must be composed of the paths to the calendars Kimberly wants to export. In case Kimberly is not familiar with how Outlook folder paths work, here’s an explanation.

A folder path in Outlook is essentially the same as a folder path in the file system. The one difference being that Outlook folder paths do not include a drive letter. The path to a folder is a list of all the folders from the root to the target folder with each folder name separated from the preceding folder name by a backslash (i.e. \). Consider the following folder structure:

Mailbox - Doe, John
    - Calendar
    - Inbox
    - Tasks
Personal Folders
    + Marketing
        + Proposals
        + Reviews
    + Projects
        + Project 1
        + Project 2

The path to “Inbox” is “Mailbox – Doe, John\Inbox”.
The path to “Reviews” is “Personal Folders\Marketing\Reviews”.
The path to “Project 1” is “Personal Folders\Projects\Project 1”.

Revision 3.

This revision is for Phil at LightSpeed Fitness. Phil asked for a version that limits the export to only those appointments with a certain word or phrase in the subject line.

Phil will use the instructions from the original post to add the code to Outlook.

Sub ExportAppointmentsToExcel()
    Const SCRIPT_NAME = "Export Appointments to Excel (Rev 3)"
    Dim olkFld As Object, _
        olkLst As Object, _
        olkApt As Object, _
        excApp As Object, _
        excWkb As Object, _
        excWks As Object, _
        lngRow As Long, _
        lngCnt As Long, _
        strFil As String, _
        strFlt As String
    Set olkFld = Application.ActiveExplorer.CurrentFolder
    If olkFld.DefaultItemType = olAppointmentItem Then
        strFil = InputBox("Enter a filename (including path) to save the exported appointments to.", SCRIPT_NAME)
        If strFil <> "" Then
            strFlt = InputBox("Enter the string to search the subject for.", SCRIPT_NAME)
            If strFlt <> "" Then
                Set excApp = CreateObject("Excel.Application")
                Set excWkb = excApp.Workbooks.Add()
                Set excWks = excWkb.Worksheets(1)
                'Write Excel Column Headers
                With excWks
                    .Cells(1, 1) = "Subject"
                    .Cells(1, 2) = "Location"
                    .Cells(1, 3) = "Start Date"
                    .Cells(1, 4) = "End Date"
                    .Cells(1, 5) = "Start Time"
                    .Cells(1, 6) = "End Time"
                    .Cells(1, 7) = "Duration (Minutes)"
                End With
                lngRow = 2
                Set olkLst = olkFld.Items
                olkLst.Sort "[Start]"
                olkLst.IncludeRecurrences = True
                Set olkRes = olkLst.Restrict("@SQL=" & Chr(34) & "http://schemas.microsoft.com/mapi/proptag/0x0037001E" & Chr(34) & " ci_phrasematch " & "'" & strFlt & "'")
                'Write appointments to spreadsheet
                For Each olkApt In olkRes
                    'Only export appointments
                    If olkApt.Class = olAppointment Then
                        'Add a row for each field in the message you want to export
                        excWks.Cells(lngRow, 1) = olkApt.Subject
                        excWks.Cells(lngRow, 2) = olkApt.Location
                        excWks.Cells(lngRow, 3) = Format(olkApt.Start, "mm/dd/yyyy")
                        excWks.Cells(lngRow, 4) = Format(olkApt.End, "mm/dd/yyyy")
                        excWks.Cells(lngRow, 5) = Format(olkApt.Start, "hh:nn AMPM")
                        excWks.Cells(lngRow, 6) = Format(olkApt.End, "hh:nn AMPM")
                        excWks.Cells(lngRow, 7) = olkApt.Duration
                        lngRow = lngRow + 1
                        lngCnt = lngCnt + 1
                    End If
                Next
                excWks.Columns("A:G").AutoFit
                excWkb.SaveAs strFil
                excWkb.Close
                MsgBox "Process complete.  A total of " & lngCnt & " appointments were exported.", vbInformation + vbOKOnly, SCRIPT_NAME
            Else
                MsgBox "Operation cancelled.  You must enter a search term for this macro to work.", vbCritical + vbOKOnly, SCRIPT_NAME
            End If
        Else
            MsgBox "Operation cancelled.  You must enter a filename and path to save the exported appointments to.", vbCritical + vbOKOnly, SCRIPT_NAME
        End If
    Else
        MsgBox "Operation cancelled.  The selected folder is not a calendar.  You must select a calendar for this macro to work.", vbCritical + vbOKOnly, SCRIPT_NAME
    End If
    Set excWks = Nothing
    Set excWkb = Nothing
    Set excApp = Nothing
    Set olkApt = Nothing
    Set olkLst = Nothing
    Set olkFld = Nothing
End Sub

Revision 4.

I created this revision for a reader named Julien. Julien asked for a version that

  1. Is triggered by adding an appointment to a calendar
  2. Exports to an existing workbook (the solution should overwrite the workbook each time)
  3. Exports from the current date forward
  4. Only exports appointments belonging to a specified category

This version implements all four of those features. In addition to exporting each time Julien adds an item belonging to the triggering category, it will also export when he edits an item belonging to the category. Unfortunately, the code cannot detect when Julien deletes an item belonging to the category. To handle that, I’m giving Julien a way to manually run the export. If he deletes an item belonging to the category, then he can run the export himself. He’ll do that by running the ManualExport macro.

One caveat. This version only monitors the default calendar. If Julien needs to monitor some other calendar, then I’ll need to modify the code.

The code comes in two parts. This is part #1. Follow these instructions to add this part of the code to Outlook.

  1. Start Outlook
  2. Press ALT + F11 to open the Visual Basic Editor
  3. If not already expanded, expand Microsoft Office Outlook Objects
  4. Right-click on Class Modules, select InsertModule
  5. In the Properties panel click on Name and enter clsCalendarMonitor
  6. Copy the code from the code snippet box and paste it into the right-hand pane of Outlook’s VB Editor window
  7. Edit the code as needed. I included a comment where changes are needed or allowed.
  8. Click the diskette icon on the toolbar to save the changes
'On the next line, edit the number of calendar days to export starting with today
Const DAYS_TO_INCLUDE = 90
'On the next line, edit the path to the workbook the solution is to update
Const WORKBOOK_PATH = "c:\users\david\documents\testarea\julien.xlsx"
'On the next line, edit the name of the category to key on.  The solution will only export appointments that have this category applied.
Const CAT_NAME = "Testing"
Const SCRIPT_NAME = "Export Appointments to Excel (Rev 4)"

Private WithEvents olkFld As Outlook.Items

Private Sub Class_Initialize()
    Set olkFld = Session.GetDefaultFolder(olFolderCalendar).Items
End Sub

Private Sub Class_Terminate()
    Set olkFld = Nothing
End Sub

Private Sub olkFld_ItemAdd(ByVal Item As Object)
    If InStr(1, Item.Categories, CAT_NAME) > 0 Then
        ExportAppointmentsToExcel
    End If
End Sub

Private Sub olkFld_ItemChange(ByVal Item As Object)
    If InStr(1, Item.Categories, CAT_NAME) > 0 Then
        ExportAppointmentsToExcel
    End If
End Sub

Public Sub ExportAppointmentsToExcel()
    Dim olkLst As Object, _
        olkRes As Object, _
        olkApt As Object, _
        excApp As Object, _
        excWkb As Object, _
        excWks As Object, _
        lngRow As Long
    Set excApp = CreateObject("Excel.Application")
    Set excWkb = excApp.Workbooks.Open(WORKBOOK_PATH)
    Set excWks = excWkb.Worksheets(1)
    excWks.Range("A2:I" & excWks.UsedRange.rows.Count).rows.Delete
    lngRow = 2
    Set olkLst = olkFld
    olkLst.Sort "[Start]"
    olkLst.IncludeRecurrences = True
    Set olkRes = olkLst.Restrict("[Start] >= '" & VBA.Format(Now, "ddddd h:nn AMPM") & "' AND [Start] <= '" & VBA.Format(DateAdd("d", DAYS_TO_INCLUDE, Now), "ddddd h:nn AMPM") & "'")
    'Write appointments to spreadsheet
    For Each olkApt In olkRes
        'Only export appointments
        If olkApt.Class = olAppointment Then
            If InStr(1, olkApt.Categories, CAT_NAME) > 0 Then
                'Add a row for each field in the message you want to export
                excWks.Cells(lngRow, 1) = olkApt.Categories
                excWks.Cells(lngRow, 2) = olkApt.Subject
                excWks.Cells(lngRow, 3) = olkApt.Organizer
                excWks.Cells(lngRow, 4) = VBA.Format(olkApt.Start, "Short Date")
                excWks.Cells(lngRow, 5) = VBA.Format(olkApt.End, "Short Date")
                excWks.Cells(lngRow, 6) = VBA.Format(olkApt.Start, "Long Time")
                excWks.Cells(lngRow, 7) = VBA.Format(olkApt.End, "Long Time")
                excWks.Cells(lngRow, 8) = olkApt.RequiredAttendees
                excWks.Cells(lngRow, 9) = olkApt.OptionalAttendees
                lngRow = lngRow + 1
                lngCnt = lngCnt + 1
            End If
        End If
        DoEvents
    Next
    excWks.Columns("A:I").AutoFit
    excWkb.Close True
    Set excWks = Nothing
    Set excWkb = Nothing
    Set excApp = Nothing
    Set olkApt = Nothing
    Set olkLst = Nothing
End Sub

This is part #2 of the code. Follow these instructions to add this portion of the code to Outlook.

  1. If not already expanded, expand Microsoft Office Outlook Objects and click on ThisOutlookSession
  2. Copy the code from the code snippet box and paste it into the right-hand pane of Outlook’s VB Editor window
  3. Click the diskette icon on the toolbar to save the changes
  4. Close the VB Editor
  5. Click File and select Options
  6. When the Outlook Options dialog appears click Trust Center then click the Trust Center Settings button
  7. Click Macro Settings
  8. Select either of the two bottom settings (i.e. “Notifications for all macros” or “Enable all macros (not recommended; potentially dangerous code can run)”. The choice of which to choose is up to you. If you select “Notifications”, then you’ll be prompted at times to enable macros. If you pick “Enable all” then there’s a chance that a malicious macro could run. It’s a question of how much risk you want to assume.
  9. Click Ok until the dialog-boxes have all closed
  10. Close Outlook
  11. Start Outlook. If Outlook displays a dialog-box warning that ThisOutlookSession contains macros and asking if you want to allow them to run, say yes.
Dim objCM As clsCalendarMonitor

Private Sub Application_Quit()
    Set objCM = Nothing
End Sub

Private Sub Application_Startup()
    Set objCM = New clsCalendarMonitor
End Sub

Sub ManualExport()
    objCM.ExportAppointmentsToExcel
End Sub

495 comments on “Exporting Appointments from Outlook to Excel

  1. Sir, this code is awesome, it does what has been missing for me, i.e. expanding recurring events. I have spent the last three days trying to find it, and finally asked Google the right question, plus I got away from SharePoint and MS Access and started for Outlook to do it, which helped me find the code here, which, again is awesome.

    Ultimately, I will import the data into an Access database which is used for rendering scheduling reports, for further analysis. In order to support this, I need ONLY those appointments with recurrence set, I can’t seem to reference that field appropriately. Also, is there a “key” field or numerical value unique to each main appointment that could be returned?

    Respectfully,

    Jonathan French

    • Hi, Jonathan.

      Thanks!

      Appointment items have a property called IsRecurring which indicates whether the appointment is a recurring item or not. You can eliminate the non-recurring appointments with a test like

      If olkApt.IsRecurring Then
          'code to process recurring items goes here
      End If
      

      I’m not aware of a key field that points to the mater appointment in a series. All the items in the series should share the same ConversationIndex value and GlobalAppointmentID value (if you’re using Outlook 2013 or later). You can identify the master appointment by testing what type of item is its parent. Something like

      If TypeName(olkApt.Parent) = "MAPIFolder" Then
          'This is the master item in the series
      End If
      

      If the item is one of the recurrences, then TypeName will return “AppointmentItem”.

  2. Firstly can I start by thanking you for pulling this together, making it much easier for me to at least partly carry out the task I have been given – thank you.

    Secondly can I ask for advice regarding the Start Date/End Date – I have this code running, and when prompted for the dates I can input them, but the extract still contains dates outside of these? Its no hardship it just means the extraction is slow (due to the large volume of entries) and requires some post export manipulation. Any ideas on a solution would be greatly appreciated.

    Thirdly I would like to extract information from custom forms that are built into the appointment and I am all at sea with this one – I have searched for where the information might be saved, and looked for the names of the controls but currently I have no solution – again any assistance would be greatly appreciated.

    Regards

    Andrew.

    • Hi, Andrew.

      You’re welcome.

      Which version of the code are you using?

      What does “custom forms” mean in this context? Do you mean a custom Outlook form? If so, how is it “built into the appointment”? If not, please explain what type of form you’re talking about.

    • Apologies for being a little vague – I was using the second version you posted (Revision 1) and all appears well to start with. I get the message box requesting dates and input the dates that define the period I want information from – however the export to Excel contains all entries for the past 4 years and not those specific to the current financial/reporting year?

      With regard to the ‘custom forms’ these are custom fields added to additional pages within the appointment. The template appointment has been edited to capture these fields, however I am unable to retrieve the saved information. The template has been saved to the calendar folder of the shared mailbox with the imaginative title ‘Part VII Contact Form v4’ (not my naming convention I have inherited this).

      I have been looking for some script that might loop through the custom controls retrieving their name and then the contents – though anything would be a great help.

      Thanks again – Andrew.

    • Good morning, Andrew.

      I just ran Rev 1 on my computer and the date filter worked properly. Have you made any changes to the code? Are you entering the date in the correct format (i.e. mm/dd/yyyy)?

      To get the values of the custom controls we have to add code that reads the user-defined properties the controls are connected to. Open the custom form in the form editor and switch to the “All Fields” tab. There you’ll see a list of the user-defined fields in the form. For each user-defined field you’ll have to add this line of code to the macro.

      excWks.Cells(lngRow, x) = olkApt.UserProperties.Item("user-defined-property-name").Value
      

      where x is the column you want the value to appear in
      user-defined-property-name is the name of one of the user-defined properties in the form

    • David,

      I am not sure if you got my reply (posted last week?)

      In response to your questions I have the second version (1st revision) working, but the start/end dates don’t seem to be working for me – this isn’t the end of the world it must be said.

      The custom form, however, is a much more pressing task – the form has been created within the appointment (p.2 and p.3) and has a number of fields without any code in the background. the form itself is entitled ‘PartVII contact form v4’ and is saved in the ‘calendar’ folder of a shared mailbox. The controls on the form have the names ‘TextBox1’ etc but field names such as ‘Surname’.

      Any assistance would be appreciated.

    • Hi, Andrew.

      I saw your comment. Comment don’t become visible until I approve them, which I don’t normally do until I’m ready to respond. That allows me to keep track of which ones I haven’t replied to yet. Apologies if I seem to be taking a long time. I respond as time and energy permit.

    • David,

      Please accept my apologies – I was beginning to think I hadn’t responded and genuinely questioned myself as there was nothing in the thread to indicate my post was pending etc.

    • David,

      Again can I thank you for taking the time out to investigate and provide a response. I have added the line(s) of code as suggested and unfortunately I am getting a Run-time Error 91 Object variable or With block variable not set – I have checked the references and both Outlook and Excel Object Libraries are checked and I am reaching the limits of my understanding of vba sadly.

      Regards

      Andrew

  3. Hello, Hopefully this site is still reviewed…I was wondering if you can help update this code to allow for data from a table inserted into a meeting to be pulled.

    I manage a shared calendar that sets meetings and inside of that invite is a two column table (below)

    control number: 5454696
    Employee name: abcdefg
    Reason: Nursing

    There are also notes (always in red font) in the body of the e-mail, though not required exporting these as well would be helpful.

    If not can I also export sentences from the body that may include a specified keyword such as “representation?”

    Please advise and thanks in advance for any help!

  4. David, a noble thank you for all your contributions. Just learning Outlook VBAs and these are true gems. Based on your code was trying to export durations of Outlook calendar events which had a UserInput keyword X in either the title or location fields and split the results in 3x sheets (current month, previous month and month before the previous month)

    https://codepad.co/snippet/A8VyUaoV

    The excel gets created but my code gets stuck at identifying the current folder, do your wizard eyes see where the issue relies? And please set up a PayPal donation button so I can at least offer you a coffee =)

    • Hi, Juho.

      Thanks! I am a coffee lover, addict really, so I’ll definitely think about the donate button.

      There are a couple of problems, both a result of the code running from Excel instead of from Outlook. It’s okay to run this from Excel, but doing so means making some changes to the code.

      1. The code doesn’t define a value for olFolderCalendar (used on line 104). olFolderCalendar is an Outlook constant defined automatically in Outlook, but not defined by default in Excel. There are two ways to fix this. One is to add a reference to Outlook in your Excel project. The other is to define the constant yourself. The former is easier and by adding a reference you’ll save the need to define any other constants you might use. To add a reference, open the VB editor in Excel then click Tools, References. Scroll down through the list of references until you find “Microsoft Outlook xx.x Object Library” (where xx.x is a version number). Check the box next to that item and then click OK.
      2. The code on line 104 is also using the “Application” object. In Outlook, “Application” refers to Outlook itself. But in Excel, “Application” refers to Excel. The code will fail because Excel doesn’t have a “Session” object. Even if it did, it wouldn’t have a “GetDefaultFolder” method. Somewhere before line 104 you need to add code to create an instance of Outlook. Something like the code below.
      'Create an instance of Outlook 
      Set olkApp = CreateObject("Outlook.Application")
      'Create a session
      Set olkSes = olkApp.GetNameSpace("MAPI")
      'Log into Outlook using the default profile
      olkSes.Logon olkApp.DefaultProfileName
      

      With this code in place, change any Outlook reference to “Application” to olkApp. For example, olkApp.Session.GetDefaultFolder.

    • Hi David, thank you for the wise words! I did try to write the original code to be run from outlook, but still quite the beginner in this. I edited the code per your suggestions https://codepad.co/snippet/A8VyUaoV and activated the respective object library from excel, it now gives me error “variable not set” so I still probably need to revise the code. Would it be easier for me to edit the code to be run from outlook instead? For others reading this, I recommend checking out the Lynda.com VBA tutorials for self-study

  5. Hi David,

    It boggles my mind how easy you make it all sound; I am sure everyone must be very grateful.

    Would you be so kind and post another Revision? I need to pull data from two operative’s Outlook diary into multiple Excel work sheets (one for each operative for each month of the year).

    I need the subject, date, start time, finish time to be pointed to set columns on the Excel sheet.

    If this is at all possible I would greatly appreciate your response.

    Thank you very much in advance!

    Kind regards,

    Reka

    • Hi, Reka.

      I can help with this. Do you want all the sheets in the same workbook or in different workbooks (e.g. one workbook for each operative)? Do you want to export the entire calendar every time or do you want to limit the export to a date range each time?

  6. Great post! Thank you so much! Does anyone know, if there is a way to get Alias or SMTP Address of the organizer, instead of just the display name of the organizer (retrieved via AppointmentItem.organizer)? Any help will be greatly appreciated.

    • Hi, Ronu.

      Thanks!

      First, add this code to the code in the post.

      Function GetOrganizerAddress(strAdr As String) As String
          Dim olkRec As Outlook.recipient
          Set olkRec = Session.CreateRecipient(strAdr)
          olkRec.Resolve
          If olkRec.Resolved Then
              Select Case olkRec.AddressEntry.AddressEntryUserType
                  Case olExchangeUserAddressEntry
                      GetOrganizerAddress = olkRec.AddressEntry.GetExchangeUser.PrimarySmtpAddress
                  Case Else
                      GetOrganizerAddress = olkRec.AddressEntry.Address
              End Select
          End If
          Set olkRec = Nothing
      End Function
      

      Now, to get the organizer’s address instead of their name, change this line

      excWks.Cells(lngRow, 1) = olkApt.Organizer
      

      to

      excWks.Cells(lngRow, 1) = GetOrganizerAddress(olkApt.Organizer)
      
    • Hi, David,

      This worked like a charm. Thank you so much! You the man!
      I have another question for you. I want to exclude (do not want to export) the cancelled meetings. Do you know, if there is a way I can achieve it?

      I truly appreciate your efforts!

      Ronu

    • Hi, Ronu.

      You’re welcome!

      Cancelled meetings are normally removed from the calendar. Why would a cancelled meeting still be there?

    • Hi, David,

      Thank you for your prompt responses.

      I believe, the cancelled meetings are removed automatically if the auto attendant (auto-processing of meeting requests) is enabled on the mailbox. Else, one has to open the cancellation meeting notice received from the meeting’s organizer, and click “Remove from Calendar”.

    • Hi, Ronu.

      There are two ways to accomplish this. First, you can add an IF … THEN statement that checks the value of each item’s MeetingStatus property. If that property is not equal to olMeetingCanceled, then process it. Otherwise, ignore it. Something like this

      If olkApt.MeetingStatus <> olMeetingCanceled Then
          'code for writing to the spreadsheet goes here
      End If
      [code]
      
      Second, you can filter the records using a query.  Something like this
      
      [code]
      Set olkLst = olkFld.Items
      olkLst.Sort "[Start]"
      olkLst.IncludeRecurrences = True
      Set olkRes = olkLst.Restrict("[MeetingStatus] <> 5'")
      'Write appointments to spreadsheet
      For Each olkApt In olkRes
          'Code for writing to the spreadsheet goes here
      Next
      
    • Hi, David,

      Cool. Thank you so much. Let me try it. Again, I truly appreciate your prompt responses and great help!

    • Hi, David,

      I hope you are doing well.

      FYI, I tried “If olkApt.MeetingStatus olMeetingCanceled Then (to try to get rid of cancelled meetings), without luck. I will try again and see if I can figure out what I am missing where.

      I have another question for you. For the Const CAL_LIST, the name of multiple mailboxes needs to be separated by a comma. This works great if you do not have a comma in the display name of the mailbox, but presents a challenge if you have a comma in the display name. As a workaround, I have added the mailboxes as secondary accounts to the Outlook profile (instead of typical auto-mapping or adding additional mailbox(s) under Advanced tab in Outlook profile), so that the email address of the mailbox is shows in Outlook, instead of it’s display name. I wonder if there is a better way to handle it.

      Thank you,
      Ronu

    • Hi, Ronu.

      Since that didn’t eliminate the cancelled meetings, then are you sure they’re actually cancelled? Is it possible that the organizer just marked them as cancelled without actually cancelling them?

      You don’t have to use a comma as the separator for CAL_LIST. You can use some other character, you just need to change this line

      arrCal = Split(CAL_LIST, ",")
      

      to reflect the character you switch to. For example, if you switch to using the vertical bar (i.e. |) as the separator, then you’d change that line to

      arrCal = Split(CAL_LIST, "|")
      
    • Hi, David,

      Thank you for the response.

      In my test case, I sent a test invite from mailbox A to mailbox B. Accepted the invite in mailbox B. Then opened mailbox A and cancelled the meeting. Then I ran the macro (with the modification you suggested) in mailbox B and got the cancelled invite in the export. Actually, a cancelled meeting will not get removed from the recipient’s mailbox until you open the cancellation notification that’s received, and hit remove from Calendar.

      Your separator solution worked like a charm. Thank you so much!

      Any idea, how to add a message such as “Processing…” or something while the macro is being run? Just to let the user know that it’s being run.

      I truly appreciate your hard word!

      Ronu

    • Hi, Ronu.

      I could add code that displays a standard message-box to let the user know the macro is running, but there are a couple of problems with doing that. First, the message-box might appear behind another window. Not much point in a notification the user can’t see. If instead I force the message-box to appear in the foreground, then the macro will stop working until the user clears it. Another approach is to use a user-form. The code would display the user-form when the macro begins running and will clear it when the macro finishes. That’s a better approach but it adds an additional form object that would have to be added to any computer using the solution. Since the user has to take action to run the macro and the macro tells the user when it’s finished, shouldn’t the user already know that the macro is running in the intervening time? If so, then is there really a need for a visual reminder that the macro is running?

  7. HI David, thanks for your hard work on this topic. Revision 1 has proven to be invaluable for me as I have been tasked with creating some analytics surrounding meeting room utilization at my organization. I have heavily modified Rev 1 to pull meeting records from 26 shared meeting room calendars, but what is causing me problems are recurring appointments.

    While the code will get recurring appointments, every instance of the appointment will have the same start and end dates. For instance, a meeting that is recurring weekly from May 1st to December 31st will show up 35 times, as it should, all with the same start and end dates, which is should not. What I need is to see the meeting happening on May 1st, then May 8th, 15th, etc.

    I have searched high and low for code to get the actual start and end dates of an instance of the appointment rather than the entire set and I have found nothing that works. Do you know any code I could use to solve this problem?

    • Hi, Kevin.

      You’re welcome!

      Each iteration of a recurring appointment has its own start and end dates. When I run the code here that’s what I get in the spreadsheet, a different start and end for each iteration. Can you share your modified code with me? If so, perhaps I can figure out what’s going on.

    • I wanted to follow up and say that I solved my issue with the recurring dates. It still doesn’t make sense to me why it was happening, but if I grab the organizer field AFTER I get the other fields (subject, start, end, creationTime), then I got the correct start and end dates for each instance of the recurring appointment. The same issue seems to happen if I grabbed the list of attendees before the start and end columns.

  8. Thanks for your great work!

    I think i have the same Problem as <> posted earlier, he got always 0 appointments. nevertheless he commented that he found the solution… “I was able to find the solution, it is working, a little messy but it works.”. Do you know how he did it?

    I would like to extract the appointments of our Meeting room on a specific date. The Meeting room is listed in our Companys outlook adress book, like other People are.

    Could you please help me?

    • Hi, MT.

      You’re welcome!

      No, I’ve no idea what he did to solve the problem he was having. Which version of the code are you trying to use, where is the calendar you’re trying to export (i.e. is it a calendar in your mailbox, someone else’s mailbox, or in a public folder), and what version of Outlook are you using?

    • Thanks for your reply.

      I used the version “Export Appointments to Excel (Rev 1)”. Now it works with one calendar (other Person or room)… but when i mark more then one, just the appointments from the first one are exported.

      i think the calendar is in someone else’s mailbox? (not quite sure about that)

      I’m using outlook 2016

  9. Hi David,
    I like Yours solution esp.Revision 2. It’s work. But I need to use this for the Calendar Gruope whoch I have in my Outlook/calendar. Is it possible? Which path it vwill be in this case? I tryed but nothibg Accept. Actually I need this information from all Room in Our organisation (Exchange 2013).
    Thank you
    Best regards
    Elena

  10. Hi David,
    I like this solution esp Revision 2. It’s work. Bui I need to use this for en Calendar Groupe which I have in my calendar. Is it possible? Which path it must be in this case? Actually I need collect information from all Room in Exchange environment. Is it possible?
    Tnahk you.
    Best regards Elena

  11. David- This post is excellent!!! I can’t thank you enough as your contributions as open source is truly commendable.

    I started looking to analyze my time spent in meetings over the last few months as i started facing Bandwidth concerns. It has been ages since i had my hands active on VBA macros and landing your page seriously brought an instant smile! Thank you!

    Could you please help me with specific syntax for the below, while i explain why i need them alongside?
    1. read the outlook appointments as ‘Accepted’ or ‘Tentative’…there is high likelihood that i havent attended the ‘Tentative’ ones if still exist in my calendar. So, i would like to ignore them from my analysis

    2. help me read from the attendees list, to classify as few (individual ids of internal employees), many (invite sent to a Distribution list that appear as @xx), client (that involve mail ids that doesnt look as internal (last name, first name)

    3. how do i have read the user mail using the macro than asking the user to enter. In my case, while i could see my name as ‘s, kathiravan’, I would prefer this be read automatically by the code while exporting these from outlook…this will help me analyze if i’m ‘Required’ or ‘Optional’

    Thanks.

    KT

    • Hi, KT.

      Thank you for those very kind comments.

      1. What about meetings where you are the organizer? Do you want to ignore them altogether?
      2. How do you want to handle meetings that are a mixture of those categories? For example, a meeting that has both internal employees and a distribution list?
      3. Read what user email? The email of the organizer, the recipients, both, or something else? If you’re trying to determine which meetings have you listed as “Required” or “Optional”, then the code can determine that by looking for your name in the RequiredAttendees or OptionalAttendees properties.
  12. David,

    I am not sure if my last message went through. I still would prefer a report that automates to add new data to the spreadsheet, but I haven’t been able to figure out how to do that.

    This is my most recent code. I tried to add a column for color category to the macro, but I keep getting a 438 error. I think I might be using the wrong reference property or enumeration. Is it possible that I cannot access this through VBA because I do not have editorial access to the calendar? It is a shared folder and I have view only permission.

    Sub ExportAppointmentsToExcel()
    Const SCRIPT_NAME = “Export Appointments to Excel”
    Const xlAscending = 1
    Const xlYes = 1
    Dim olkFld As Object, _
    olkLst As Object, _
    olkRes As Object, _
    olkApt As Object, _
    olkRec As Object, _
    excApp As Object, _
    excWkb As Object, _
    excWks As Object, _
    lngRow As Long, _
    lngCnt As Long, _
    strFil As String, _
    strLst As String, _
    strDat As String, _
    datBeg As Date, _
    datEnd As Date, _
    arrTmp As Variant
    Set olkFld = Application.ActiveExplorer.CurrentFolder
    If olkFld.DefaultItemType = olAppointmentItem Then
    strDat = InputBox(“Enter the date range of the appointments to export in the form “”mm/dd/yyyy to mm/dd/yyyy”””, SCRIPT_NAME, Date & ” to ” & Date)
    arrTmp = Split(strDat, “to”)
    datBeg = IIf(IsDate(arrTmp(0)), arrTmp(0), Date) & ” 12:00am”
    datEnd = IIf(IsDate(arrTmp(1)), arrTmp(1), Date) & ” 11:59pm”
    strFil = InputBox(“Express Calendar.xls”, SCRIPT_NAME)
    If strFil “” Then
    Set excApp = CreateObject(“Excel.Application”)
    Set excWkb = excApp.Workbooks.Add()
    Set excWks = excWkb.Worksheets(1)
    ‘Write Excel Column Headers
    With excWks
    .Cells(1, 1) = “Category”
    .Cells(1, 2) = “Organizer”
    .Cells(1, 3) = “Created”
    .Cells(1, 4) = “Subject”
    .Cells(1, 5) = “Location”
    .Cells(1, 6) = “Start”
    .Cells(1, 7) = “End”
    .Cells(1, 8) = “Required”
    .Cells(1, 9) = “Optional”
    .Cells(1, 10) = “Recurring”
    End With
    lngRow = 2
    Set olkLst = olkFld.Items
    olkLst.Sort “[Start]”
    olkLst.IncludeRecurrences = True
    Set olkRes = olkLst.Restrict(“[Start] >= ‘” & Format(datBeg, “ddddd h:nn AMPM”) & “‘ AND [Start] <= '" & Format(datEnd, "ddddd h:nn AMPM") & "'")
    'Write appointments to spreadsheet
    For Each olkApt In olkRes
    'Only export appointments
    If olkApt.Class = olAppointment Then
    strLst = ""
    For Each olkRec In olkApt.Recipients
    strLst = strLst & olkRec.Name & ", "
    Next
    If strLst “” Then strLst = Left(strLst, Len(strLst) – 2)
    ‘Add a row for each field in the message you want to export
    excWks.Cells(lngRow, 1) = olkApt.olCategoryColorGreen
    excWks.Cells(lngRow, 2) = olkApt.Organizer
    excWks.Cells(lngRow, 3) = olkApt.CreationTime
    excWks.Cells(lngRow, 4) = olkApt.Subject
    excWks.Cells(lngRow, 5) = olkApt.Location
    excWks.Cells(lngRow, 6) = olkApt.Start
    excWks.Cells(lngRow, 7) = olkApt.End
    excWks.Cells(lngRow, 8) = olkApt.RequiredAttendees
    excWks.Cells(lngRow, 9) = olkApt.OptionalAttendees
    excWks.Cells(lngRow, 10) = olkApt.IsRecurring
    lngRow = lngRow + 1
    intCnt = intCnt + 1
    End If
    Next
    excWks.Columns(“A:I”).AutoFit
    excWkb.SaveAs strFil
    excWkb.Close
    MsgBox “Process complete. A total of ” & intCnt & ” appointments were exported.”, vbInformation + vbOKOnly, SCRIPT_NAME
    End If
    Else
    MsgBox “Operation cancelled. The selected folder is not a calendar. You must select a calendar for this macro to work.”, vbCritical + vbOKOnly, SCRIPT_NAME
    End If
    Set excWks = Nothing
    Set excWkb = Nothing
    Set excApp = Nothing
    Set olkApt = Nothing
    Set olkLst = Nothing
    Set olkFld = Nothing
    End Sub

    • Hi, Kristin.

      Yes, I saw your other post. Posts don’t become visible until I approve them and I don’t normally do that until I’m ready to respond to the post.

      To get the categories change this line

      excWks.Cells(lngRow, 1) = olkApt.olCategoryColorGreen
      

      to

      excWks.Cells(lngRow, 1) = olkApt.olCategories
      
  13. I am a real newbie at this! I currently using version 1 and modified it just a bit. I want it to update when I open the excel workbook instead of outlook and I want it to simply insert new rows for new data, rather than overwrite the file by running the macro through VBA with the calendar open. Can you help me achieve this?

    Sub ExportAppointmentsToExcel()
        Const SCRIPT_NAME = "Export Appointments to Excel"
        Dim olkFld As Object, _
            olkLst As Object, _
            olkApt As Object, _
            excApp As Object, _
            excWkb As Object, _
            excWks As Object, _
            lngRow As Long, _
            intCnt As Integer
        Set olkFld = Application.ActiveExplorer.CurrentFolder
        If olkFld.DefaultItemType = olAppointmentItem Then
            strFilename = InputBox("C:\Users\kguthrie\Desktop\Express Calendar.xls", SCRIPT_NAME)
            If strFilename  "" Then
                Set excApp = CreateObject("Excel.Application")
                Set excWkb = excApp.Workbooks.Add()
                Set excWks = excWkb.Worksheets(1)
                'Write Excel Column Headers
                With excWks
                    .Cells(1, 1) = "Organizer"
                    .Cells(1, 2) = "Created"
                    .Cells(1, 3) = "Subject"
                    .Cells(1, 4) = "Location"
                    .Cells(1, 5) = "Start"
                    .Cells(1, 6) = "End"
                    .Cells(1, 7) = "Required"
                    .Cells(1, 8) = "Optional"
                End With
                lngRow = 2
                Set olkLst = olkFld.Items
                olkLst.Sort "[Start]"
                olkLst.IncludeRecurrences = True
                'Write appointments to spreadsheet
                For Each olkApt In Application.ActiveExplorer.CurrentFolder.Items
                    'Only export appointments
                    If olkApt.Class = olAppointment Then
                        'Add a row for each field in the message you want to export
                        excWks.Cells(lngRow, 1) = olkApt.Organizer
                        excWks.Cells(lngRow, 2) = olkApt.CreationTime
                        excWks.Cells(lngRow, 3) = olkApt.Subject
                        excWks.Cells(lngRow, 4) = olkApt.Location
                        excWks.Cells(lngRow, 5) = olkApt.Start
                        excWks.Cells(lngRow, 6) = olkApt.End
                        excWks.Cells(lngRow, 7) = olkApt.RequiredAttendees
                        excWks.Cells(lngRow, 8) = olkApt.OptionalAttendees
                        lngRow = lngRow + 1
                        intCnt = intCnt + 1
                    End If
                Next
                excWks.Columns("A:F").AutoFit
                excWkb.SaveAs strFilename
                excWkb.Close
                MsgBox "Process complete.  A total of " &amp; intCnt &amp; " appointments were exported.", vbInformation + vbOKOnly, SCRIPT_NAME
            End If
        Else
            MsgBox "Operation cancelled.  The selected folder is not a calendar.  You must select a calendar for this macro to work.", vbCritical + vbOKOnly, SCRIPT_NAME
        End If
        Set excWks = Nothing
        Set excWkb = Nothing
        Set excApp = Nothing
        Set olkApt = Nothing
        Set olkLst = Nothing
        Set olkFld = Nothing
    End Sub
    
    • Hi, Kristin.

      Yes, I can help with this. Before doing so though, you need to decide on some sort of limit for the export. By “limit” I mean some condition that restricts the appointments being exported on each run. For example, you might want to limit the export to just those appointments that have a start date greater than the start dart of the last export. If you don’t establish a limit, then the solution is going to export every appointment on every run. If the target calendar has 1,000 appointments, then every time you open the spreadsheet it’s going to export those same 1,000 appointments. That doesn’t strike me as being very useful.

    • So, what I have done is I have created a file that I am overwriting, and then turned that excel file (Express Calendar.xls) into a dqy and then an odc file connection to another spreadsheet with a table (Data – Express Plan Review Calendar.xls) that will I plan to create pivots from for the analytics. Right now, the entire data set overwrites to the original file. Its not a bad way of doing it…. but I would rather use a simple odbc data connection that will populate the data directly to the workbook I will be working in (Data – Express Plan Review Calendar.xls).

      I have added this code for the date range, but for some reason it is not pulling data past 5/24 when I ran the VBA this morning. I want the data to refresh with all old appointments and any new appointments out 4 weeks from today.

      strDat = InputBox(“07/01/2014 to 06/01/2016″, SCRIPT_NAME, Date & ” to ” & Date)
      arrTmp = Split(strDat, “to”)
      datBeg = IIf(IsDate(arrTmp(0)), arrTmp(0), Date) & ” 12:00am”
      datEnd = IIf(IsDate(arrTmp(1)), arrTmp(1), Date) & ” 11:59pm”
      strFilename = InputBox(“Express Calendar.xls”, SCRIPT_NAME)

    • Hi, Kristin.

      In your first post you mentioned wanting to “insert new rows for new data”. Are you saying that you’ve changed your mind and want to overwrite each time?

    • No. I have just developed work arounds so I can access the data. I also just realized that I need to include a column that shows categories. The events on the calendar are categorized by color which correlates with appointment types.

  14. I’m just looking to export dates days with no appointment between 9:00 and 17:00 on a period of 2 months from the date excluding Saturdays and Sundays and send the result to the clipboard
    Is that possible for you?

    Thank you

    • Hello,

      Thank you for your reply
      I would like a DD / MM / YYYY , followed by a carriage return all classified in ascending order
      example:
      28/04/2016
      29/04/2016
      02//042016
      …..

      cordially

    • Hi, just poking my nose in as I follow this forum with interest.

      deboyo wants the dates with NO appointments, hence there is nothing else to provide as they are empty periods.

  15. Hi David,

    Sorry for this late reply, but was really busy with my coding which is still not finished. I am making a new comment instead of replying in old comment.

    I am sharing my almost final code which is combination of different codes from internet and yours.

    Now I have a small issue with it, Everything is working good, but when I have freshly booting my computer and when I run the code the first time, it take like 5 minutes to get data and outlook stop to react.

    I also see a small popup in task bar saying Outlook is trying to connect to exchange server etc….

    But when I ran the 2nd time it take 1 second to bring all data. In both cases my Outlook was Open. I repeated the above scenario 100 times and it is always same.

    I will appreciate if you could help debug my code and tell my a way to accelerate things. It is really annoying to have to wait 5 minutes just to pull data from outlook.

    Thanks in advance

    Here is the code (modified some part which were confidentials) :

    Sub GetApptsFromOutlook()
    
    Dim SDate As Date
    Dim EDate As Date
    
    SDate = Format(Now, "yyyy/mm/dd")
    'EDate = SDate + 1
    
    Application.ScreenUpdating = False
      Call GetCalData(SDate, SDate)
    Application.ScreenUpdating = True
    End Sub
      
    Private Sub GetCalData(StartDate As Date, Optional EndDate As Date)
    
    ' -------------------------------------------------
    ' Notes:
    ' If Outlook is not open, it still works, but much slower (~8 secs vs. 2 secs w/ Outlook open).
    ' Make sure to reference the Outlook object library before running the code
    ' End Date same as Start if you want to pull from only one day
    ' -------------------------------------------------
    Dim myCalItems As Object
    Dim ItemstoCheck As Object
    Dim ThisAppt As Object
    Dim MyItem As Object
    Dim StringToCheck As String
    Dim MyBook As Workbook
    Dim rngStart As Range
    Dim NextRow As Long
    Dim oNs As Namespace
    Dim mpiFolder As MAPIFolder
    Dim LastRow
    Dim LastRow2
    
     
      
    
    
    Worksheets("Temp2").Visible = True
    Worksheets("Temp2").Activate
    'clean up
    Cells.Select
    Selection.Delete Shift:=xlUp
    Range("A1").Select
     
    On Error Resume Next
        
        Set oNs = Outlook.GetNamespace("MAPI")
       
        Set mpiFolder = oNs.GetDefaultFolder(olPublicFoldersAllPublicFolders)
        Set mpiFolder = oNs.GetDefaultFolder(olPublicFoldersAllPublicFolders).Folders("my company ").Folders("Departement - Calendrier")
        Set myCalItems = mpiFolder.Items
    
    With myCalItems
      .Sort "[Start]", False
      .IncludeRecurrences = True
    End With
    
    StringToCheck = "[End] &gt;= " &amp; Quote(StartDate &amp; " 00:01") &amp; " AND [Start]  0 Then
      ' we found at least one appt
     ' check if there are actually any items in the collection, otherwise exit
     If ItemstoCheck.Item(1) Is Nothing Then GoTo ExitProc
      Set MyBook = ThisWorkbook
      Set rngStart = Worksheets("Temp2").Range("A1")
      With rngStart
        .Offset(0, 2).Value = "End Time"
        .Offset(0, 1).Value = "Start Time"
        .Offset(0, 0).Value = "Subject"
    
    
     End With
    
      For Each MyItem In ItemstoCheck
    
         Set ThisAppt = MyItem
        NextRow = Range("A" &amp; Rows.count).End(xlUp).Row
    
    With rngStart
    .Offset(NextRow, 2).Value = Format(ThisAppt.End, "YYYY/MM/DD hh:mm")
    .Offset(NextRow, 1).Value = Format(ThisAppt.Start, "YYYY/MM/DD hh:mm")
    .Offset(NextRow, 0).Value = Trim(ThisAppt.Subject)
        
         End With
      Next MyItem
    Else
        MsgBox "There are no appointments or meetings during" &amp; _
          "the time you specified. Exiting now.", vbCritical
          Exit Sub
    End If
    ExitProc:
    Set myCalItems = Nothing
    Set ItemstoCheck = Nothing
    Set rngStart = Nothing
    Set ThisAppt = Nothing
    Set oNs = Nothing
    Set mpiFolder = Nothing
    
    
    
    End Sub
    
    Function Quote(MyText)
        Quote = Chr(34) &amp; MyText &amp; Chr(34)
    End Function
    
    • Hi, JhonP.

      There’s too much code missing for me to figure out what is going on. For example, the code references an object named Outlook on line 48, but I don’t see where that object is created. Line 59 builds what I assume is the filter you apply to the calendar, but I do not see a Find or Restrict applying it. Lines 85 and 89 suggest that there is an IF statement someone above them, but the only IF statement I see is on line 62 and it is a complete IF … THEN clause.

      The above aside, my best guess is that the first run forcing Outlook to query the server. That run probably synchronizes the information to the local computer and all subsequent runs hit the copy on the local computer. Here is a test to try that might confirm my hypothesis. Open Outlook then open the public calendar. Do something on the calendar (for example open an item). Now run the code and see how long it takes. I am thinking that opening the calendar and doing something on it will force Outlook to read and cache the calendar. If it does, then the first run should be much faster.

    • Thanks for the tip, I will test it tomorrow as for now even after rebooting it is fast, I think it is just the first run of morning. So if the issue the synchronization, what should I do to make it quicker for 1st run ? anything to put in code ?

      I don’t understand why there are missing parts in my post I just copy pasted, only thing I modified was calendar and company name.

      Here is code again I hope this time you can get it in full, otherwise tell me how to share it

      Sub GetApptsFromOutlook()

      Dim SDate As Date
      Dim EDate As Date

      SDate = Format(Now, “yyyy/mm/dd”)
      ‘EDate = SDate + 1

      Application.ScreenUpdating = False
      Call GetCalData(SDate, SDate)
      Application.ScreenUpdating = True
      End Sub

      Private Sub GetCalData(StartDate As Date, Optional EndDate As Date)

      ‘ ————————————————-
      ‘ Notes:
      ‘ If Outlook is not open, it still works, but much slower (~8 secs vs. 2 secs w/ Outlook open).
      ‘ Make sure to reference the Outlook object library before running the code
      ‘ End Date same as Start if you want to pull from only one day
      ‘ ————————————————-
      Dim myCalItems As Object
      Dim ItemstoCheck As Object
      Dim ThisAppt As Object
      Dim MyItem As Object
      Dim StringToCheck As String
      Dim MyBook As Workbook
      Dim rngStart As Range
      Dim NextRow As Long
      Dim oNs As Namespace
      Dim mpiFolder As MAPIFolder
      Dim LastRow
      Dim LastRow2

      Worksheets(“Temp2”).Visible = True
      Worksheets(“Temp2”).Activate
      ‘clean up
      Cells.Select
      Selection.Delete Shift:=xlUp
      Range(“A1”).Select

      On Error Resume Next

      Set oNs = Outlook.GetNamespace(“MAPI”)

      Set mpiFolder = oNs.GetDefaultFolder(olPublicFoldersAllPublicFolders)
      Set mpiFolder = oNs.GetDefaultFolder(olPublicFoldersAllPublicFolders).Folders(“my company “).Folders(“Departement – Calendrier”)
      Set myCalItems = mpiFolder.Items

      With myCalItems
      .Sort “[Start]”, False
      .IncludeRecurrences = True
      End With

      StringToCheck = “[End] >= ” & Quote(StartDate & ” 00:01″) & ” AND [Start] 0 Then
      ‘ we found at least one appt

      ‘ check if there are actually any items in the collection, otherwise exit
      If ItemstoCheck.Item(1) Is Nothing Then GoTo ExitProc
      Set MyBook = ThisWorkbook
      Set rngStart = Worksheets(“Temp2”).Range(“A1”)
      With rngStart
      .Offset(0, 2).Value = “End Time”
      .Offset(0, 1).Value = “Start Time”
      .Offset(0, 0).Value = “Subject”

      End With

      For Each MyItem In ItemstoCheck

      Set ThisAppt = MyItem
      NextRow = Range(“A” & Rows.count).End(xlUp).Row

      With rngStart
      .Offset(NextRow, 2).Value = Format(ThisAppt.End, “YYYY/MM/DD hh:mm”)
      .Offset(NextRow, 1).Value = Format(ThisAppt.Start, “YYYY/MM/DD hh:mm”)
      .Offset(NextRow, 0).Value = Trim(ThisAppt.Subject)

      End With
      Next MyItem
      Else
      MsgBox “There are no appointments or meetings during” & _
      “the time you specified. Exiting now.”, vbCritical
      Exit Sub
      End If
      ExitProc:
      Set myCalItems = Nothing
      Set ItemstoCheck = Nothing
      Set rngStart = Nothing
      Set ThisAppt = Nothing
      Set oNs = Nothing
      Set mpiFolder = Nothing

      End Sub

      Function Quote(MyText)
      Quote = Chr(34) & MyText & Chr(34)
      End Function

    • Hi, JhonP.

      If the issue is synchronization, then there is no code-based solution, or none that I know of. Follow the steps in the this Microsoft article to make sure that you are caching the public folder in question to your computer. If the folder is being cached, then I don’t know of any way to speed up the synchronization process.

    • Hi, John.

      If Outlook isn’t using cached mode, then every read operation takes place across that network. That’s going to be slow. You should consider enabling cached mode if possible.

  16. Hi David,

    You code is awesome. I adopt it for a project I am working on and try to figure how to get this to work against a collection of PST files. I basically need to export calendar items from each of the PST files into an excel file.. I am a little fuzzy as to how to open PST files instead of outlook folder.
    Thanks so much

    • Hi, Sakura.

      Thank you!

      For calendars in multiple PST files I recommend that you use Revision 2. It’s written to take a list of calendars and export each member in that list. The list of calendars is defined on line #3. For each calendar you need the path to the calendar. For calendars in a PST file that path would be something like “PSTFile\Calendar,PSTFile\Calendar” where “PSTFile” is the name of the PST file as it appears in Outlook.

  17. Congratulations, David. This is a very useful post!

    Although I’m just a beginner in the Visual Basic world, mainly in Excel, and not in Outlook, I’ve been trying to work from your code. But, as I’m a beginner, I’ve got stuck, and that’s why maybe I’m going to ask some easy questions. Excuseme for that, but I’d be very grateful if you could help me. To begin with, I would point these three main doubts:

    1. What I need is to build a code mix of the previous you provided. I’d like to export several calendars appointments, shared only with read permission. Is that possible? I haven’t been able to identify what the folder path should be in this case. I have used version 1 with this kind of calendars and it works, so I guess it could be possible, but can’t find the proper path.

    2. As I’m Spanish, the format of the dates is different (dd/mm/yyyy). I’d like to change this, because I’d like to use the feature of the Rev 1 to consider only the appointments falling within a date range, but the format is driving me mad: not only in the dialog-box caption, but also in the interpretation made from the original data (the results exported are not well-formated about the date). Could you help me on this?

    3. On the other hand, I’d like to extract only certain appointments identified by a certain text String in the subject field.

    All this information should be exported to the same excel file every time the macro is executed, rewritting the previous.

    Could you help me with the code or at least give me any hint to keep on working on it?

    Thank you very much in advance!

    • Hi, jajugon.

      Thanks!

      1. Are the appointments on another user’s calendar or are they on a calendar in a public folder?
      2. I can change the date formatting.
      3. That’s simple enough. All we need to do is add an “IF … THEN” statement to filter on the subject.

      The code below takes care of items 2 and 3. Let me know the answer to my question about your first item and I’ll make the necessary adjustments to handle that too.

      Sub ExportAppointmentsToExcel()
          'on the next line edit the text you want to filter the subject on.  The comparison is case sensitive.
          Const FILTER_TEXT = "Some text"
          Const SCRIPT_NAME = "Export Appointments to Excel (Rev 1)"
          Const xlAscending = 1
          Const xlYes = 1
          Dim olkFld As Object, _
              olkLst As Object, _
              olkRes As Object, _
              olkApt As Object, _
              olkRec As Object, _
              excApp As Object, _
              excWkb As Object, _
              excWks As Object, _
              lngRow As Long, _
              lngCnt As Long, _
              strFil As String, _
              strLst As String, _
              strDat As String, _
              datBeg As Date, _
              datEnd As Date, _
              arrTmp As Variant
          Set olkFld = Application.ActiveExplorer.CurrentFolder
          If olkFld.DefaultItemType = olAppointmentItem Then
              strDat = InputBox("Enter the date range of the appointments to export in the form ""dd/mm/yyyy to dd/mm/yyyy""", SCRIPT_NAME, Date & " to " & Date)
              arrTmp = Split(strDat, "to")
              datBeg = IIf(IsDate(arrTmp(0)), arrTmp(0), Date) & " 12:00am"
              datEnd = IIf(IsDate(arrTmp(1)), arrTmp(1), Date) & " 11:59pm"
              strFil = InputBox("Enter a filename (including path) to save the exported appointments to.", SCRIPT_NAME)
              If strFil <> "" Then
                  Set excApp = CreateObject("Excel.Application")
                  Set excWkb = excApp.Workbooks.Add()
                  Set excWks = excWkb.Worksheets(1)
                  'Write Excel Column Headers
                  With excWks
                      .Cells(1, 1) = "Category"
                      .Cells(1, 2) = "Subject"
                      .Cells(1, 3) = "Starting Date"
                      .Cells(1, 4) = "Ending Date"
                      .Cells(1, 5) = "Start Time"
                      .Cells(1, 6) = "End Time"
                      .Cells(1, 7) = "Hours"
                      .Cells(1, 8) = "Attendees"
                  End With
                  lngRow = 2
                  Set olkLst = olkFld.Items
                  olkLst.Sort "[Start]"
                  olkLst.IncludeRecurrences = True
                  Set olkRes = olkLst.Restrict("[Start] >= '" & Format(datBeg, "ddddd h:nn AMPM") & "' AND [Start] <= '" & Format(datEnd, "ddddd h:nn AMPM") & "'")
                  'Write appointments to spreadsheet
                  For Each olkApt In olkRes
                      'Only export appointments
                      If olkApt.Class = olAppointment Then
                          If InStr(1, olkApt.Subject, FILTER_TEXT) > 0 Then
                              strLst = ""
                              For Each olkRec In olkApt.Recipients
                                  strLst = strLst & olkRec.Name & ", "
                              Next
                              If strLst <> "" Then strLst = Left(strLst, Len(strLst) - 2)
                              'Add a row for each field in the message you want to export
                              excWks.Cells(lngRow, 1) = olkApt.Categories
                              excWks.Cells(lngRow, 2) = olkApt.Subject
                              excWks.Cells(lngRow, 3) = Format(olkApt.Start, "dd/mm/yyyy")
                              excWks.Cells(lngRow, 4) = Format(olkApt.End, "dd/mm/yyyy")
                              excWks.Cells(lngRow, 5) = Format(olkApt.Start, "hh:nn ampm")
                              excWks.Cells(lngRow, 6) = Format(olkApt.End, "hh:nn ampm")
                              excWks.Cells(lngRow, 7) = DateDiff("n", olkApt.Start, olkApt.End) / 60
                              excWks.Cells(lngRow, 7).NumberFormat = "0.00"
                              excWks.Cells(lngRow, 8) = strLst
                              lngRow = lngRow + 1
                              lngCnt = lngCnt + 1
                          End If
                      End If
                  Next
                  excWks.Columns("A:H").AutoFit
                  excWks.Range("A1:H" & lngRow - 1).Sort Key1:="Category", Order1:=xlAscending, Header:=xlYes
                  excWks.Cells(lngRow, 7) = "=sum(G2:G" & lngRow - 1 & ")"
                  excWkb.SaveAs strFil
                  excWkb.Close
                  MsgBox "Process complete.  A total of " & lngCnt & " appointments were exported.", vbInformation + vbOKOnly, SCRIPT_NAME
              End If
          Else
              MsgBox "Operation cancelled.  The selected folder is not a calendar.  You must select a calendar for this macro to work.", vbCritical + vbOKOnly, SCRIPT_NAME
          End If
          Set excWks = Nothing
          Set excWkb = Nothing
          Set excApp = Nothing
          Set olkApt = Nothing
          Set olkLst = Nothing
          Set olkFld = Nothing
      End Sub
      
    • First of all, thank you very much.

      Answering the first point, the appointments are on another user’s calendar, which was shared with read permission.

      Willing to see if it works as I’d like 🙂

      Thanks again.

    • Hi, jajugon.

      Please select the other user’s calendar and then run the code. Let me know if that works. If it does, then we can optionally hard-code the path the other user’s calendar into the code so you don’t have to select it each time you run the script.

    • Great David! The code works!

      I’ve had some problems about the permissions needed to execute it on a shared calendar by other user, but I finally got it! Thanks a lot!

      As mentioned, I’d like to improve it selecting different calendars with a given path. Nevertheless, it would be more important to make the filter on the subject field no case sensitive. In fact I’d like to extract all the appointments whose subject field contains at least a certain text String.

      I’ll keep on searching through the Internet, but any hint will be very helpful!

      Thanks!

    • Hi, jajugon.

      To make the subject field search case insensitive change line 54 of the code from

      If InStr(1, olkApt.Subject, FILTER_TEXT) > 0 Then
      

      to

      If InStr(1, LCase(olkApt.Subject), LCase(FILTER_TEXT)) > 0 Then
      
    • Great David. Thank you very much again.

      Would you kindly tell me how to introduce the shared calendar path in the code?

      Thanks in advance.

    • Hi, jajugon.

      You need to make two changes to the existing code in order to hard code the path to the shared calendar into the solution. First, add this code to what you already have.

      Public Function OpenOutlookFolder(strFolderPath As String) As Outlook.MAPIFolder
          ' Purpose: Opens an Outlook folder from a folder path.'
          ' Written: 4/24/2009'
          ' Author:  David Lee'
          ' Outlook: All versions'
          Dim arrFolders As Variant, _
              varFolder As Variant, _
              bolBeyondRoot As Boolean
          On Error Resume Next
          If strFolderPath = "" Then
              Set OpenOutlookFolder = Nothing
          Else
              Do While Left(strFolderPath, 1) = "\"
                  strFolderPath = Right(strFolderPath, Len(strFolderPath) - 1)
              Loop
              arrFolders = Split(strFolderPath, "\")
              For Each varFolder In arrFolders
                  Select Case bolBeyondRoot
                      Case False
                          Set OpenOutlookFolder = Outlook.Session.Folders(varFolder)
                          bolBeyondRoot = True
                      Case True
                          Set OpenOutlookFolder = OpenOutlookFolder.Folders(varFolder)
                  End Select
                  If Err.Number <> 0 Then
                      Set OpenOutlookFolder = Nothing
                      Exit For
                  End If
              Next
          End If
          On Error GoTo 0
      End Function
      

      Second, change line 23 from

      Set olkFld = Application.ActiveExplorer.CurrentFolder
      

      to

      Set olkFld = OpenOutlookFolder("Path_to_shared_calendar")
      

      Replace “Path_to_shared_calendar” with the actual path to the shared calendar. If you aren’t familiar with Outlook folder paths, then the quickest way to get the folder path is to use the code below. Once you’ve added that code to Outlook, select the folder then run that macro. It will display the folder path in a dialog-box.

      Sub DisplayFolderPath()
          Const SCRIPT_NAME = "Display Folder Path"
          Dim olkFol As Outlook.MAPIFolder
          Set olkFol = Application.ActiveExplorer.CurrentFolder
          MsgBox "The path to the currently selected folder is " & vbCrLf & vbCrLf & olkFol.FolderPath, vbInformation + vbOKOnly, SCRIPT_NAME
          Set olkFol = Nothing
      End Sub
      
    • Thanks David.

      I have followed your indications, but when executing the code to obtain the path to the shared calendar I obtain a huge string as:

      “000000000BD9C1E9306442CEA56EDB2C1E4AB6E60C000000380000003800000036000000CD6BC6D801E5024AB98666A22076AA1047BFFBA458F59E4595A9AA82667EC0BE9D00000000000000DCA740C8C042101AB4B908002B2FE18201000000000000002F6F3D45786368616E6764C6162732F6F753D45786368616E”

      When I try to do the same with my own calendar I obtain a reasonable path like:

      “\\name.surname@domain.es\Calendar”

      I’ve even tried to replace the “Path_to_shared_calendar” value with the huge string, but I get an error anyway,

      Any idea?

      Thanks!

    • Hi, jajugon.

      This is a shared calendar in a another mailbox, right? Not one in a public folder?

    • No. Just want to make sure I have the facts right. Is it the default calendar in the other mailbox?

    • Okay. We need to change line #23 again. Change it from

      Set olkFld = OpenOutlookFolder("Path_to_shared_calendar")
      

      to

      'On the next line replace "Smith, John" with the name of the other mailbox
      Set olkRcp = Session.CreateRecipient("Smith, John")
      Set olkFld = Session.GetSharedDefaultFolder(olkRcp, olFolderCalendar)
      
  18. Hi,
    Thanks for sharing these code and nice to see you adopt them with people requests 🙂

    I hope you can help me too.

    First thing, I want the code to be in Excel and not Outlook. Because I have a macro that is ran in Excel and I want to bring info from Outlook Calendar.

    In one of My Excel sheet name Availabilty, I have name of people that are also in Global list of Outlook. When I run the macro in Excel I want the macro to bring for the TODAY date the schedule of each people in the list . Is this possible to do ?
    Thanks

    • Hi, John.

      You’re welcome!

      Do you have access to everyone’s calendar in Outlook? You must have for this to work in the way you’ve described.

    • By access you mean if I can open calendar of person and see his/her schedule ? Yes I do have that.

      Thanks in advance for your help 🙂

    • Ok we decided to have a Group Calendar in order to avoid giving access to everyone’s calendar to people who will run the Macro. So in this calendar we have schedule of each person. What I will need is bring info from this calendar called “Work Load” for Today date and put it in a Worksheet. Then I will do all other stuff by the Macro myself as data will be already in Excel. So no need to look for calendar of each person in Outlook anymore.

      Thanks again for all your help 🙂

    • Hi, John.

      Please try this version. It is written to run from Excel. Outlook must be open and the shared calendar selected before running this macro.

      Sub ExportAppointmentsFromOutlook()
          Const SCRIPT_NAME = "Export Appointments from Outlook"
          Const olAppointmentItem = 1
          Const olAppointment = 26
          Dim olkApp As Object, _
              olkFld As Object, _
              olkLst As Object, _
              olkFlt As Object, _
              olkApt As Object, _
              excWks As Object, _
              lngRow As Long, _
              intCnt As Integer, _
              datBeg As Date, _
              datEnd As Date
          Set olkApp = GetObject(, "Outlook.Application")
          Set olkFld = olkApp.ActiveExplorer.CurrentFolder
          If olkFld.DefaultItemType = olAppointmentItem Then
              strFilename = InputBox("Enter a filename (including path) to save the exported appointments to.", SCRIPT_NAME)
              If strFilename <> "" Then
                  datBeg = Date & " 12:00am"
                  datEnd = Date & " 11:59pm"
                  Set excWks = Application.ActiveSheet
                  lngRow = excWks.UsedRange.Rows.Count + 1
                  Set olkLst = olkFld.Items
                  olkLst.Sort "[Start]"
                  olkLst.IncludeRecurrences = True
                  Set olkFlt = olkLst.Restrict("[Start] >= '" & Format(datBeg, "ddddd h:nn AMPM") & "' AND [Start] <= '" & Format(datEnd, "ddddd h:nn AMPM") & "'")
                  'Write appointments to spreadsheet
                  For Each olkApt In olkFlt
                      'Only export appointments
                      If olkApt.Class = olAppointment Then
                          'Add a row for each field in the message you want to export
                          excWks.Cells(lngRow, 1) = olkApt.Organizer
                          excWks.Cells(lngRow, 2) = olkApt.CreationTime
                          excWks.Cells(lngRow, 3) = olkApt.Subject
                          excWks.Cells(lngRow, 4) = olkApt.Start
                          excWks.Cells(lngRow, 5) = olkApt.RequiredAttendees
                          excWks.Cells(lngRow, 6) = olkApt.OptionalAttendees
                          lngRow = lngRow + 1
                          intCnt = intCnt + 1
                      End If
                      DoEvents
                  Next
                  excWks.Columns("A:F").AutoFit
                  MsgBox "Process complete.  A total of " & intCnt & " appointments were exported.", vbInformation + vbOKOnly, SCRIPT_NAME
              End If
          Else
              MsgBox "Operation cancelled.  The selected folder is not a calendar.  You must select a calendar for this macro to work.", vbCritical + vbOKOnly, SCRIPT_NAME
          End If
          Set excWks = Nothing
          Set olkApt = Nothing
          Set olkLst = Nothing
          Set olkFld = Nothing
          Set olkApp = Nothing
      End Sub
      
    • Thanks David, No matter what Calendar I select (even my own) it give message 0 appointment were exported. (I have a lot of appointments in my calendar for today)

      Also isn’t there a way to give fix name for Calendar we want to extract data from ? As this will be use by multiple persons and Selecting manually will not be user friendly.

    • Hi, John.

      The code definitely works. I just tested again by running it against my calendar and it exported all of today’s appointments. Tell me more about your setup. What version of Windows are you using? What version of Outlook?

      Yes, we can hard-code the folder the solution is to export from into the code. Will the path be the same for every person or will it vary from one person to the next?

    • It is WIndows 7 Prof, Outlook and Excel 2010. Calendar is from Public folders, address seem to add my email address in it, so I believe with each user it will add their email address ?

      But your code I tested on my own default non shared calendar and it still say 0 appointments.

      I used the following code and it do bring all the data from my own default calendar

      Private Sub Get_Appoinments()

      Dim mybk As Workbook
      Dim FolderCal As Outlook.Folder
      Dim ItemsApt As Outlook.Items
      Dim appt As Outlook.AppointmentItem

      i = 1
      Set mybk = ThisWorkbook
      Set FolderCal = Outlook.Application.GetNamespace(“MAPI”).GetDefaultFolder(olFolderCalendar)
      Set ItemsApt = FolderCal.Items
      For Each appt In ItemsApt
      mybk.Sheets(1).Cells(i, 1) = appt.Start
      mybk.Sheets(1).Cells(i, 2) = appt.End
      mybk.Sheets(1).Cells(i, 3) = appt.Subject
      mybk.Sheets(1).Cells(i, 4) = appt.Location
      mybk.Sheets(1).Cells(i, 5) = appt.Duration
      mybk.Sheets(1).Cells(i, 6) = appt.Size
      ‘mybk.Sheets(1).Cells(i, 7) = appt.Body
      i = i + 1
      Next

      MsgBox “OutLook Appointments Retrieved”

      End Sub

    • Hi David.

      I posted a reply yesterday but for some reason it is not showing up,

      I am using Windows 7 Pro and Outlook and Excel 2010.

      Also I used another code that bring data from my defaul calendar and it is working with no issue. But your code give message 0 appointement exported

      here is the code that is wokring:

      Private Sub Get_Appoinments()

      Dim mybk As Workbook
      Dim FolderCal As Outlook.Folder
      Dim ItemsApt As Outlook.Items
      Dim appt As Outlook.AppointmentItem

      i = 1
      Set mybk = ThisWorkbook
      Set FolderCal = Outlook.Application.GetNamespace(“MAPI”).GetDefaultFolder(olFolderCalendar)

      Set ItemsApt = FolderCal.Items
      For Each appt In ItemsApt

      mybk.Sheets(1).Cells(i, 1) = appt.Start
      mybk.Sheets(1).Cells(i, 2) = appt.End
      mybk.Sheets(1).Cells(i, 3) = appt.Subject
      mybk.Sheets(1).Cells(i, 4) = appt.Location
      mybk.Sheets(1).Cells(i, 5) = appt.Duration
      mybk.Sheets(1).Cells(i, 6) = appt.Size
      mybk.Sheets(1).Cells(i, 7) = appt.Body
      i = i + 1

      Next

      MsgBox “OutLook Appointments Retrieved”

      End Sub

    • Hi, John.

      Replies don’t show up until I approve them. I don’t normally do that until I’m ready to respond.

    • Hi David,

      After doing hours and hours of search on Google I was able to have a code that is working, it is mix of your code and some other stuff from internet. Right now the code is complete mess as I have been testing it, so I can’t share the code here right now.

      I just have 1 issue that is making me pull my hair, as you are very good with VBA and Outlook I wonder if you can solve this issue then I willl do a cleanup of my code.

      When I use .Restrict to limit my appointment to just TODAY date, it works but it do not bring the appointments that are on multiple days. For example there is an employee who is on holidays from 12th March to 24th March, which fell into Today date, but the code is not listing this appointment. I tested by adding more multiday appointments and it never bring these appointments.

      Do you have any idea what to add to allow these appointment to be added in .Restrict too ?

      Thanks a lot for all your help 🙂

    • Hi, John.

      As I noted earlier, the code works perfectly for me. I don’t know why it’s not working on your computer. I’d be curious to see the version that is working so I can compare it to my version and see what the differences are.

      Here are the two lines of code you need to add to include recurring appointments. These lines go immediately before the .Restrict command.

      olkLst.Sort "[Start]"
      olkLst.IncludeRecurrences = True
      
    • I was able to find the solution, it is working, a little messy but it works.

      I will still be interested to see your code if you can post it.

      Thanks again for all your help 🙂

    • Hi,
      The functions on this page are excellent, I have am so close with a combination of a few of them. All I need to do is export all the items in approx 30 shared calendars. The one you did for Julien was close for me as I believe I need the line – Set olkFld = Session.GetFolderFromID(“String”).Items, as the folder name of the shared calendars is the long string of letters and numbers. The format it is exported into is not an issue, I just need to loop through all the calendars and export all the details.

      Is this one an easy fix? i have tried all day and am so close!

      Thanks 🙂

    • Hi, Gareth.

      Are you sure about wanting to use Rev 4, the version I created for Julien? It’s designed to export appointments as they’re created. Doing that for 30 shared calendars may not work very well.

    • First of all, thank you very much.

      Answering the first point, the appointments are on another user’s calendar, which was shared with read permission.

      Willing to see if it works as I’d like 🙂

      Thanks again.

    • Hi David, i found out that it was a shared calendar.

      Now it works, i used the Rev1 and replaced these code:

      <>
      with
      <>

      Thanks again!

  19. Hi David,

    Your code is very helpful. I used Revision 1, added a few columns and it’s working fine. Is it possible to add a column that indicates whether or not it is a recurring appointment?

    The code is as follows:
    Sub ExportAppointmentsToExcel()
    Const SCRIPT_NAME = “Export Appointments to Excel (Rev 1)”
    Const xlAscending = 1
    Const xlYes = 1
    Dim olkFld As Object, _
    olkLst As Object, _
    olkRes As Object, _
    olkApt As Object, _
    olkRec As Object, _
    excApp As Object, _
    excWkb As Object, _
    excWks As Object, _
    lngRow As Long, _
    lngCnt As Long, _
    strFil As String, _
    strLst As String, _
    strDat As String, _
    datBeg As Date, _
    datEnd As Date, _
    arrTmp As Variant
    Set olkFld = Application.ActiveExplorer.CurrentFolder
    If olkFld.DefaultItemType = olAppointmentItem Then
    strDat = InputBox(“Enter the date range of the appointments to export in the form “”mm/dd/yyyy to mm/dd/yyyy”””, SCRIPT_NAME, Date & ” to ” & Date)
    arrTmp = Split(strDat, “to”)
    datBeg = IIf(IsDate(arrTmp(0)), arrTmp(0), Date) & ” 12:00am”
    datEnd = IIf(IsDate(arrTmp(1)), arrTmp(1), Date) & ” 11:59pm”
    strFil = InputBox(“Enter a filename (including path) to save the exported appointments to.”, SCRIPT_NAME)
    If strFil “” Then
    Set excApp = CreateObject(“Excel.Application”)
    Set excWkb = excApp.Workbooks.Add()
    Set excWks = excWkb.Worksheets(1)
    ‘Write Excel Column Headers
    With excWks
    .Cells(1, 1) = “Organizer”
    .Cells(1, 2) = “Created”
    .Cells(1, 3) = “Subject”
    .Cells(1, 4) = “Starting Date”
    .Cells(1, 5) = “Ending Date”
    .Cells(1, 6) = “Start Time”
    .Cells(1, 7) = “End Time”
    .Cells(1, 8) = “Hours”
    .Cells(1, 9) = “Attendees”
    End With
    lngRow = 2
    Set olkLst = olkFld.Items
    olkLst.Sort “[Start]”
    olkLst.IncludeRecurrences = True
    Set olkRes = olkLst.Restrict(“[Start] >= ‘” & Format(datBeg, “ddddd h:nn AMPM”) & “‘ AND [Start] <= '" & Format(datEnd, "ddddd h:nn AMPM") & "'")
    'Write appointments to spreadsheet
    For Each olkApt In olkRes
    'Only export appointments
    If olkApt.Class = olAppointment Then
    strLst = ""
    For Each olkRec In olkApt.Recipients
    strLst = strLst & olkRec.Name & ", "
    Next
    If strLst “” Then strLst = Left(strLst, Len(strLst) – 2)
    ‘Add a row for each field in the message you want to export
    excWks.Cells(lngRow, 1) = olkApt.Organizer
    excWks.Cells(lngRow, 2) = olkApt.CreationTime
    excWks.Cells(lngRow, 3) = olkApt.Subject
    excWks.Cells(lngRow, 4) = Format(olkApt.Start, “mm/dd/yyyy”)
    excWks.Cells(lngRow, 5) = Format(olkApt.End, “mm/dd/yyyy”)
    excWks.Cells(lngRow, 6) = Format(olkApt.Start, “hh:nn ampm”)
    excWks.Cells(lngRow, 7) = Format(olkApt.End, “hh:nn ampm”)
    excWks.Cells(lngRow, 8) = DateDiff(“n”, olkApt.Start, olkApt.End) / 60
    excWks.Cells(lngRow, 8).NumberFormat = “0.00”
    excWks.Cells(lngRow, 9) = strLst
    lngRow = lngRow + 1
    lngCnt = lngCnt + 1
    End If
    Next
    excWks.Columns(“A:H”).AutoFit
    excWks.Range(“A1:I” & lngRow – 1).Sort Key1:=”Organizer”, Order1:=xlAscending, Header:=xlYes
    excWks.Cells(lngRow, 7) = “=sum(G2:G” & lngRow – 1 & “)”
    excWkb.SaveAs strFil
    excWkb.Close
    MsgBox “Process complete. A total of ” & lngCnt & ” appointments were exported.”, vbInformation + vbOKOnly, SCRIPT_NAME
    End If
    Else
    MsgBox “Operation cancelled. The selected folder is not a calendar. You must select a calendar for this macro to work.”, vbCritical + vbOKOnly, SCRIPT_NAME
    End If
    Set excWks = Nothing
    Set excWkb = Nothing
    Set excApp = Nothing
    Set olkApt = Nothing
    Set olkLst = Nothing
    Set olkFld = Nothing
    End Sub

    Thanks!

    • Hi, YHL.

      Yes, that’s possible. The property name you want is IsRecurring. For example

      excWks.Cells(lngRow, 10) = olkApt.IsRecurring
      
  20. Hi David,

    Great article indeed. It is not easy to find this topic so well described. At least for me this is the first one.

    Could you please advise if it’s possible to download details from shared calendars by Microsoft Exchange? I was trying to get path of one (using your macro from last comments). I got a long numeric something, which doesn’t seem to be a path.

    Unfortunately I’m not able to copy the calendars to my outlook, as there are some private items.

    I just know the manual walk-around for this (changing view to a list and copy pasting to Excel).

    Hope it has not been already discussed. I was trying to find the answer in comments, but I was not able to go through all of them.

    Kind regards,
    Wojtek

    • Hi, Wojtek.

      When you say “shared calendars” do you mean a calendar in a public folder? If not, what does “shared calendars” mean in this context?

    • Hi David,

      Exactly, I meant calendars in a public folder.

      In the folder list view I am able to locate PublicFolder_Calendars in Public Folders, however when I click on it the message “Cannot display the folder” appears.

      Nevertheless I can see all shared calendars in the Calendar view.

      Is it possible to automatically export data from public calendars to Excel file?

      Kind regards,
      Wojtek

    • Hi, Wojtek.

      Yes, the code will export from whatever calendar you have open when you run the macro.

  21. Hi, Great Post. I am not sure If I am incorrectly trying to utilize your code or if it is an enhancement but whenever I am using the code the events with one occurrence work great; however, the recurring events only pull the first instance. Is that a user issue or an enhancement request?

  22. David,

    Awsome information you posted. Thank you very much!! One question I had is that is it possible to export recurring calendar events to excel ?

    • Hi, Terry.

      Thanks!

      Yes. Assuming that you mean you want to export recurring events in addition to non-recurring events, then the code already does that. If instead you mean that you only want to export recurring events, then that’s possible too but I’ll need to make a change to the code to make that happen.

  23. David,
    Regarding my use of Revision 2….. I resolved the calendar path problem. It turns out I had to use a capital letter in Calendar when referencing it as part of the overall path…

    I tested out Revision 2 and it works well. It would really be helpful, however, if I could have a few modifications to the output of information in the Excel spreadsheet, please. Specifically, I only need the following categories, in this order:
    Subject
    Start Date
    Start Time
    End Time

    I attempted to make changes myself, but I quickly discovered that all the outputs are “intertwined,” so that if I eliminated one thing or changed the order, things fell apart.
    Again, I would really appreciate your help on this, please. Thanks.

    Greg

    • Hi, Greg.

      This should do it. Only replace the ExportAppointmentsToExcel subroutine. Leave the rest of the code as is.

      Sub ExportAppointmentsToExcel()
          'On the next line, edit the list of calendars you want to export.  Each entry is the path to a calendar.  Entries are separated by a comma.
          Const CAL_LIST = "Calendar1,Calendar2"
          'On the next line, edit the path to and name of the Excel spreadsheet to export to
          Const EXCEL_FILE = "c:\users\david\documents\testarea\kimberly.xlsx"
          Const SCRIPT_NAME = "Export Appointments to Excel (Rev 2)"
          Const xlAscending = 1
          Const xlYes = 1
          Dim olkFld As Object, _
              olkLst As Object, _
              olkRes As Object, _
              olkApt As Object, _
              olkRec As Object, _
              excApp As Object, _
              excWkb As Object, _
              excWks As Object, _
              lngRow As Long, _
              lngCnt As Long, _
              strFil As String, _
              strLst As String, _
              strDat As String, _
              datBeg As Date, _
              datEnd As Date, _
              arrTmp As Variant, _
              arrCal As Variant, _
              varCal As Variant
          strDat = InputBox("Enter the date range of the appointments to export in the form ""mm/dd/yyyy to mm/dd/yyyy""", SCRIPT_NAME, Date & " to " & Date)
          arrTmp = Split(strDat, "to")
          datBeg = IIf(IsDate(arrTmp(0)), arrTmp(0), Date) & " 12:00am"
          datEnd = IIf(IsDate(arrTmp(1)), arrTmp(1), Date) & " 11:59pm"
          Set excApp = CreateObject("Excel.Application")
          Set excWkb = excApp.Workbooks.Add()
          Set excWks = excWkb.Worksheets(1)
          'Write Excel Column Headers
          With excWks
              .Cells(1, 1) = "Subject"
              .Cells(1, 2) = "Starting Date"
              .Cells(1, 3) = "Start Time"
              .Cells(1, 4) = "End Time"
          End With
          lngRow = 2
          arrCal = Split(CAL_LIST, ",")
          For Each varCal In arrCal
              Set olkFld = OpenOutlookFolder(CStr(varCal))
              If TypeName(olkFld) <> "Nothing" Then
                  If olkFld.DefaultItemType = olAppointmentItem Then
                      Set olkLst = olkFld.Items
                      olkLst.Sort "[Start]"
                      olkLst.IncludeRecurrences = True
                      Set olkRes = olkLst.Restrict("[Start] >= '" & Format(datBeg, "ddddd h:nn AMPM") & "' AND [Start] <= '" & Format(datEnd, "ddddd h:nn AMPM") & "'")
                      'Write appointments to spreadsheet
                      For Each olkApt In olkRes
                          'Only export appointments
                          If olkApt.Class = olAppointment Then
                              'Add a row for each field in the message you want to export
                              excWks.Cells(lngRow, 1) = olkApt.Subject
                              excWks.Cells(lngRow, 2) = Format(olkApt.Start, "mm/dd/yyyy")
                              excWks.Cells(lngRow, 3) = Format(olkApt.Start, "hh:nn ampm")
                              excWks.Cells(lngRow, 4) = Format(olkApt.End, "hh:nn ampm")
                              lngRow = lngRow + 1
                              lngCnt = lngCnt + 1
                          End If
                      Next
                  Else
                      MsgBox "Operation cancelled.  The selected folder is not a calendar.  You must select a calendar for this macro to work.", vbCritical + vbOKOnly, SCRIPT_NAME
                  End If
              Else
                  MsgBox "I could not find a folder named " & varCal & ".  Folder skipped.  I will continue processing the remaining folders.", vbExclamation + vbOKOnly, SCRIPT_NAME
              End If
          Next
          excWks.Columns("A:D").AutoFit
          excWkb.SaveAs EXCEL_FILE
          excWkb.Close
          MsgBox "Process complete.  I exported a total of " & lngCnt & " appointments were exported.", vbInformation + vbOKOnly, SCRIPT_NAME
          Set excWks = Nothing
          Set excWkb = Nothing
          Set excApp = Nothing
          Set olkApt = Nothing
          Set olkLst = Nothing
          Set olkFld = Nothing
      End Sub
      
  24. David,
    I am attempting to use Revision #2 of this macro. The example you provide for the Outlook path format to enter into the macro for the folder does not work. I typed the following in the macro, with T102 being the name of the Outlook account/calendar:
    “Mailbox – T102\Inbox”
    I get the message that the macro cannot find a folder with that name. What am I missing? I appreciate your help. Thanks.

    • Hi, Greg.

      Add this code to Outlook.

      Sub DisplayFolderPath()
          Const SCRIPT_NAME = "Display Folder Path"
          Dim olkFol As Outlook.MAPIFolder
          Set olkFol = Application.ActiveExplorer.CurrentFolder
          MsgBox "The path to the currently selected folder is " & vbCrLf & vbCrLf & olkFol.FolderPath, vbInformation + vbOKOnly, SCRIPT_NAME
          Set olkFol = Nothing
      End Sub
      

      Once you’ve done that, select the target folder and run the DsiplayFolderPath macro. It will display the path to the currently selected folder. That’s the path to use in Revision #2.

  25. Hi David,

    Happy New Year!
    I found all your posts on this thread to be very helpful – awesome stuff!

    I’m actually currently putting one of the macros you posted here to good use but was wondering if you’d be able to help me make a few modifications to it. I already made a few tweaks to the code but got stuck when trying to add more functionalities to it and I’d appreciate any help I can get from you.

    The code, which I’ll paste at the end of my message, reads my outlook calendar and exports all the appointments and their lengths into the correct column which is arranged by month and category of the appointment. Here are some other things I want it to do; let me know if any of the following is possible:
    1) Each month column is currently split into 2 sub columns that indicate the category of the appointment, Call or In-Person Meeting. Is it possible to make the macro add 3 sub columns under each month that read “Call”, “Review” and “In-Person Meeting”?
    2) The macro currently looks at the category of the appointment. If the appointment does not have a category assigned to it, the macro reads it as if it has the “Call” category assigned to it. I want the macro to consider a third category called “Review” and spit out the length of the appointment that has the category “Review” into the corresponding new sub column that I mentioned in #1 I want to add under each month. Can we do that? And the appointments that do not have a category I don’t mind if the macro continues to default it as a “Call”, you can leave that part as it is.
    3) Can you make the macro spit out the category of the appointment into a separate column?
    4) Each appointment in my outlook has an ID number at the end of the appointment’s name (the ‘subject’ field of the appointment). Can you make the macro spit out the ID number into a separate column? So, say the subject of the appointment reads, “Meeting in Chicago with Peter ID: 6778779”. I want the macro to read the subject and spit out everything after the colon into a separate column i.e. spit out “6778779”. I’d prefer, if possible, to have this column be the first column on the excel sheet right before the column that would have the name of the appointments.
    5) When I run this macro, it prompts me to specify the date range that I would like the macro to export. Can you have the macro mention somewhere on the excel sheet the date range that I entered?
    6) Some appointments on my calendar are reoccurring appointments. Currently, the macro reads a recurring appointment as if that appointment only occurred once – the first date in the series. So say I create a recurring appointment that would occur the third Monday of every month starting on December 21st. The macro only reads that as if it took place once on December 21st and would spit out the time of that appointment into the December column but not in every other month as it should since it’s recurring. Can you fix that and make the macro account for every time the recurring appointment actually appears on the calendar and not only the first time it occurs?

    Apologies if this post is too overwhelming – I would really appreciate it if you let me know if this is all possible!

    Thanks in advance, David!

    Best,
    Steve

    Here’s the macro I’m using:
    Sub ExportAppointmentsToExcel()
    Const SCRIPT_NAME = “Export Appointments to Excel (Rev 1)”
    Const xlAscending = 1
    Const xlYes = 1
    Dim olkFld As Object, _
    olkLst As Object, _
    olkRes As Object, _
    olkApt As Object, _
    excApp As Object, _
    excWkb As Object, _
    excWks As Object, _
    lngRow As Long, _
    lngCnt As Long, _
    strFil As String, _
    curCli As String, _
    strDat As String, _
    datBeg As Date, _
    datEnd As Date, _
    arrTmp As Variant, _
    i As Long, _
    callOrMeet As Integer, _
    col As Long
    Set olkFld = Application.ActiveExplorer.CurrentFolder
    If olkFld.DefaultItemType = olAppointmentItem Then
    strDat = InputBox(“Enter the date range of the appointments to export in the form “”mm/dd/yyyy to mm/dd/yyyy”””, SCRIPT_NAME, Date & ” to ” & Date)
    arrTmp = Split(strDat, “to”)
    datBeg = IIf(IsDate(arrTmp(0)), arrTmp(0), Date) & ” 12:00am”
    datEnd = IIf(IsDate(arrTmp(1)), arrTmp(1), Date) & ” 11:59pm”
    strFil = InputBox(“Enter a filename (including path) to save the exported appointments to.”, SCRIPT_NAME)
    If strFil “” Then
    Set excApp = CreateObject(“Excel.Application”)
    Set excWkb = excApp.Workbooks.Add()
    Set excWks = excWkb.Worksheets(1)
    ‘Write Excel Column Headers
    With excWks
    .Cells(1, 1) = “Client”
    .Cells(1, 2) = “January”
    .Cells(1, 4) = “February”
    .Cells(1, 6) = “March”
    .Cells(1, 8) = “April”
    .Cells(1, 10) = “May”
    .Cells(1, 12) = “June”
    .Cells(1, 14) = “July”
    .Cells(1, 16) = “August”
    .Cells(1, 18) = “September”
    .Cells(1, 20) = “October”
    .Cells(1, 22) = “November”
    .Cells(1, 24) = “December”
    For i = 2 To 24 Step 2
    .Range(.Cells(1, i), .Cells(1, i + 1)).Merge
    .Cells(1, i).HorizontalAlignment = xlCenter
    .Cells(2, i) = “Call”
    .Cells(2, i + 1) = “In Person”
    Next i
    End With
    lngRow = 2
    Set olkLst = olkFld.Items
    olkLst.Sort “[Subject]”
    olkLst.IncludeRecurrences = True
    Set olkRes = olkLst.Restrict(“[Start] >= ‘” & Format(datBeg, “ddddd h:nn AMPM”) & “‘ AND [Start] <= '" & Format(datEnd, "ddddd h:nn AMPM") & "'")
    curCli = ""
    'Write appointments to spreadsheet
    For Each olkApt In olkRes
    If olkApt.AllDayEvent True Then
    ‘Only export appointments
    If olkApt.Class = olAppointment Then
    If curCli olkApt.Subject Then
    curCli = olkApt.Subject
    lngRow = lngRow + 1
    excWks.Cells(lngRow, 1) = olkApt.Subject
    End If

    callOrMeet = 0
    If olkApt.Categories = “In-Person Meeting” Then callOrMeet = 1

    col = Month(olkApt.Start) * 2 + callOrMeet

    ‘Add a row for each field in the message you want to export
    If excWks.Cells(lngRow, col) = “” Then
    excWks.Cells(lngRow, col) = DateDiff(“n”, olkApt.Start, olkApt.End) / 60
    Else
    excWks.Cells(lngRow, col) = excWks.Cells(lngRow, col) + DateDiff(“n”, olkApt.Start, olkApt.End) / 60
    End If

    lngCnt = lngCnt + 1

    End If
    End If
    Next
    excWks.Columns(“A:M”).AutoFit
    ‘excWks.Range(“A1:H” & lngRow – 1).Sort Key1:=”Category”, Order1:=xlAscending, Header:=xlYes
    ‘excWks.Cells(lngRow, 7) = “=sum(G2:G” & lngRow – 1 & “)”
    excWkb.SaveAs strFil
    excWkb.Close
    MsgBox “Process complete. A total of ” & lngCnt & ” appointments were exported.”, vbInformation + vbOKOnly, SCRIPT_NAME
    End If
    Else
    MsgBox “Operation cancelled. The selected folder is not a calendar. You must select a calendar for this macro to work.”, vbCritical + vbOKOnly, SCRIPT_NAME
    End If
    Set excWks = Nothing
    Set excWkb = Nothing
    Set excApp = Nothing
    Set olkApt = Nothing
    Set olkLst = Nothing
    Set olkFld = Nothing
    End Sub

    • Happy New Year, Steve.

      Everything you described sounds doable. The only thing I’m a little unclear on is the layout of the resulting spreadsheet. Could you provide me with an example?

    • Hi David,

      I appreciate your response and your willingness to help!
      Sure, I can provide you with an example. What would be the easiest way to do so?
      Should I provide you with a Dropbox link to an excel spreadsheet example or a screen shot of an example?

      Please let me know what would be more convenient for you.

      Thanks again!
      Steve

    • Steve,

      Dropbox will work or you can just email me the spreadsheet. If email will work for you, then I can send you a message and you can reply and attach the sample spreadsheet.

    • David,

      That would be perfect – please, when you get a chance, send me a message as I am not sure where I can find your email address.

      Thanks so much!
      Steve

Leave a comment