Outlook Export Custom Field to Excel - vba

I have a module that I had used in the past to pull data from my outlook calendar and was putting basically “billing” information into the location field so I didn’t have to do a custom field. Of course that kind of worked until someone sent an invite using location … so I needed to evolve and create a new field. My problem is now of course my VBA must change to use custom fields.
Below is what I have – the “BillingInfo” or the following
.End(xlDown).End(xlUp).Offset(NextRow, 3).Value = ThisAppt.BillingInfo is what is getting flagged.
here is the full ...
' this is the sub to tell outlook what to pull in -
' select the dates as needed
'
Sub GetApptsFromOutlook()
Dim dteStart As Date
Dim dteEnd As Date
dteStart = InputBox("What is the start date?")
dteEnd = InputBox("What is the end date?")
Call GetCalData(dteStart, dteEnd)
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 is optional, if you want to pull from only one day, use: Call GetCalData("7/14/2008")
' -------------------------------------------------
Dim olApp As Outlook.Application
Dim olNS As Outlook.Namespace
Dim myCalItems As Outlook.Items
Dim ItemstoCheck As Outlook.Items
Dim ThisAppt As Outlook.AppointmentItem
Dim MyItem As Object
Dim StringToCheck As String
Dim MyBook As Excel.Workbook
Dim rngStart As Excel.Range
Dim i As Long
Dim NextRow As Long
' if no end date was specified, then the requestor only wants one day, so set EndDate = StartDate
' this will let us return appts from multiple dates, if the requestor does in fact set an appropriate end date
If EndDate = "12:00:00 AM" Then
EndDate = StartDate
End If
If EndDate < StartDate Then
MsgBox "Those dates seem switched, please check them and try again.", vbInformation
GoTo ExitProc
End If
If EndDate - StartDate > 28 Then
' ask if the requestor wants so much info
If MsgBox("This could take some time. Continue anyway?", vbInformation + vbYesNo) = vbNo Then
GoTo ExitProc
End If
End If
' get or create Outlook object and make sure it exists before continuing
On Error Resume Next
Set olApp = GetObject(, "Outlook.Application")
If Err.Number <> 0 Then
Set olApp = CreateObject("Outlook.Application")
End If
On Error GoTo 0
If olApp Is Nothing Then
MsgBox "Cannot start Outlook.", vbExclamation
GoTo ExitProc
End If
Set olNS = olApp.GetNamespace("MAPI")
Set myCalItems = olNS.GetDefaultFolder(olFolderCalendar).Items
' ------------------------------------------------------------------
' the following code adapted from:
' http://www.outlookcode.com/article.aspx?id=30
'
With myCalItems
.Sort "[Start]", False
.IncludeRecurrences = True
End With
'
StringToCheck = "[Start] >= " & Quote(StartDate & " 12:00 AM") & " AND [End] <= " & _
Quote(EndDate & " 11:59 PM")
Debug.Print StringToCheck
'
Set ItemstoCheck = myCalItems.Restrict(StringToCheck)
Debug.Print ItemstoCheck.Count
' ------------------------------------------------------------------
If ItemstoCheck.Count > 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 = Excel.Workbooks.Add
Set rngStart = MyBook.Sheets(1).Range("A1")
With rngStart
.Offset(0, 0).Value = "Start"
.Offset(0, 1).Value = "Duration"
.Offset(0, 2).Value = "Categories"
.Offset(0, 3).Value = "BillingInfo"
.Offset(0, 4).Value = "Subject"
End With
For Each MyItem In ItemstoCheck
If MyItem.Class = olAppointment Then
' MyItem is the appointment or meeting item we want,
' set obj reference to it
Set ThisAppt = MyItem
NextRow = WorksheetFunction.CountA(Range("A:A"))
With rngStart
.End(xlDown).End(xlUp).Offset(NextRow, 0).Value = Format(ThisAppt.Start, "MM/DD/YYYY")
.End(xlDown).End(xlUp).Offset(NextRow, 1).Value = ThisAppt.Duration
.End(xlDown).End(xlUp).Offset(NextRow, 2).Value = ThisAppt.Categories
.End(xlDown).End(xlUp).Offset(NextRow, 3).Value = ThisAppt.BillingInfo
.End(xlDown).End(xlUp).Offset(NextRow, 4).Value = ThisAppt.Subject
If ThisAppt.Categories <> "" Then
.End(xlDown).End(xlUp).Offset(NextRow, 6).Value = ThisAppt.Categories
Else
.End(xlDown).End(xlUp).Offset(NextRow, 6).Value = "n/a"
End If
End With
End If
Next MyItem
' make it pretty
Call Cool_Colors(rngStart)
Else
MsgBox "There are no appointments or meetings during" & _
"the time you specified. Exiting now.", vbCritical
End If
ExitProc:
Set myCalItems = Nothing
Set ItemstoCheck = Nothing
Set olNS = Nothing
Set olApp = Nothing
Set rngStart = Nothing
Set ThisAppt = Nothing
End Sub
Private Function Quote(MyText)
' from Sue Mosher's excellent book "Microsoft Outlook Programming"
Quote = Chr(34) & MyText & Chr(34)
End Function
Private Sub Cool_Colors(rng As Excel.Range)
'
' Lt Blue BG with white letters
'
'
With Range(rng, rng.End(xlToRight))
.Font.ColorIndex = 2
.Font.Bold = True
.HorizontalAlignment = xlCenter
.MergeCells = False
.AutoFilter
.CurrentRegion.Columns.AutoFit
With .Interior
.ColorIndex = 41
.Pattern = xlSolid
End With
End With
End Sub

ThisAppt does not contains BillingInfo directly. You will need to retrieve it through the UserProperties collection like this :
.End(xlDown).End(xlUp).Offset(NextRow, 3).Value = ThisAppt.UserProperties.Item("BillingInfo").Value

Related

Count Outlook emails by Sender & date in Excel VBA

The objective is to find the total/count of emails from Sender on Monthly basis.
The below code retrieves Date/Time for a count by month.
How to display by SenderName on the worksheet?
I'm not sure if I've to use two dictionaries? If yes no knowledge about how to work around it.
Sub ReferSpecificFolder()
'Declare Outlook application & folder object variables.
Dim objOutlook as Object, objnSpace as Object, objFolder As Outlook.MAPIFolder
Dim olItem As Variant 'Object
Dim dictDate as Object
Set objOutlook = CreateObject("Outlook.Application")
Set objnSpace=objOutlook.GetNamespace("MAPI")
Set objFolder = objOutlook.GetNamespace("MAPI").Folders("xyz#microsoft.com").Folders("Sales - 2020")
Set dictDate=CreateObject("Scripting.Dictionary")
Set myItems = objFolder.Items
On Error Resume Next
If Err.Number <> 0 Then
Err.Clear
MsgBox "No such folder!"
Exit Sub
End If
If fldr.Items.Count = 0 Then
MsgBox "There were no messages found in your folders"
Exit Sub
End If
'Select the sheet to enter the data
Dim wbData As Worksheet
Dim LastRow As Long
Set wbData = ThisWorkbook.Sheets("Rawdata - Time Period")
LastRow = wbData.Range("A" & wbData.Rows.Count).End(xlUp).Row + 1
myItems.SetColumns("SenderName, SentOn")
For Each i In myItems
dateStr=GetDate(i.SentOn)
strSender=i.SenderName
If Not dictDate.Exists(dateStr) Then
dictDate(dateStr)=0
End If
dictDate(dateStr)=CLng(dictDate(dateStr))+1
Next i
For Each o In dictDate.keys
LastRow = wbData.Range("A" & wbData.Rows.Count).End(xlUp).Row + 1
With wbData
.Cells(LastRow, 1) = o 'Received Date
.Cells(LastRow, 3) = dictDate(o) 'Count
End With
Next o
Set fldr = Nothing
Set olItem = Nothing
Set olApp = Nothing
MsgBox "DONE!"
End Sub
Function GetDate(dt as Date) as String
GetDate=Year(dt) & "-" & Month(dt) & "-" & Day(dt) & " " & Hour(dt) & ":" & Minute(dt)
End Function
This generates a single sender dictionary then a date dictionary corresponding to each entry in the sender dictionary.
Option Explicit ' Consider this mandatory
' Tools | Options | Editor tab
' Require Variable Declaration
'
' If desperate declare as Variant
'
Sub ReferSpecificFolderSender()
' Early binding, must set a reference to
' Microsoft Outlook XX.X Object Library
Dim objOutlook As Outlook.Application
Dim objnSpace As Outlook.Namespace
Dim objFolder As Outlook.Folder
Dim olItemI As Object
Dim olItemJ As Object
Dim myItems As Outlook.Items
Dim myItemsDate As Outlook.Items
Dim strFilter As String
Dim dictDate As Object
Dim o As Variant
Dim dateStr As String
Dim dictSender As Object
Dim p As Variant
Dim strSender As String
Set objOutlook = CreateObject("Outlook.Application")
Set objnSpace = objOutlook.GetNamespace("MAPI")
' For the specific purpose of addressing an expected error
' due to not finding objFolder
On Error Resume Next
Set objFolder = objnSpace.Folders("xyz#microsoft.com").Folders("Sales - 2020")
If Err.Number <> 0 Then
Err.Clear
'MsgBox "No such folder!"
'Exit Sub
Set objFolder = objnSpace.PickFolder
If objFolder Is Nothing Then Exit Sub
End If
' Consider mandatory to closely follow On Error Resume Next
' Return to normal error handling
On Error GoTo 0
Set myItems = objFolder.Items
Debug.Print vbCr & "myItems.Count: " & myItems.Count
If objFolder.Items.Count = 0 Then
MsgBox "There were no messages found in " & objFolder.FolderPath
Exit Sub
End If
Set dictSender = CreateObject("Scripting.Dictionary")
' Restrict to mailitems
' 0x001A001F
' https://stackoverflow.com/questions/61793354/delete-items-in-outlook-by-type-or-message-class
'strFilter = "#SQL=""http://schemas.microsoft.com/mapi/proptag/0x001A001F"" LIKE 'IPM.Note'"
'Set myItems = myItems.Restrict(strFilter)
' 0x001A001E
' "PR_MESSAGE_CLASS" http://schemas.microsoft.com/mapi/proptag/0x001A001E
' https://www.slipstick.com/developer/read-mapi-properties-exposed-outlooks-object-model/
strFilter = "#SQL=""http://schemas.microsoft.com/mapi/proptag/0x001A001E"" LIKE 'IPM.Note'"
Set myItems = myItems.Restrict(strFilter)
Debug.Print vbCr & "Mailitems"
Debug.Print "myItems.Count: " & myItems.Count
myItems.Sort "[SenderName]", False
Set dictDate = CreateObject("Scripting.Dictionary")
Set myItemsDate = myItems
Debug.Print "myItemsDate.Count: " & myItemsDate.Count
'The sheet to enter the data
Dim wbData As Worksheet
Dim LastRow As Long
Set wbData = ThisWorkbook.Sheets("Rawdata - Time Period")
LastRow = wbData.Range("A" & wbData.Rows.Count).End(xlUp).Row + 1
' dictionary of sender names
Debug.Print "Sender dictionary"
' With the SetColumns method, Outlook only checks the properties that you have cached,
' and provides fast, read-only access to these properties.
' https://learn.microsoft.com/en-us/office/vba/api/outlook.items.setcolumns
myItems.SetColumns ("SenderName")
For Each olItemJ In myItems
strSender = olItemJ.SenderName
If Not dictSender.Exists(strSender) Then
Debug.Print " " & strSender
dictSender(strSender) = 0
End If
dictSender(strSender) = CLng(dictSender(strSender)) + 1
Next
' iterate unique sender names
For Each p In dictSender.keys
Debug.Print "Date dictionary for: " & p
myItems.Sort "[SentOn]", False
myItemsDate.SetColumns ("SenderName, SentOn")
' check item's date against the sender name dictionary
For Each olItemI In myItemsDate
strSender = olItemI.SenderName
If strSender = p Then
' unique dates for current SenderName
dateStr = GetDate(olItemI.SentOn)
If Not dictDate.Exists(dateStr) Then
dictDate(dateStr) = 0
End If
' count of ccurrences for each date
dictDate(dateStr) = CLng(dictDate(dateStr)) + 1
End If
Next
For Each o In dictDate.keys
LastRow = wbData.Range("A" & wbData.Rows.Count).End(xlUp).Row + 1
With wbData
.Cells(LastRow, 1) = p ' SenderName
.Cells(LastRow, 2) = o ' GetDate value
.Cells(LastRow, 3) = dictDate(o) ' Count
End With
Next
' delete date dictionary entries for current SenderName
dictDate.RemoveAll
Next p
ActiveSheet.Columns.AutoFit
Set objFolder = Nothing
Set olItemI = Nothing
Set olItemJ = Nothing
Set objOutlook = Nothing
Set objnSpace = Nothing
Set dictSender = Nothing
Set dictDate = Nothing
Set myItemsDate = Nothing
Debug.Print "DONE!"
'MsgBox "DONE!"
End Sub

VBA Run-Time Error '-2147221233 (8004010f)'

I am attempting to run the VBA code mentioned below.
The VBA code is for pulling email information from a single folder of the user's selection in Microsoft Outlook and listing what the response time is in Microsoft Excel.
Here is the error message I receive when I attempt to run it.
"Run-time error '-2147221233 (8004010f)':
The Property "http://schemas.microsoft.com/mapi/proptag/0x003F0102" is unknown or cannot be found.
Here is the code I am using:
Option Explicit
Public ns As Outlook.Namespace
Private Const EXCHIVERB_REPLYTOSENDER = 102
Private Const EXCHIVERB_REPLYTOALL = 103
Private Const EXCHIVERB_FORWARD = 104
Private Const PR_LAST_VERB_EXECUTED = "http://schemas.microsoft.com/mapi/proptag/0x10810003"
Private Const PR_LAST_VERB_EXECUTION_TIME = "http://schemas.microsoft.com/mapi/proptag/0x10820040"
Private Const PR_SMTP_ADDRESS = "http://schemas.microsoft.com/mapi/proptag/0x39FE001E"
Private Const PR_RECEIVED_BY_ENTRYID As String = "http://schemas.microsoft.com/mapi/proptag/0x003F0102"
' Locates best matching reply in related conversation to the given mail message passed in as oMailItem
Private Function GetReply(oMailItem As MailItem) As MailItem
Dim conItem As Outlook.Conversation
Dim ConTable As Outlook.Table
Dim ConArray() As Variant
Dim MsgItem As MailItem
Dim lp As Long
Dim LastVerb As Long
Dim VerbTime As Date
Dim Clockdrift As Long
Dim OriginatorID As String
Set conItem = oMailItem.GetConversation ' Let Outlook and Exchange do the hard lifting to get entire converstion for email being checked.
OriginatorID = oMailItem.PropertyAccessor.BinaryToString(oMailItem.PropertyAccessor.GetProperty(PR_RECEIVED_BY_ENTRYID))
If Not conItem Is Nothing Then ' we have a conversation in which we should be able to match the reply
Set ConTable = conItem.GetTable
ConArray = ConTable.GetArray(ConTable.GetRowCount)
LastVerb = oMailItem.PropertyAccessor.GetProperty(PR_LAST_VERB_EXECUTED)
Select Case LastVerb
Case EXCHIVERB_REPLYTOSENDER, EXCHIVERB_REPLYTOALL ', EXCHIVERB_FORWARD ' not interested in forwarded messages
VerbTime = oMailItem.PropertyAccessor.GetProperty(PR_LAST_VERB_EXECUTION_TIME)
VerbTime = oMailItem.PropertyAccessor.UTCToLocalTime(VerbTime) ' convert to local time
' Debug.Print "Reply to " & oMailItem.Subject & " sent on (local time): " & VerbTime
For lp = 0 To UBound(ConArray)
If ConArray(lp, 4) = "IPM.Note" Then ' it is a mailitem
Set MsgItem = ns.GetItemFromID(ConArray(lp, 0)) 'mail item to check against
If Not MsgItem.Sender Is Nothing Then
If OriginatorID = MsgItem.Sender.ID Then
Clockdrift = DateDiff("s", VerbTime, MsgItem.SentOn)
If Clockdrift >= 0 And Clockdrift < 300 Then ' Allow for a clock drift of up to 300 seconds. This may be overgenerous
Set GetReply = MsgItem
Exit For ' only interested in first matching reply
End If
End If
End If
End If
Next
Case Else
End Select
End If
' as we exit function GetMsg is either Nothing or the reply we are interested in
End Function
Public Sub ListIt()
Dim myOlApp As New Outlook.Application
Dim myItem As Object ' item may not necessarily be a mailitem
Dim myReplyItem As Outlook.MailItem
Dim myFolder As Folder
Dim xlRow As Long
Set ns = myOlApp.GetNamespace("MAPI") ' Initialise Outlook access
Set myFolder = ns.PickFolder() ' for the sake of this example we just pick a folder.
InitSheet ActiveSheet ' initialise the spreadsheet
xlRow = 3
For Each myItem In myFolder.Items
If myItem.Class = olMail Then
Set myReplyItem = GetReply(myItem) ' this example only deals with mailitems
If Not myReplyItem Is Nothing Then ' we found a reply
PopulateSheet ActiveSheet, myItem, myReplyItem, xlRow
xlRow = xlRow + 1
End If
End If
DoEvents ' cheap and nasty way to allow other things to happen
Next
MsgBox "Done"
End Sub
Private Sub InitSheet(mySheet As Worksheet)
With mySheet
.Cells.Clear
.Cells(1, 1).FormulaR1C1 = "Received"
.Cells(2, 1).FormulaR1C1 = "From"
.Cells(2, 2).FormulaR1C1 = "Subject"
.Cells(2, 3).FormulaR1C1 = "Date/Time"
.Cells(1, 4).FormulaR1C1 = "Replied"
.Cells(2, 4).FormulaR1C1 = "From"
.Cells(2, 5).FormulaR1C1 = "To"
.Cells(2, 6).FormulaR1C1 = "Subject"
.Cells(2, 7).FormulaR1C1 = "Date/Time"
.Cells(2, 8).FormulaR1C1 = "Response Time"
End With
End Sub
Private Sub PopulateSheet(mySheet As Worksheet, myItem As MailItem, myReplyItem As MailItem, xlRow As Long)
Dim recips() As String
Dim myRecipient As Outlook.Recipient
Dim lp As Long
With mySheet
.Cells(xlRow, 1).FormulaR1C1 = myItem.SenderEmailAddress
.Cells(xlRow, 2).FormulaR1C1 = myItem.Subject
.Cells(xlRow, 3).FormulaR1C1 = myItem.ReceivedTime
'.Cells(xlRow, 4).FormulaR1C1 = myReplyItem.SenderEmailAddress
.Cells(xlRow, 4).FormulaR1C1 = myReplyItem.Sender.PropertyAccessor.GetProperty(PR_SMTP_ADDRESS) ' I prefer to see the SMTP address
For lp = 0 To myReplyItem.Recipients.Count - 1
ReDim Preserve recips(lp) As String
recips(lp) = myReplyItem.Recipients(lp + 1).Address
Next
.Cells(xlRow, 5).FormulaR1C1 = Join(recips, vbCrLf)
.Cells(xlRow, 6).FormulaR1C1 = myReplyItem.Subject
.Cells(xlRow, 7).FormulaR1C1 = myReplyItem.SentOn
.Cells(xlRow, 8).FormulaR1C1 = "=RC[-1]-RC[-5]"
.Cells(xlRow, 8).NumberFormat = "[h]:mm:ss"
End With
End Sub
Can you help me out? Please let me know if I could be any more specific.
I noticed that the error occurs on the only line using the "as string" in the declaration. Although this type of declaration if perfectly fine in VB, it doesn't work in VBA.
Simply remove the "as string" on that line.

Exporting Outlook calendar data to Excel file - Shared calendars and VBA

I'm trying to export some data from Outlook to Excel. The task is to analyze all the shared calendar and find out when an user is going on vacation.
All the people would put an appointment with location "vacation" and, day by day, running the script the result would be an excel sheet with rows like "Employee - Start - End" with meaning employee who is in vacation from when to when.
I managed to adapt a script found on internet. It works but only with my local calendar. How could I adapt this script again in order to scan all the shared calendars? Here is the code:
Private Sub Test_Click()
Call GetCalData("16/06/2015", "28/06/2015")
InputBox("Data inizio")
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 is optional, if you want to pull from only one day, use: Call GetCalData("7/14/2008")
' -------------------------------------------------
Dim olApp As Outlook.Application
Dim olNS As Outlook.Namespace
Dim myCalItems As Outlook.Items
Dim ItemstoCheck As Outlook.Items
Dim ThisAppt As Outlook.AppointmentItem
Dim MyItem As Object
Dim StringToCheck As String
Dim MyBook As Excel.Workbook
Dim rngStart As Excel.Range
Dim i As Long
Dim NextRow As Long
' if no end date was specified, then the requestor only wants one day, so set EndDate = StartDate
' this will let us return appts from multiple dates, if the requestor does in fact set an appropriate end date
If EndDate = "12:00:00 AM" Then
EndDate = StartDate
End If
If EndDate < StartDate Then
MsgBox "Those dates seem switched, please check them and try again.", vbInformation
GoTo ExitProc
End If
If EndDate - StartDate > 28 Then
' ask if the requestor wants so much info
If MsgBox("This could take some time. Continue anyway?", vbInformation + vbYesNo) = vbNo Then
GoTo ExitProc
End If
End If
' get or create Outlook object and make sure it exists before continuing
On Error Resume Next
Set olApp = GetObject(, "Outlook.Application")
If Err.Number <> 0 Then
Set olApp = CreateObject("Outlook.Application")
End If
On Error GoTo 0
If olApp Is Nothing Then
MsgBox "Cannot start Outlook.", vbExclamation
GoTo ExitProc
End If
Set olNS = olApp.GetNamespace("MAPI")
Set myCalItems = olNS.GetDefaultFolder(olFolderCalendar).Items
' ------------------------------------------------------------------
' the following code adapted from:
' http://www.outlookcode.com/article.aspx?id=30
'
With myCalItems
.Sort "[Start]", False
.IncludeRecurrences = True
End With
'
StringToCheck = "[Start] >= " & Quote(StartDate & " 12:00 AM") & " AND [End] <= " & _
Quote(EndDate & " 11:59 PM")
Debug.Print StringToCheck
'
Set ItemstoCheck = myCalItems.Restrict(StringToCheck)
Debug.Print ItemstoCheck.Count
' ------------------------------------------------------------------
If ItemstoCheck.Count > 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 = ThisWorkbook.Sheets(1).Range("A1")
With rngStart
.Offset(0, 0).Value = "Impiegato"
.Offset(0, 1).Value = "Data inizio"
.Offset(0, 2).Value = "Fine"
.Offset(0, 3).Value = "Location"
End With
For Each MyItem In ItemstoCheck
If MyItem.Class = olAppointment Then
' MyItem is the appointment or meeting item we want,
' set obj reference to it
Set ThisAppt = MyItem
If StrComp(ThisAppt.Location, "vacation") = 0 Then
NextRow = Range("A" & Rows.Count).End(xlUp).Row
With rngStart
.Offset(NextRow, 0).Value = ThisAppt.Organizer
.Offset(NextRow, 1).Value = ThisAppt.Start
.Offset(NextRow, 2).Value = ThisAppt.End
.Offset(NextRow, 3).Value = ThisAppt.Location
End With
End If
End If
Next MyItem
' make it pretty
Call Cool_Colors(rngStart)
Else
MsgBox "There are no appointments or meetings during" & _
"the time you specified. Exiting now.", vbCritical
End If
ExitProc:
Set myCalItems = Nothing
Set ItemstoCheck = Nothing
Set olNS = Nothing
Set olApp = Nothing
Set rngStart = Nothing
Set ThisAppt = Nothing
End Sub
Private Function Quote(MyText)
' from Sue Mosher's excellent book "Microsoft Outlook Programming"
Quote = Chr(34) & MyText & Chr(34)
End Function
Private Sub Cool_Colors(rng As Excel.Range)
'
' Lt Blue BG with white letters
'
'
With Range("A18:AE18")
'With Range(rng, rng.End(xlToRight))
.Font.ColorIndex = 2
.Font.Bold = True
'.HorizontalAlignment = xlCenter
'.MergeCells = False
'.AutoFilter
'.CurrentRegion.Columns.AutoFit
With .Interior
.ColorIndex = 41
.Pattern = xlSolid
End With
End With
End Sub
Instead of using Namespace.GetDefaultFolder, call Namespace.CreateRecipient passing the name of the other user, call Recipient.Resolve, then pass it to Namespace.GetSharedDefaultFolder

Excel VBA Recipient Add based relevant cell

I took this code (http://www.jpsoftwaretech.com/using-excel-vba-to-set-up-task-reminders-in-outlook/) and added the strRecipient field myself. I am a total VBA noob and quite obviously, it doesn't work. Can anyone offer a suggestion as to how I can get a Recipient section added that automatically feeds off of cell A4 for example?
Thanks
Option Explicit
Dim bWeStartedOutlook As Boolean
Function AddToTasks(strDate As String, strText As String, DaysOut As Integer, strRecipient As String) As Boolean
' Adds a task reminder to Outlook Tasks a specific number of days before the date specified
' Returns TRUE if successful
' Will not trigger OMG because no protected properties are accessed
' by Jimmy Pena, http://www.jpsoftwaretech.com, 10/30/2008
'
' Usage:
' =AddToTasks("12/31/2008", "Something to remember", 30)
' or:
' =AddToTasks(A1, A2, A3)
' where A1 contains valid date, A2 contains task information, A3 contains number of days before A1 date to trigger task reminder
'
' can also be used in VBA :
'If AddToTasks("12/31/2008", "Christmas shopping", 30) Then
' MsgBox "ok!"
'End If
Dim intDaysBack As Integer
Dim dteDate As Date
Dim olApp As Object ' Outlook.Application
Dim objTask As Object ' Outlook.TaskItem
' make sure all fields were filled in
If (Not IsDate(strDate)) Or (strText = "") Or (DaysOut <= 0) Or (strRecipient = "") Then
AddToTasks = False
GoTo ExitProc
End If
' We want the task reminder a certain number of days BEFORE the due date
' ex: if DaysOut = 120, then we want the due date to be -120 before the date specified
' we need to pass -120 to the NextBusinessDay function, so to go from 120 to -120,
' we subtract double the number (240) from the number provided (120).
' 120 - (120 * 2); 120 - 240 = -120
intDaysBack = DaysOut - (DaysOut * 2)
dteDate = CDate(strDate) + intDaysBack
On Error Resume Next
Set olApp = GetOutlookApp
On Error GoTo 0
If Not olApp Is Nothing Then
Set objTask = olApp.CreateItem(3) ' task item
With objTask
.StartDate = dteDate
.Subject = strText & ", due on: " & strDate
.ReminderSet = True
.Recipients.Add = strRecipient
.Save
.Assign
.Send
End With
Else
AddToTasks = False
GoTo ExitProc
End If
' if we got this far, it must have worked
AddToTasks = True
ExitProc:
If bWeStartedOutlook Then
olApp.Quit
End If
Set olApp = Nothing
Set objTask = Nothing
End Function
Function GetOutlookApp() As Object
On Error Resume Next
Set GetOutlookApp = GetObject(, "Outlook.Application")
If Err.Number <> 0 Then
Set GetOutlookApp = CreateObject("Outlook.Application")
bWeStartedOutlook = True
End If
On Error GoTo 0
End Function
add the following before With objTask
strRecipient = Sheets("sheet name here").Range("A4").Value
strRecipient = Sheets("sheet name here").Range("A4").Value
With objTask
.startdate = dteDate
.CC = strRecipient
.Subject = strText & ", due on: " & strDate
.ReminderSet = True
.Save
.Assign
.Send
End With

Runtime error looping through Outlook items

I am using VBA in Outlook to extract mail information from items in the mainfolder and subfolder. The mainfolder failed to set(capture) the subfolder properties into it and it causes the runtime error.
The runtime error differs whenever I run. For example, sometime I received -970718969 (c6240107) and another time I received -2044460793 (86240107).
When I clicked debug, it points to this line of code:
For Each itm In subFld.Items
Here is the screenshot:
Here is the full code:
Public monthValue As Integer
Public yearValue As String
'Ensure Microsoft Excel 11.0 Object Library is ticked in tools.
Sub ExportToExcel1()
Dim appExcel As Excel.Application
Dim wkb As Excel.Workbook
Dim wks As Excel.Worksheet
Dim rng As Excel.Range
Dim strSheet As String
Dim strPath As String
Dim intRowCounter As Integer
Dim msg As Outlook.MailItem
Dim nms As Outlook.NameSpace
Dim mainFld As Outlook.MAPIFolder
Dim subFld As Outlook.MAPIFolder
Dim itm As Object
Dim offsetRow As Long
Dim emailCount As Long
'Set the path of the excel file.
strSheet = "For fun.xlsx"
strPath = "C:\Users\xxxxxx\Desktop\xxxxx\"
strSheet = strPath & strSheet
Debug.Print strSheet
Set nms = Application.GetNamespace("MAPI")
Set mainFld = nms.PickFolder 'Open the box to select the file.
'Handle potential errors with Select Folder dialog box.
If mainFld Is Nothing Then
MsgBox "Thank you for using this service.", vbOKOnly, "Error"
Set nms = Nothing
Set mainFld = Nothing
Exit Sub
ElseIf mainFld.DefaultItemType <> olMailItem Then
MsgBox "Please select the correct folder.", vbOKOnly, "Error"
Set nms = Nothing
Set mainFld = Nothing
Exit Sub
ElseIf mainFld.Items.Count = 0 Then
MsgBox "There are no mail messages to export", vbOKOnly, "Error"
Set nms = Nothing
Set mainFld = Nothing
Exit Sub
End If
mainForm.Show
'If user clicks cancel, it will exit sub.
If yearValue = "" Then
Set nms = Nothing
Set mainFld = Nothing
Exit Sub
End If
'Open and activate Excel workbook.
Set appExcel = CreateObject("Excel.Application")
appExcel.Workbooks.Open (strSheet)
Set wkb = appExcel.ActiveWorkbook
Set wks = wkb.Sheets(1)
wks.Activate
appExcel.Application.Visible = True 'Show my workbook.
'Check if there are any subfolders.
If mainFld.Folders.Count = 0 Then '1
'No subfolder.
For Each itm In mainFld.Items
If itm.Class <> olMail Then '2
'do nothing
Else
Set msg = itm
'Validate the month and year for the email.
If Month(msg.ReceivedTime) = monthValue And Year(msg.ReceivedTime) = yearValue Then '3
With wks
offsetRow = .Cells(.Rows.Count, 1).End(xlUp).Row
End With
intRowCounter = 1 + offsetRow
Set rng = wks.Cells(intRowCounter, 1)
rng.Value = msg.ReceivedTime
Set rng = wks.Cells(intRowCounter, 2)
rng.Value = msg.SentOn
Set rng = wks.Cells(intRowCounter, 3)
rng.Value = msg.Subject
emailCount = 1 + emailCount 'Track the number of email.
Else
'Do nothing
End If '3
End If '2
Next itm
Else
'With subfolder
For Each itm In mainFld.Items
If itm.Class <> olMail Then '4
'do nothing
Else
Set msg = itm
If Month(msg.ReceivedTime) = monthValue And Year(msg.ReceivedTime) = yearValue Then '5
With wks
offsetRow = .Cells(.Rows.Count, 1).End(xlUp).Row
End With
intRowCounter = 1 + offsetRow
Set rng = wks.Cells(intRowCounter, 1)
rng.Value = msg.ReceivedTime
Set rng = wks.Cells(intRowCounter, 2)
rng.Value = msg.SentOn
Set rng = wks.Cells(intRowCounter, 3)
rng.Value = msg.Subject
emailCount = 1 + emailCount
Else
'Do nothing
End If '5
End If '4
Next itm
For Each subFld In mainFld.Folders
For Each itm In subFld.Items
If itm.Class <> olMail Then '6
'do nothing
Else
Set msg = itm
If Month(msg.ReceivedTime) = monthValue And Year(msg.ReceivedTime) = yearValue Then '7
With wks
offsetRow = .Cells(.Rows.Count, 1).End(xlUp).Row
End With
intRowCounter = 1 + offsetRow
Set rng = wks.Cells(intRowCounter, 1)
rng.Value = msg.ReceivedTime
Set rng = wks.Cells(intRowCounter, 2)
rng.Value = msg.SentOn
Set rng = wks.Cells(intRowCounter, 3)
rng.Value = msg.Subject
emailCount = 1 + emailCount
Else
'Do nothing
End If '7
End If '6
Next itm
Next subFld
End If '1
Set appExcel = Nothing
Set wkb = Nothing
Set wks = Nothing
Set rng = Nothing
Set msg = Nothing
Set nms = Nothing
Set mainFld = Nothing
Set subFld = Nothing
Set itm = Nothing
'Inform the user that there are no email.
If emailCount = 0 Then
MsgBox "No emails associated with this date: " & MonthName(monthValue, True) & " " & yearValue, vbOKOnly, "No Emails"
End If
Exit Sub
Set appExcel = Nothing
Set wkb = Nothing
Set wks = Nothing
Set rng = Nothing
Set msg = Nothing
Set nms = Nothing
Set mainFld = Nothing
Set subFld = Nothing
Set itm = Nothing
End Sub
Do you get that error immediately or only after processing a large number of items? Most likely you are opening too many items and run out of RPC channels. Is this a cached or an online Exchange profile?
Instead of looping through all items, use the Table object (MAPITable.GetTable) - if nothing else, it will be a lot faster.
EDIT: If you are using Exchange, every store object (message, folder, store) opens an RPC channel. Exchange Server limits the number of RPC channels to 255 per client (can be changed on the server). Do not use "for each" loop (it keeps all items referenced until the loop ends) and avoid multiple dot notation (because you will have implicit variables that you cannot explicitly dereference). You will also need to release all Outlook objects as soon as you are done with them.
set fldItems = mainFld.Items
For i = 1 to fldItems.Count do
set itm = fldItems.Item(i)
'do stuff
set itm = Nothing
next
As for the Table object (introduced in Outlook 2007), see http://msdn.microsoft.com/en-us/library/office/ff860769.aspx. If you need to use this in an earlier version of Outlook, you can use the MAPITable object in Redemption (I am its author); it also has a MAPITable.ExecSQL method that takes a standard SQL query and returns the ADODB.Recordset object.