An Outlook Calendar owner wanted to know how to notify a delegate that a new appointment was scheduled when adding an appointment to the calendar. Solution: VBA that watches for a new appointment item and sends an email to a predetermined email address.
To avoid sending email for personal appointments, the VBA looks for a category named "private" and only sends an email if that category is NOT assigned to the appointment. You could use a subject filter to check for the word Private as the first word in the subject instead:
If Item.Class = olAppointment And _ Left(Item.Subject, 8) <> "Private:" Then
With a little tweaking, the delegate could generate the email to the boss when she adds a new appointment to the boss's calendar.
Send an Email when a New Appointment is added to Calendar
Private WithEvents Items As Outlook.Items Private Sub Application_Startup() Dim Ns As Outlook.NameSpace Set Ns = Application.GetNamespace("MAPI") Set Items = Ns.GetDefaultFolder(olFolderCalendar).Items End Sub Private Sub Items_ItemAdd(ByVal Item As Object) On Error Resume Next If Item.Class = olAppointment And _ Item.Categories <> "private" Then Dim objMsg As MailItem Set objMsg = Application.CreateItem(olMailItem) objMsg.To = "alias@domain.com" objMsg.Subject = Item.Subject objMsg.Body = "New appointment added to " & Item.Organizer & "'s calendar." & _ vbCrLf & "Subject: " & Item.Subject & " Location: " & Item.Location & _ vbCrLf & "Date and time: " & Item.Start & " Until: " & Item.End 'use Display instead of Send if you want to add a note before sending objMsg.Send Set objMsg = Nothing End If End Sub
Watching for new items in a non-default calendars
If the calendar is not your default calendar, you need to use the Function for non-default folders at Working with VBA and non-default Outlook Folders.
After adding the GetFolderPath function to the module, change
Set Items = Ns.GetDefaultFolder(olFolderCalendar).Items
to
Set Items = GetFolderPath("other-datafile-display-name\Calendar").Items
Don't forget to change the display name to the name that is used in the folder list.
Watch for new appointments in a Shared Calendar
To watch for updates in a shared calendar (Exchange Server), you need to resolve the recipient and use GetSharedDefaultFolder. Replace the Application_Startup macro with this, using the shared mailbox's display name as it appears in the GAL.
Private Sub Application_Startup() Dim Ns As Outlook.NameSpace Dim CalendarFolder As Outlook.Folder Dim objOwner As Outlook.Recipient Set Ns = Application.GetNamespace("MAPI") Set objOwner = Ns.CreateRecipient("Mary Contrary") objOwner.Resolve 'MsgBox objOwner.Name If objOwner.Resolved Then Set CalendarFolder = Ns.GetSharedDefaultFolder(objOwner, olFolderCalendar) Set Items = CalendarFolder.Items End If End Sub
Watch for Updates
To watch for updates, you'll use the same code in a procedure named Private Sub Items_ItemChange(ByVal Item As Object). If you are watch for new or updated items, add this code to the module after the ItemAdd code above. If you are only watching for the ItemChange event, you need to use the Application_Startup and declaration code from above. (Or use the code above and change ItemAdd to ItemChange.)
Private Sub Items_ItemChange(ByVal Item As Object) On Error Resume Next If Item.Class = olAppointment Then Dim objMsg As MailItem Set objMsg = Application.CreateItem(olMailItem) objMsg.To = "alias" objMsg.Subject = Item.Subject objMsg.Body = "Appointment changed " & Item.Organizer & "'s calendar." & _ vbCrLf & "Subject: " & Item.Subject & " Location: " & Item.Location & _ vbCrLf & "Date and time: " & Item.Start & " Until: " & Item.End 'use Display instead of Send if you want to add a note before sending objMsg.Display Set objMsg = Nothing End If End Sub
Send message from Creator
If you have multiple users sharing the same calendar and set the macro up for each user, when the new calendar event syncs to each computer, multiple messages will be generated. To prevent this, use a properyaccessor to get the account name that created the appointment and compare it to the default email account name. If they match, generate the message.
This code watches the user's default calendar. See Working with VBA and non-default Outlook Folders if you need to watch a different calendar.
Private WithEvents Items As Outlook.Items Private Sub Application_Startup() Dim Ns As Outlook.NameSpace Set Ns = Application.GetNamespace("MAPI") Set Items = Ns.GetDefaultFolder(olFolderCalendar).Items End Sub Private Sub Items_ItemAdd(ByVal Item As Object) 'On Error Resume Next Dim CreatedByName 'As String Dim pa As Outlook.propertyAccessor Set olns = Application.GetNamespace("MAPI") Set pa = Item.propertyAccessor CreatedByName = pa.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x3FFA001E") If CreatedByName = olns.Accounts.Item(1) Then 'If Item.Class = olAppointment And _ Item.Categories <> "private" Then Dim objMsg As MailItem Set objMsg = Application.CreateItem(olMailItem) objMsg.To = "alias@domain.com" objMsg.Subject = Item.Subject objMsg.Body = "New appointment added to " & Item.Organizer & "'s calendar." & "By " & CreatedByName & _ vbCrLf & "Subject: " & Item.Subject & " Location: " & Item.Location & _ vbCrLf & "Date and time: " & Item.Start & " Until: " & Item.End 'use Display instead of Send if you want to add a note before sending objMsg.Display 'Send Set objMsg = Nothing End If ' End If Set olns = Nothing End Sub
Hi Diane,
I'm struggling with this macro. Here is my scenario: I have two mailboxes - me@domain.com and InteractionsCalendar@domain.com, which shows up in my company's address book as Interactions Calendar. I am the "owner" of the Interactions Calendar mailbox, but it is not my default mailbox. I have granted Author permissions to other users (user3, user4, etc.) so that they can send meeting invitations on this calendar, "I" have shared the calendar with them (they received a sharing invitation from Interactions Calendar but I'm the actual person).
I want to generate an e-mail to user2@domain.com every time I or one of the Authors adds, updates, or deletes a meeting from the Interactions Calendar. It's not my default calendar, but it's not a second calendar on my default mailbox. It's the default calendar on an entirely separate mailbox, but it's not quite like another user shared the calendar with me, because I'm the owner and have full access to this second mailbox. So I'm struggling with which code pieces to use from this page and the page on "Working with VBA and non-default Outlook Folders". Can you provide me some guidance?
I've been playing with your code and I can get (2) operations to work separately in the code, but not together - I can add events to calendar then it sends an email, or I can delete events and it sends an email. But I can't do both in one combined code. Can you help?
Private WithEvents Items As Outlook.Items
Private Sub Application_Startup()
Dim Ns As Outlook.NameSpace
Set Ns = Application.GetNamespace("MAPI")
Set Items = Ns.GetDefaultFolder(olFolderCalendar).Items
End Sub
Private Sub Items_ItemAdd(ByVal Item As Object)
On Error Resume Next
If Item.Class = olAppointment And _
Item.Categories "private" Then
Dim objMsg As MailItem
Set objMsg = Application.CreateItem(olMailItem)
objMsg.To = "jaime@whatever.com"
objMsg.Subject = "New entry on Whatever's calendar"
objMsg.Body = Item.Subject & _
vbCrLf & "" & _
vbCrLf & "Location: " & Item.Location & _
vbCrLf & "" & _
vbCrLf & Item.Start & _
vbCrLf & "until" & _
vbCrLf & Item.End
'use Display instead of Send if you want to add a note before sending
objMsg.Send
Set objMsg = Nothing
End If
End Sub
Diane,
WHat are the steps to get this to work? I have Outlook 2016. I added developer toolbar, new Macro, named it EmailCal, copy paste your code. It has a syntax error, and Private WithEvents Items As Outlook.Items is all in red.
New to Outlook VBA, just curious if you have a step by step guide on how to create and run a module.
Thanks
did you paste the macros in thisoutlooksession?
I have an outlook.com that i have shared with my wife, when i make a change, she is getting an email notification that the calendar event was updated, which is not desirable. I can't find any settings to control this behavior. This is something that just recently started occurring. Do you have any idea what would be causing this or how to control it?
try options, calendar - under shared calendars.
Diane,
Running Outlook 2013 and I'm trying to e-mail the day's calendar whenever a new mtg is scheduled. It sounds very similar to your "Send an Email when a New Appointment is added to Calendar", which I've successfully implemented, but just do not know how to access Outlook's e-mail calendar feature. I've looked at other threads, but it looks rather involved. Wish I had the record macro feature here which is common to other MS Office apps...
Hi,
I was wondering if it would be possible to check multiple shared calendar's (Exchange Server) at the same time? How would I set this up?
Thx
You can. You need to set a unique reference for each one in the app start macro then repeat the itemadd macros - what I usually do is create 'stub' macros that pass the item to the macro that does the work, especially when everything in the macros would be identical. Private WithEvents Items As Outlook.Items Private WithEvents shared1 As Outlook.Items Private Sub Application_Startup() Dim Ns As Outlook.NameSpace Set Ns = Application.GetNamespace("MAPI") Set Items = Ns.GetDefaultFolder(olFolderCalendar).Items ' shared folder code goes here Set shared1 = ' the code End Sub Private Sub Items_ItemAdd(ByVal Item As Object) Dowhatever item End sub Private Sub shared1_ItemAdd(ByVal Item As Object) Dowhatever item End sub Sub dowhatever(ByVal Item As Object) On Error Resume Next If Item.Class = olAppointment And _ Item.Categories "private" Then Dim objMsg As MailItem Set objMsg = Application.CreateItem(olMailItem) objMsg.To = "alias@domain.com" objMsg.Subject = Item.Subject objMsg.Body = "New appointment added to " & Item.Organizer & "'s calendar." & _ vbCrLf & "Subject: " & Item.Subject & " Location: " & Item.Location & _ vbCrLf & "Date and time: " & Item.Start & " Until: " & Item.End 'use Display instead of Send if you want to add a note before sending objMsg.Send Set… Read more »
Hi, Thanks for you answer but I am not quite sure what I am supposed to do. ( I am new to VBA) I am currently using the following code: Private WithEvents Items As Outlook.Items Private Sub Application_Startup() Dim Ns As Outlook.NameSpace Dim CalendarFolder As Outlook.folder Dim objOwner As Outlook.Recipient Set Ns = Application.GetNamespace("MAPI") Set objOwner = Ns.CreateRecipient("mailadressharedfolder@company.com") objOwner.Resolve 'MsgBox objOwner.Name If objOwner.Resolved Then Set CalendarFolder = Ns.GetSharedDefaultFolder(objOwner, olFolderCalendar) Set Items = CalendarFolder.Items End If End Sub Private Sub Items_ItemAdd(ByVal Item As Object) 'On Error Resume Next Dim CreatedByName 'As String Dim pa As Outlook.PropertyAccessor Set olns = Application.GetNamespace("MAPI") Set pa = Item.PropertyAccessor CreatedByName = "user@company.com" If CreatedByName = olns.Accounts.Item(1) Then 'If Item.Class = olAppointment And _ Item.Categories "private" Then Dim objMsg As MailItem Set objMsg = Application.CreateItem(olMailItem) objMsg.To = "receiver@company.com" objMsg.Subject = Item.Subject & " " & Item.Start objMsg.Body = "subject" & Item.Organizer & "'s calendar." & "By " & CreatedByName & _ vbCrLf & "Subject: " & Item.Subject & _ vbCrLf & "Date and time: " & Item.Start & " Until: " & Item.End & _ vbCrLf & vbCrLf & Item.Body 'use Display instead of Send if you want to add a note before sending objMsg.Send Set objMsg… Read more »
Add this at the top:
Private WithEvents sItems As Outlook.Items
Add this to app start:
Dim CalendarShareFolder As Outlook.folder
Dim objOwnerS As Outlook.Recipient
Set objOwnerS = Ns.CreateRecipient("second account")
objOwnerS.Resolve
If objOwnerS.Resolved Then
Set CalendarShareFolder = Ns.GetSharedDefaultFolder(objOwner, olFolderCalendar)
Set sItems = CalendarFolder.Items
then duplicate the items add sub, renaming it.
Private Sub sItems_ItemAdd(ByVal Item As Object)
if everything is identical in both itemadd macros, you could use stubs to call a 3rd macro that is shared but i have a meeting starting in 5 minutes and don't have time to do it. I have stub examples on the site though.
Hello,
VBA isn't an area I know about and I'm trying to get a custom email sent to an address once a NEW appointment is added to a shared "Training" calendar.
I have merged the code below but it's not working I believe, can someone help me please? (Using Outlook 2013 and may go to 2016 soon):
Private Sub Application_Startup(ByVal Item As Object)
Dim Ns As Outlook.NameSpace
Dim CalendarFolder As Outlook.Folder
Dim objOwner As Outlook.Recipient
Set Ns = Application.GetNamespace("MAPI")
Set objOwner = Ns.CreateRecipient("Training")
objOwner.Resolve
'MsgBox objOwner.Name
If objOwner.Resolved Then
Set CalendarFolder = Ns.GetSharedDefaultFolder(objOwner, olFolderCalendar)
Set Items = CalendarFolder.Items
End If
Dim objMsg As MailItem
Set objMsg = Application.CreateItem(olMailItem)
objMsg.To = "MYSELF@DOMAIN.co.uk"
objMsg.Subject = "Training appointment"
objMsg.Body = Item.Subject & "with" & Item.Organizer & _
vbCrLf & "Subject: " & Item.Subject & _
vbCrLf & "#priority medium" & _
vbCrLf & "#due" & Item.Start & _
vbCrLf & "#set customer= CODE - NAME" & Item.End
'use Display instead of Send if you want to add a note before sending
objMsg.Send
Set objMsg = Nothing
End Sub
you need two macros - the app startup to tell it which folder to watch and the itemadd that actually watches the folder.
*snip*
Set CalendarFolder = Ns.GetSharedDefaultFolder(objOwner, olFolderCalendar)
Set Items = CalendarFolder.Items
End If
End Sub
Private Sub Items_ItemAdd(ByVal Item As Object)
Dim objMsg As MailItem
Set objMsg = Application.CreateItem(olMailItem)
*snip*
Also, you need to reference items, not item:
objMsg.Body = Items.subject...
You also need this at the very top of the macros:
Private WithEvents Items As Outlook.Items
Hi Diane,
Great article thank you! - I was able to set up email notifications for a Public Shared Calendar when anything is added or changed in the Calendar. However, I was wondering if there is a way to get notified when something is deleted from a Calendar, and have a notification email sent which includes info about what was deleted. I was able to setup notifications using ItemRemove() - but this lacks info about what was removed. I've been trying to setup BeforeDeleteItem - but no matter what I do I can't get it to work, even with a local calendar. The script just doesn't fire when I delete something. I am using Office 365.
I'll take a look and see if i can come up with something that works better then this - which only works if you use the macro, not the X button.
Public WithEvents myItem As Outlook.AppointmentItem
Public olApp As New Outlook.Application
Public Sub DeleteMail()
Const strCancelEvent = "Application-defined or object-defined error"
On Error GoTo ErrHandler
Set olApp = CreateObject("Outlook.Application")
Set myItem = olApp.ActiveExplorer.Selection.Item(1)
myItem.Delete
Exit Sub
ErrHandler:
MsgBox Err.Description
If Err.Description = strCancelEvent Then
MsgBox "The event was cancelled."
End If
'If you want to execute the next instruction
Resume Next
'Otherwise it will finish here
End Sub
Private Sub myItem_BeforeDelete(ByVal Item As Object, Cancel As Boolean)
Set objMsg = Application.CreateItem(olMailItem)
With objMsg
.To = "Alias@domain.com"
.Subject = Item.Subject & " was deleted on " & Now
.Body = Item.Start & vbCrLf & Item.Body
.Display
End With
Set objMsg = Nothing
End Sub
Here's a better one - watch the deleted items folder and when an appointment items hits, create the email. it doesn't work when you delete a recurring series and I'm not sure why.
Private WithEvents trashCalendar As Outlook.Items
Private Sub Application_Startup()
Dim NS As Outlook.NameSpace
Set NS = Application.GetNamespace("MAPI")
' watch for new items
Set trashCalendar = NS.GetDefaultFolder(olFolderDeletedItems).Items
Set NS = Nothing
End Sub
Private Sub trashCalendar_ItemAdd(ByVal Item As Object)
If Not TypeOf Item Is AppointmentItem Then Exit Sub
On Error Resume Next
Set objMsg = Application.CreateItem(olMailItem)
With objMsg
.To = "Alias@domain.com"
.Subject = Item.Subject & " was deleted on " & Now
.Body = Item.Start & vbCrLf & Item.Body
.Display
End With
Set objMsg = Nothing
End Sub
This works perfectly...but only with local calendars not Public :( - Thanks for the effort! I'm going to investigate if the exchange server settings can be tweaked.
Oh, it only works on appointments you delete - it should work for any calendar item that hits your deleted items folder.
Thanks Diane,
I was able to get BeforeDeleteItem to work with local calendars, or sub-calendars - but for some reason it doesn't work with a Public shared calendar. This same code works well with the Update and New routines (on Public Shared Calendars). The only thing I notice is when I delete from a Public Calendar it says it will be permanently deleted...not sure if that's a clue.
Here's the code I'm using so far:
Dim WithEvents JobFolder As Outlook.Folder
Dim objDelFolder As Outlook.Folder
Private Sub Application_Quit()
Set olkCalendar = Nothing
Set JobFolder = Nothing
Set objDelFolder = Nothing
End Sub
'Sets up the Calendar - drill down the folder hierarchy
Private Sub Application_Startup()
'Change the folder name on the next line as needed'
Set JobFolder = Session.GetDefaultFolder(olPublicFoldersAllPublicFolders).Folders("TRSI - Canada")
Set JobFolder = JobFolder.Folders("Marine Jobs")
'Set JobFolder = Session.GetDefaultFolder(olFolderCalendar).Folders("Test")
Set objDelFolder = Application.Session.GetDefaultFolder(olFolderDeletedItems)
End Sub
Private Sub JobFolder_BeforeItemMove(ByVal Item As Object, ByVal MoveTo As MAPIFolder, Cancel As Boolean)
MsgBox "Fired"
If MoveTo Is Nothing Then
Debug.Print Item.Subject & " was hard deleted"
MsgBox Item.Subject & "hard delete"
ElseIf MoveTo = objDelFolder Then
Debug.Print Item.Subject & " was moved to Deleted Items"
MsgBox Item.Subject & "soft delete"
End If
End Sub
>> it will be permanently deleted...not sure if that's a clue.
I'm sure it is a clue. I know the code i used that watches the deleted items folder won't work, because the apt isn't moved to the deleted items folder. I'll play with it this afternoon.