Outlook automatically change reminder based on category - vba

I need to automate Outlook so that when a user sets a certain category on an appointment, it automatically sets the reminder time based on the category.
For example, the user has an "On site meeting" category and an "Off site meeting" category. He wants the reminder time to automatically change to 15 minutes for an on site meeting and 30 minutes for the off site meeting. He understands that if he sets the category wrong or applies both categories the time wont change correctly.
Is it possible to do this, and if so how do I go about it? I imagine there is an event I can catch and handle when an appointment category is changed.
Thank you
EDIT: The appointment requests are received in email, he sets the categories when he accepts the meeting request. The reminder time should be set whenever the category changes.
How to hook up to the event is the part I can't seem to find.

When exactly is the change of reminder time supposed to happen? When initially composing the meeting? Whenever categories are modified?
(e.g. if the user already set a value for the reminder, and then changed the category, would the reminder change?)
Anyway, I guess the solution is to hook up to some events that happen in Outlook and set these values according to your logic. But until the above questions are answered it's not clear which events you'll need to hook up to.

You will want ItemAdd and ItemChange
http://msdn.microsoft.com/en-us/library/office/ff869609(v=office.14).aspx
http://msdn.microsoft.com/en-us/library/office/ff865866(v=office.14).aspx
Something like this:
Public Sub Application_Startup()
Set objCalendar = Outlook.Session.GetDefaultFolder(olFolderCalendar).Items
End Sub
Private Sub objCalendar_ItemAdd(ByVal Item As Object)
setReminder Item
End Sub
Private Sub objCalendar_ItemChange(ByVal Item As Object)
setReminder Item
End Sub
Sub setReminder(ByVal Item As Object)
If InStr(Item.Categories, "A")
' Set the reminder time A
GoTo exitRoutine ' A the longer takes priority over B the shorter
End If
If InStr(Item.Categories, "B")
' Set the reminder time B
End If
exitRoutine:
End Sub

Related

(Outlook) Recurring monthly email sent 2 days before the last Wednesday?

I manually send an email out on the last Monday of every month that is before the last Wednesday of the month. I essentially want email replies on the last Wednesday of every month and send the email 2 days prior on the Monday for notice.
Can this be solved with a VBA/Macro? It can be a meeting or email or anything so long as an email with the same canned text gets sent 2 days before that last Wednesday of each month. Thank you!
Yes, that can be solved with Outlook VBA. You can set up a reminder in Outlook which you can handle and send out your emails 2 days prior the event for notice. Here is sample code that shows how to handle reminders:
Dim WithEvents myolapp As Outlook.Application
Sub Initialize_handler()
Set myolapp = Outlook.Application
End Sub
Private Sub myolapp_Reminder(ByVal Item As Object)
' here you can send emails to notice 2 days before
' or just display the source item
Item.Display
End Sub
The AppointmentItem, MailItem, ContactItem, or TaskItem associated with the reminder is passed as a parameter. If the appointment associated with the reminder is a recurring appointment, Item is the specific occurrence of the appointment that displayed the reminder, not the master appointment. So, I think it is more convenient to create a recurring appointment with a reminder set up.
To handle incoming responses you need to handle the NewMailEx event of the Application class in Outlook. This event fires once for every received item that is processed by Microsoft Outlook. The item can be one of several different item types, for example, MailItem, MeetingItem, or SharingItem. The EntryIDsCollection string contains the Entry ID that corresponds to that item. Use the Entry ID to call the NameSpace.GetItemFromID method and process the item.
Finally, I'd suggest starting from the Getting started with VBA in Office article.

Outlook VBA - Change Meeting Reminder Time on Meeting Accept

I have been burned on more than one occasion where I accept a meeting from someone else, but forget to check the meeting reminder time. Sometimes there is no reminder or it's 15 minutes before the meeting that is all the way on the other side of town.
I'd like to automatically change the meeting time from 0 or 15 minutes to at least 30 minutes and leave anything over 30 minutes unchanged. That or if there is a way to have a message box pop up on a meeting accept that says "Hey, check your meeting reminder time!".
I think this could help a lot of people out. Thanks!
You can set up the MeetingItem.ReminderTime property which returns or sets a date indicating the date and time at which the reminder should occur for the specified item.
To handle incoming items you can use the NewMailEx event of the Application class which is fired once for every received item that is processed by Microsoft Outlook. The item can be one of several different item types, for example, MailItem, MeetingItem, or SharingItem. The EntryIDsCollection string contains the Entry ID that corresponds to that item.
The NewMailEx event fires when a new message arrives in the Inbox and before client rule processing occurs. Use the Entry ID represented by the EntryIDCollection string to call the NameSpace.GetItemFromID method and process the item.
I just caught that a similar article was posted. I did get this to work, so thank you! Here is the exact code I modified.
Public WithEvents objCalendar As Outlook.Folder
Public WithEvents objCalendarItems As Outlook.Items
Private Sub Application_Startup()
Set objCalendar = Outlook.Application.Session.GetDefaultFolder(olFolderCalendar)
Set objCalendarItems = objCalendar.Items
End Sub
Private Sub objCalendarItems_ItemAdd(ByVal Item As Object)
Call SetReminder(Item)
End Sub
Private Sub objCalendarItems_ItemChange(ByVal Item As Object)
Call SetReminder(Item)
End Sub
Private Sub SetReminder(ByVal objCalendarItem As Object)
Dim objMeeting As AppointmentItem
If TypeOf objCalendarItem Is AppointmentItem Then
Set objMeeting = objCalendarItem
If objMeeting.ReminderMinutesBeforeStart < 30 Then
MsgBox "The meeting reminder was under 30 minutes. This will auto set the reminder to 30 minutes. You might want to notify the other participants."
objMeeting.ReminderSet = True
objMeeting.ReminderMinutesBeforeStart = 30
objMeeting.Save
End If
End If
End Sub

Change response to Outlook meeting and add text

I would like to change the response to a meeting, that I have accepted, to tentative and send text like "I'm sorry, but I cannot attend.".
Online, I found solutions that show how to accept, cancel, forward, and copy a meeting.
I also understood that I can open the message to edit before sending the reply with
Item.Respond(olMeetingTentative, False, False)
I would like to have it automated.
I tried the following
Sub tentativeOccurenceWithResponse()
Dim Item As Outlook.AppointmentItem
Dim response As Outlook.MeetingItem
For i = ActiveExplorer.Selection.Count To 1 Step -1
Set Item = ActiveExplorer.Selection.Item(i)
If TypeName(Item) = "AppointmentItem" Then
If Item.ResponseRequested Then
Set response = Item.Respond(olMeetingTentative, True)
response.RTFBody = "Thank you for the invitation. Unfortunatelly, I cannot attend the meeting.\nPlease check my calendar for alternative time slots if my attendance is required."
response.Send
Else
Item.MeetingStatus = olMeetingTentative
End If
Set Item = Nothing
Else
MsgBox "Sorry, you need to select an appointment"
End If
Next
End Sub
The workflow:
I would like to go to my calendar and select meetings that I will not be able to join. Most of them are meeting serious or long time planned. Hence, it was not possible to react when I got the invitation.
I want to notify all Meeting organizers that I cannot attend, but I would like to get updates and might still be able to join in case of vacation changes. (So no decline here.)
First of all, you need to declare the item as a generic object because Outlook folders may contain different kind of items:
Dim Item As Object
Then in the loop you can check out the message class and only after making sure the item is an appointment you can cast it to the required type and process the item further.
For i = ActiveExplorer.Selection.Count To 1 Step -1
Set Item = ActiveExplorer.Selection.Item(i)
If TypeName(Item) = "AppointmentItem" Then
If you need to handle incoming items automatically you can handle the NewMailEx event of the Application class which is fired when a new message arrives in the Inbox and before client rule processing occurs. This event fires once for every received item that is processed by Microsoft Outlook. The item can be one of several different item types, for example, MailItem, MeetingItem, or SharingItem. The EntryIDsCollection string contains the Entry ID that corresponds to that item. So, you are interested in processing meeting items only. To recognize the item you need to get an instance of the incoming Outlook item. Use the Entry ID returned in the EntryIDCollection string to call the NameSpace.GetItemFromID method and process the item.
Also you may consider hooking up the ItemAdd event on the folder. The event is fired when one or more items are added to the specified collection. Note, this event does not run when a large number of items are added to the folder at once.

How can I implement the PropertyChange event?

I wish to get the details of what has been changed in a MailItem.
I have been able to get ItemChange to trigger based upon Application.Session.Folders("TargetFolder") to a variable as such:
Private Sub olInvMbxItems_ItemChange(ByVal X As Object).
I would like to know the property changed in X. If I pass X to an global variable for Private Sub X_PropertyChange(ByVal x As Object), it will miss the first iteration as X was not initialized on the first pass of ItemChange.
How can I monitor a folder of MailItems to detect Category changes. Whilst ItemChange does this, it gives duplication of action, if I look for specific categories, as many changes trigger ItemChange as mentioned here:
Handle ItemChange event when outlook appointments are dismissed
and here:
Outlook Macro that will copy an email I flag and put it in a folder
The binary flag for the UserProperties in the second item will not function as it is not a one-off event.
Outlook Events VBA says to use PropertyChange but doesn't provide a technique for implementation.
There is no way to do that - even on the MAPI level, the store provider does not keep track on what changed. Your only solution is to compare the old (saved elsewhere by you) and new values to see what changed.
Here is a method that works for a single selection. Refinement yet needed, but this is a starting point:
Private WithEvents olExplorer As Outlook.Explorer
Private olCurSel As Selection
Private WithEvents olCurSelItem As Outlook.MailItem
Private Sub olExplorer_SelectionChange()
Set olCurSel = olExplorer.Selection
Set olCurSelItem = Nothing
Dim i As Long
For i = 1 To olCurSel.Count
If TypeName(olCurSel.Item(i)) = "MailItem" Then
Set olCurSelItem = olCurSel.Item(i)
End If
Next i
End Sub
Private Sub olCurSelItem_PropertyChange(ByVal Name As String)
Debug.Print Name; " is what changed!"
End Sub
Using Outlook.Explorer.Selection we can know that an item has been selected. We can then assign that item to and Outlook.MailItem conditionally and use the PropertyChange event of that Outlook.MailItem trigger the action we wish to take.
Problems:
Does not handle multiple selections
SelectionChange is triggered by the Reading Pane on each selection as well. Thus it is fired twice if the reading pane is open. As written above, olCurSelItem is set twice each SelectionChange.
This is only triggered by local changes. Other systems with access to the mailbox may change the item and it will not trigger the action.

Make Outlook AppointmentItem Read-Only

I am creating outlook appointment items programmatically using VBA in MS Access and the Outlook Object Model (though the language shouldn't matter).
Items are added to multiple calendars belonging to a single user that other users are given read/write permissions to. The users have no reason to create or edit appointments on the calendar using Outlook. Appointment data is then stored in backend tables. Essentially, Outlook is being used as my "calendar view."
I am having major issues, however, with users changing appointment items directly in Outlook, which in turn do not update in my backend.
I would love an updateable "ReadOnly" property that can be set per appointment item and that disallows changes unless set back to False...but don't think one exists. Any suggestions?
Things I've tried or dismissed as solutions:
Reminding users of the rules.
Script that finds all mismatched items - this works but is not practical.
Custom Outlook form that doesn't allow edits - doesn't prevent users from dragging appointment around.
UPDATE:
Using the suggestion by nemmy below, I have manged to get this far. This only works if the user selects the appointment before changing anything. It does not work if the appointment is selected and dragged in the same click.
Private WithEvents objExplorer As Outlook.Explorer
Private WithEvents appt As Outlook.AppointmentItem
Public Sub Application_Startup()
Set objExplorer = Application.ActiveExplorer
End Sub
Private Sub objExplorer_SelectionChange()
If objExplorer.CurrentFolder.DefaultItemType = olAppointmentItem Then
If objExplorer.Selection.Count > 0 Then
Set appt = objExplorer.Selection(1)
End If
End If
End Sub
Private Sub appt_Write(Cancel As Boolean)
If Not appt.Mileage = "" Then 'This appointment was added by my program
MsgBox ("Do not change appointments directly in Outlook!")
Cancel = True
appt.Close (olDiscard)
End If
End Sub
Can you hook into the Write Event of appointment items? You could prevent changes being made that way. Something like below might work (Disclaimer not tested):
Public WithEvents myItem As Outlook.AppointmentItem
Sub Initialize_handler()
Set myItem = Application.GetNamespace("MAPI").GetDefaultFolder(olFolderCalendar).Items("Your Appointment")
End Sub
Private Sub myItem_Write(Cancel as boolean)
Cancel=true
End Sub
The problem you have is that the people have write access, can you or is it possible to only give them read access? If that is not acceptable, then my answer is you cannot or should not stop them from changing the items. You need to deal with it. This is what I do.
So when you create the calendar item give it a unique ID for example the ID from your backend table row. Add this to a property of the calendar item like the mileage property.
Now just create an update method which loops through all current calendar items in your table and get them from outlook with the ID, check it has not changed and if it has update your table.
Alternatively and given your comment below;
In my opinion you must control outlook. As such nemmy is on the right track you need to hook into the outlook object probably with the use of an outlook addin. Then you need to get each appointment item that the user opens and check if it has a mileage ID. If it does you either need to tell them to change this in your data base and not outlook, or you need to get the events relevant indicating changes to the appointment item and wait for it to be changed. Then send these changes from outlook to your database.