Macro fails to create appointments based on worksheet data - excel

I have an Excel macro that I run, which takes activity names, dates and times from the spreadsheet and places them into the Outlook calendar. This works fine when Outlook is running, but when it is not, the macro does not make the appointments.
I have made an error checking piece that checks to see if a running instance of Outlook is running and if not creates one but it still only works when Outlook is running.
Any ideas why??
Sub SetAppt()
' Dim olApp As Outlook.Application
Dim olApt As AppointmentItem
Dim olApp As Object
'if an instance of outlook is not open then create an instance of the application
On Error Resume Next
Set olApp = GetObject(, "Outlook.Application")
If er.Number = 429 Then
Set olApp = CreateObject("Outlook.Application.14")
End If
On Error GoTo 0
Set olApp = CreateObject("Outlook.Application")
' Set olApp = New Outlook.Application
'declare an index for all the variables
Dim i As Integer
i = 2
'declare the variables that will hold the data and set their initial value
Dim occ, actName, srtTime, duration As String
occ = "A" & i
actName = "B" & i
srtTime = "F" & i
duration = "G" & i
'for holding different parts of the dates/times that will be split
Dim splitStr() As String
Dim splitDrtion() As String
'loop until there is no more items
While Range(occ).Value <> ""
'create a new appointment
Set olApt = olApp.CreateItem(olAppointmentItem)
'we must split the start time and date
splitStr = Split(Range(srtTime).Value, " ")
Dim oDate As Date
oDate = splitStr(0)
'we must also spilt the duration (number/hour)
splitDrtion = Split(Range(duration).Value, " ")
'with is used to acces the appointment items properties
With olApt
.Start = oDate + TimeValue(splitStr(1))
'if the duration is in hours then multiply number else leave it
If splitDrtion(1) = "Hour" Then
.duration = 60 * splitDrtion(0)
Else
.duration = splitDrtion(0)
End If
.Subject = Range(occ).Value
.Body = Range(actName).Value
.Save
End With
'increment i and reset all the variables with the new number
i = i + 1
occ = "A" & i
actName = "B" & i
srtTime = "F" & i
duration = "G" & i
Set olApt = Nothing
Wend
Set olApp = Nothing
End Sub

Building on Siddharth's example, here is a refactored version of your code.
Sub SetAppt()
Dim olApt As Object ' Outlook.AppointmentItem
Dim olApp As Object ' Outlook.Application
Dim i As Long
Dim apptRange As Variant
Const olAppointmentItem As Long = 1
' create outlook
Set olApp = GetOutlookApp
If olApp Is Nothing Then
MsgBox "Could not start Outlook"
Exit Sub
End If
' read appts into array
apptRange = Range(Cells(2, 1), Cells(Rows.Count, 7).End(xlUp)).value
For i = LBound(apptRange) To UBound(apptRange)
Set olApt = olApp.CreateItem(olAppointmentItem)
With olApt
.Start = apptRange(i, 6)
If InStr(apptRange(i, 7), "Hour") > 0 Then
' numeric portion cell is delimited by space
.Duration = 60 * Split(apptRange(i, 7), " ")(0)
Else
.Duration = apptRange(i, 7)
End If
.Subject = apptRange(i, 1)
.Body = apptRange(i, 2)
.Save
End With
Next i
End Sub
Function GetOutlookApp() As Object
On Error Resume Next
Set GetOutlookApp = CreateObject("Outlook.Application")
End Function
This code reads your worksheet data into an array. This avoids the time penalty that comes from the COM interaction between VBA and Excel.
We loop through the array and create a new appointment for each row.
Using the following sample data, it worked regardless of whether Outlook was open or not (Outlook being closed makes it obviously slower, however).
There is in fact no need to check if Outlook is open.

Instead of
On Error Resume Next
Set olApp = GetObject(, "Outlook.Application")
If er.Number = 429 Then
Set olApp = CreateObject("Outlook.Application.14")
End If
On Error GoTo 0
Set olApp = CreateObject("Outlook.Application")
Try this
On Error Resume Next
Set olApp = GetObject(, "Outlook.Application")
'~~> If not found then create new instance
If Err.Number <> 0 Then
Set olApp = CreateObject("Outlook.Application")
End If
Err.Clear
On Error GoTo 0
Since I cannot test it, here is your code with the necessary updates. Please try this.
Sub SetAppt()
Dim olApt As Object, olApp As Object
Dim i As Integer
Dim occ As String, actName As String, srtTime As String, duration As String
Dim splitStr() As String, splitDrtion() As String
Dim oDate As Date
On Error Resume Next
Set olApp = GetObject(, "Outlook.Application")
'~~> If not found then create new instance
If Err.Number <> 0 Then
Set olApp = CreateObject("Outlook.Application")
End If
Err.Clear
On Error GoTo 0
'declare an index for all the variables
i = 2
'declare the variables that will hold the data and set their initial value
occ = "A" & i
actName = "B" & i
srtTime = "F" & i
duration = "G" & i
'loop until there is no more items
While Range(occ).Value <> ""
'create a new appointment
Set olApt = olApp.CreateItem(1)
'we must split the start time and date
splitStr = Split(Range(srtTime).Value, " ")
oDate = splitStr(0)
'we must also spilt the duration (number/hour)
splitDrtion = Split(Range(duration).Value, " ")
'with is used to acces the appointment items properties
With olApt
.Start = oDate + TimeValue(splitStr(1))
'if the duration is in hours then multiply number else leave it
If splitDrtion(1) = "Hour" Then
.duration = 60 * splitDrtion(0)
Else
.duration = splitDrtion(0)
End If
.Subject = Range(occ).Value
.Body = Range(actName).Value
.Save
End With
'increment i and reset all the variables with the new number
i = i + 1
occ = "A" & i
actName = "B" & i
srtTime = "F" & i
duration = "G" & i
Set olApt = Nothing
Wend
Set olApp = Nothing
End Sub

Related

VBA Application-defined error outlook connection

I have the following code and keep having the error "application-defined or object-defined error" and cannot understand why. The tool Microsoft Office 16.0 Object library is activated, I am confident that the error is liked with the line Set outlookMail = outlookApp.CreateItem(0). For sure I am missing something in the connection with outlook.
Sub send_emails()
Dim outlookApp As Object
Dim outlookMail As Object
Dim cell As Range
Dim lastRow As Long
' Create Outlook object
Set outlookApp = CreateObject("Outlook.Application")
' Determine the last row in the worksheet
lastRow = ActiveSheet.Cells(Rows.Count, "A").End(xlUp).Row
' Loop through each cell in column D
For Each cell In Range("D2:D" & lastRow)
' Check if the date in the cell is 15 days from today
If cell.Value = Date + 15 Then
' Retrieve the corresponding email address, name, and surname
Email = cell.Offset(0, 2).Value
Name = cell.Offset(0, 1).Value
surname = cell.Offset(0, -1).Value
' Create a new email
Set outlookMail = outlookApp.CreateItem(0)
' Set the recipient, subject, and body of the email
outlookMail.To = Email
outlookMail.Subject = "Reminder"
outlookMail.Body = "Dear " & Name & " " & surname & ", this is a reminder that your event is coming up in 15 days. Please make sure to prepare accordingly."
' Set the sender and send the email
outlookMail.SendUsingAccount = outlookApp.Session.Accounts.Item("YOUR EMAIL ADDRESS")
outlookMail.Send
' If the email was sent successfully, color the cell in column E green
cell.Offset(0, 1).Interior.Color = vbGreen
End If
Next cell
' Clean up
Set outlookMail = Nothing
Set outlookApp = Nothing
End Sub
The tool Microsoft Office 16.0 Object library is activated
I suppose you have added a reference to the Outlook object model (a COM reference) in Excel VBA environment. In the code I see that the late-binding technology is used:
Dim outlookApp As Object
Dim outlookMail As Object
' Create Outlook object
Set outlookApp = CreateObject("Outlook.Application")
But at the same time you added a COM object reference for using the early-binding in the code. So, I'd suggest using the New operator and declare all Outlook objects in the code with specific types instead:
Dim outlookApp As Outlook.Application
Dim outlookMail As Outlook.MailItem
Set outlookApp = New Outlook.Application()
You can read more about early and late binding technologies in the Using early binding and late binding in Automation article.
Send Emails From Excel
Option Explicit
Private Enum eCols
ecSurName = 1 ' C
ecDate = 2 ' D
ecName = 3 ' E
ecEmail = 4 ' F
End Enum
Sub SendEmails()
Const MY_EMAIL As String = "YOUR EMAIL ADDRESS"
On Error GoTo ClearError
' Reference the worksheet.
If ActiveSheet Is Nothing Then Exit Sub ' no visible workbooks open
If Not TypeOf ActiveSheet Is Worksheet Then Exit Sub ' not a worksheet
Dim ws As Worksheet: Set ws = ActiveSheet
' Reference the range.
Dim LastRow As Long: LastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
If LastRow < 2 Then Exit Sub ' no data
Dim rg As Range: Set rg = ws.Range("C2", ws.Cells(LastRow, "F"))
' Write the values from the range to an array.
Dim Data(): Data = rg.Value
' Write the matching rows to a collection.
Dim coll As Collection: Set coll = New Collection
Dim r As Long, rDate As Variant
For r = 1 To UBound(Data, 1)
rDate = Data(r, eCols.ecDate)
If IsDate(rDate) Then
If rDate = Date + 15 Then coll.Add r
End If
Next r
If coll.Count = 0 Then Exit Sub ' no matches
' Send the emails.
Dim olApp As Object: Set olApp = CreateObject("Outlook.Application")
Dim crg As Range, rItem, ErrNum As Long, emCount As Long
Dim olMail As Object, mEmail As String, mName As String, mSurName As String
For Each rItem In coll
mEmail = Data(rItem, eCols.ecEmail)
mName = Data(rItem, eCols.ecName)
mSurName = Data(rItem, eCols.ecSurName)
Set olMail = olApp.CreateItem(0)
With olMail
.To = mEmail
.Subject = "Reminder"
.Body = "Dear " & mName & " " & mSurName _
& ", this is a reminder that your event is coming up " _
& "in 15 days. Please make sure to prepare accordingly."
.SendUsingAccount = olApp.Session.Accounts.Item(MY_EMAIL)
On Error Resume Next ' suppress send error e.g. if invalid email
olMail.Send
ErrNum = Err.Number
On Error GoTo ClearError
End With
' Count and combine cells to be highlighted.
If ErrNum = 0 Then
emCount = emCount + 1
If crg Is Nothing Then
Set crg = rg.Cells(rItem, eCols.ecName)
Else
Set crg = Union(crg, rg.Cells(rItem, eCols.ecName))
End If
End If
Next rItem
ProcExit:
On Error Resume Next
' Highlight cells.
If Not crg Is Nothing Then crg.Interior.Color = vbGreen
' Clean up.
If Not olMail Is Nothing Then Set olMail = Nothing
If Not olApp Is Nothing Then Set olApp = Nothing
' Inform.
MsgBox IIf(emCount = 0, "No", emCount) & " email" _
& IIf(emCount = 1, "", "s") & " sent.", _
IIf(emCount = 0, vbExclamation, vbInformation)
On Error GoTo 0
Exit Sub
ClearError:
Debug.Print "Run-time error '" & Err.Number & "':" & Err.Description
Resume ProcExit
End Sub

How to Convert my VBA process to run in MAC?

I have an excel macro that works perfect in windows (email text extraction), but when I run it in my mac it gives me the error missing the library Microsoft Outlook 16.0 Object Library.
I was thinking in late binding (I tried but I wasn't able to fix it)
Can you pls help me to fix my code in order to run it in my mac? thanks in advance.
Code Below:
Sub DetailExtraction() 'MacVersion
On Error GoTo ErrHandler
Application.ScreenUpdating = False
' SET Outlook APPLICATION OBJECT.
Dim objOutlook As Object
Set objOutlook = CreateObject("Outlook.Application")
' CREATE AND SET A NameSpace OBJECT.
Dim objNSpace As Object
' THE GetNameSpace() METHOD WILL REPRESENT A SPECIFIED NAMESPACE.
Set objNSpace = objOutlook.GetNamespace("MAPI")
' CREATE A FOLDER OBJECT.
Dim myFolder As Object
Set myFolder = objNSpace.GetDefaultFolder(olFolderInbox)
Dim Item As Object
Dim iRows, iCols As Integer
iRows = 2
' LOOP THROUGH EACH ITEMS IN THE FOLDER.
'For Each objItem In myFolder.Items
' LOOP THROUGH EACH ITEMS IN THE SELECTION.
For Each objItem In ActiveExplorer.Selection
If objItem.Class = olMail Then
Dim objMail As Outlook.MailItem ' PROBLEM IS IN THIS LINE
Set objMail = objItem
Cells(iRows, 1) = objMail.SenderEmailAddress
Cells(iRows, 2) = objMail.To
Cells(iRows, 3) = objMail.Subject
Cells(iRows, 4) = objMail.ReceivedTime
Cells(iRows, 6) = objMail.Body
Cells(iRows, 6).WrapText = False
'MsgBox Prompt:=objMail.Body
End If
'WRAP UP FILE OFF
' Cells*i.WrapText = False
' SHOW OTHER PROPERTIES, IF YOU WISH.
'Cells(iRows, 6) = objMail.Body
'Cells(iRows, 5) = objMail.CC
'Cells(iRows, 6) = objMail.BCC
'Cells(iRows, 4) = objMail.Recipients(1)
iRows = iRows + 1
Next
Set objMail = Nothing
' RELEASE.
Set objOutlook = Nothing
Set objNSpace = Nothing
Set myFolder = Nothing
ErrHandler:
Debug.Print Err.Description
Application.ScreenUpdating = True
MsgBox "Environments Details Extracted from the Selected Emails (" & iRows - 2 & ")"
End Sub

Excel-created Outlook appointment only notifies me

I am trying to set up an Outlook calendar at work, from Excel data sheets.
I run a query to get data, then treat it, and fill Outlook calendar events.
The problem is, when I enter my required attendees, via my olAppointmentItem, it only notifies me and fills my calendar, not my colleagues' calendars.
I think this might come from the fact that I create it from my own Outlook account.
Here is the mapping of my Excel sheet:
Here is the code I use:
Sub RegisterAppointmentList()
' adds a list of appointments to the Calendar in Outlook
Dim olApp As Outlook.Application
Dim olAppItem As Outlook.AppointmentItem
Dim row As Long
On Error Resume Next
Worksheets("to_be_added").Activate 'worksheet with the list of my appointments to be added
Set olApp = GetObject("", "Outlook.Application")
On Error GoTo 0
If olApp Is Nothing Then
On Error Resume Next
Set olApp = CreateObject("Outlook.Application")
On Error GoTo 0
If olApp Is Nothing Then
MsgBox "Outlook is not available!"
Exit Sub
End If
End If
row = 2 ' first row with appointment data in the active worksheet
Dim mysub, myStart, myEnd
While Len(Cells(row, 2).text) <> 0
mysub = "Test"
myStart = DateValue("09/20/2019") + TimeValue("8:00") 'date and time
myEnd = DateValue("09/20/2019") + TimeValue("9:00") 'date and time
Set olAppItem = olApp.CreateItem(olAppointmentItem)
' set default appointment values
.Location = "Office" 'Location of my event
.Body = "Test appointment" 'title
.ReminderSet = True
.BusyStatus = olBusy 'doesn't need to set people busy
```
.RequiredAttendees = "me#company.com" 'this works just fine
.RequiredAttendees = "colleague#company.com" 'this doesn't work
```
'On Error Resume Next
.Start = myStart
.End = myEnd
.AllDayEvent = False
.Subject = mysub
'.Location = Cells(row, 9).Value
'.Body = Cells(row, 8).Value
'.ReminderSet = True
'.BusyStatus = olBusy
.Categories = "In" 'My own categories (two possibilities, In or Out)
On Error GoTo 0
.Save
End With
row = row + 1
Wend
Set olAppItem = Nothing
Set olApp = Nothing
End Sub
I think this is just a parameter that doesn't catch or something, because it works fine on my own calendar, I get reminders as well as events.
You created an appointment with a superfluous .RequiredAttendees property.
You did not attempt to .Send.
Sub RegisterAppointmentList_SendMeetingInvitation_Minimal()
' Most Excel-related code is removed
' Create a meeting from an appointment
Dim olApp As Outlook.Application
Dim olAppItem As Outlook.AppointmentItem
Dim myStart As Date
Dim myEnd As Date
On Error Resume Next
Set olApp = GetObject("", "Outlook.Application")
On Error GoTo 0
If olApp Is Nothing Then
On Error Resume Next
Set olApp = CreateObject("Outlook.Application")
On Error GoTo 0
If olApp Is Nothing Then
MsgBox "Outlook is not available!"
Exit Sub
End If
End If
myStart = DateValue("09/21/2019") + TimeValue("8:00") 'date and time
myEnd = DateValue("09/21/2019") + TimeValue("9:00") 'date and time
Set olAppItem = olApp.CreateItem(olAppointmentItem)
With olAppItem
' set default appointment values
.Location = "Office" 'Location of my event
.Body = "Test appointment"
.ReminderSet = True
.BusyStatus = olBusy
.RequiredAttendees = "me#company.com"
.RequiredAttendees = "colleague#company.com"
.Start = myStart
.End = myEnd
.AllDayEvent = False
.Subject = "Test"
' Change appointment to meeting
.MeetingStatus = olMeeting
.Display ' change to .Send when tested
End With
End Sub

Use Excel to make appointment in All Public Folders Calendar in 2013 MS Exchange

My code works fine in the default calendar but I am unable to get it to made an appointment in the AllPublicFolders Calendar. I am unable to call the function GetPublicFolder because I am new using VBA. Any help would be greatly appreciated.
Here is my code with "Big Store A Calendar in the all public folders:
Option Explicit
Sub RegisterAppointmentList()
' adds a list of appointments to the Calendar in Outlook
Dim olApp As Outlook.Application
Dim olAppItem As Outlook.AppointmentItem
Dim r As Long
On Error Resume Next
'Worksheets("Schedule").Activate
Worksheets("Appt").Activate
Set olApp = GetObject("", "Outlook.Application")
On Error GoTo 0
If olApp Is Nothing Then
On Error Resume Next
Set olApp = CreateObject("Outlook.Application")
On Error GoTo 0
If olApp Is Nothing Then
MsgBox "Outlook is not available!"
Exit Sub
End If
End If
'r = 6 ' first row with appointment data in the active worksheet
r = 2 ' first row with appointment data in the active worksheet
Dim mysub, myStart, myEnd
While Len(Cells(r, 2).Text) <> 0
mysub = Cells(r, 2) & ", " & Cells(r, 3)
myStart = DateValue(Cells(r, 5).Value) + Cells(r, 6).Value
myEnd = DateValue(Cells(r, 7).Value) + Cells(r, 8).Value
'DeleteTestAppointments mysub, myStart, myEnd
Set olAppItem = olApp.CreateItem(olAppointmentItem) ' creates a new appointment
With olAppItem
' set default appointment values
.Location = Cells(r, 2)
.Body = Cells(r, 3).Value
.ReminderSet = False
.BusyStatus = olFree
'.RequiredAttendees = "johndoe#microsoft.com"
On Error Resume Next
.Start = myStart
.End = myEnd
.Subject = Cells(r, 1)
.Location = Cells(r, 2)
.Body = Cells(r, 3).Value
'.ReminderSet = True
'.BusyStatus = olBusy
.Categories = Cells(r, 4).Value
On Error GoTo 0
.Save ' saves the new appointment to the default folder
End With
r = r + 1
Wend
Set olAppItem = Nothing
Set olApp = Nothing
' Print the Appt Sheet
Sheets("Sheet1").PrintOut
MsgBox "The Appt Sheet Printed and the Appt was entered in your default calendar on May 31st!"
End Sub
‘-------------------------I Need to get correct Public folder for the Exchange calendar -------------
‘I am using VBA for excel workbooks and need to create appointments in 2 public folder shared calendars
‘I need to get code like the code below to create appointments in the shared public calendar – ‘
‘I determine which calendar for the appointment using a workbook cell which is a list box of the 2 calendar names –
‘ Big Store A Calendar or Big Store B Calendar
' GetFolder - Gets a Public folder based on a string path - e.g.
'If Folder name in English is
'Public Folders\All Public Folders\Big Store A Calendar or
‘'Public Folders\All Public Folders\Big Store B Calendar
Public Function GetPublicFolder(strFolderPath)
Dim colFolders
Dim objFolder
Dim arrFolders
Dim i
On Error Resume Next
strFolderPath = Replace(strFolderPath, "/", "\")
arrFolders = Split(strFolderPath, "\")
Set objFolder = Application.Session.GetDefaultFolder(18) ‘This is the correct folder # for “All Public Folders”
Set objFolder = objFolder.Folders.Item(arrFolders(0))
If Not objFolder Is Nothing Then
For i = 1 To UBound(arrFolders)
Set colFolders = objFolder.Folders
Set objFolder = Nothing
Set objFolder = colFolders.Item(arrFolders(i))
If objFolder Is Nothing Then
Exit For
End If
Next
End If
Set GetPublicFolder = objFolder
Set colFolders = Nothing
' Set objApp = Nothing
Set objFolder = Nothing
End Function
Application in Set objFolder = Application.Session.GetDefaultFolder(18) is Excel. You want to use Outlook.
Sub DisplyOutlookPublicFolderFromExcel()
Dim olApp As Outlook.Application
Dim olAppItem As Outlook.AppointmentItem
Dim pubCal As Folder
Set olApp = CreateObject("Outlook.Application")
Set pubCal = GetPublicFolder(olApp, "All Public Folders\Big Store A Calendar")
pubCal.Display
Set olAppItem = Nothing
Set olApp = Nothing
Set pubCal= Nothing
End Sub
Public Function GetPublicFolder(objApp, strFolderPath)
Dim colFolders
Dim objFolder
Dim arrFolders
Dim i
On Error Resume Next
strFolderPath = Replace(strFolderPath, "/", "\")
arrFolders = Split(strFolderPath, "\")
Set objFolder = objApp.Session.GetDefaultFolder(18) 'This is the correct folder # for “All Public Folders”
Set objFolder = objFolder.Folders.Item(arrFolders(0))
If Not objFolder Is Nothing Then
For i = 1 To UBound(arrFolders)
Set colFolders = objFolder.Folders
Set objFolder = Nothing
Set objFolder = colFolders.Item(arrFolders(i))
If objFolder Is Nothing Then
Exit For
End If
Next
End If
Set GetPublicFolder = objFolder
Set colFolders = Nothing
Set objApp = Nothing
Set objFolder = Nothing
End Function

Move a specific number of emails from shared Outlook folder

Every few days I manually move a specified number of emails from a shared network mailbox to subfolders of team managers. They want them moved from oldest to newest. Both the managers and the number can change each time.
I wrote a script for moving a small number of emails with a specific subject line in the folder to a subfolder to be worked by a certain group.
I have tried to adapt this to my current task.
Sub Moverdaily()
On Error GoTo errHandler
Dim olApp As Outlook.Application
Dim objNS As Outlook.Namespace
Dim olFolder As Outlook.MAPIFolder
Dim msg As Outlook.MailItem
Dim manager= As Outlook.MAPIFolder
Dim cell,start,finish,rng As Range
Dim countE,countM As Integer
Dim emcount, casecount, movedcount
Set rng = Range(Range("A2"), Range("A2").End(xlDown))
Set olApp = Outlook.Application
Set objNS = olApp.GetNamespace("MAPI")
Set olFolder = objNS.Folders("Documents").Folders("Inbox")
Set manager = objNS.Folders("Document").Folders("Inbox").Folders("Manager")
Set finish = ThisWorkbook.Sheets("Mover").Range("I11")
Set start = ThisWorkbook.Sheets("Mover").Range("I10")
start.Value = Format(Now, "hh:mm:ss")
Set emcount = Range("I12")
Set casecount = Range("I13")
Set movedcount = Range("I14")
countM = 0
countE = 0
For i = olFolder.Items.count To 1 Step -1
For Each cell In rng
If (cell.Text = (onlyDigits(msg.Subject))) Then
msg.move manager
countM = 1 + countM
cell.Offset(0, 1).Value = "Moved"
End If
Next
countE = 1 + countE
Next
finish.Value = Format(Now, "hh:mm:ss")
emcount.Value = countE
casecount.Value = rng.count
movedcount.Value = countM
errHandler:
MsgBox ("Error " & Err.Number & ": " & Err.Description)
Exit Sub
End Sub
Firstly, do not use "for each" with a collection that you change - MailItem.Mpve removes an itemn from that collection. Use a for i = Items.Count to 1 step -1 instead.
Secondly, do not loop through all item - if you already know the entry ids (rngarry), simply call Namespace.GetItemfromID.

Resources