Change response to Outlook meeting and add text - vba

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.

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.

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.

Outlook automatically change reminder based on category

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

Outlook - check email address type

I am trying to make a macro in Outlook that will scan the To: list for a certain text string, and spit out a message if all but one (or two, etc) addresses have it. Is there a simple way to do this?
Essentially, I am trying to write something that'll avoid being able to send a restricted message to a bunch of people with the string 'xyz' in the address, if one or more do not have it. AutoComplete makes this difficult, without checking through one-by-one.
This is possible using Outlook VBA.
You'd have to write an event hook for when the user sends an email. This is done using the Application_ItemSend(ByVal Item As Object, Cancel As Boolean) where Item is the item being sent (email or appointment), and cancel is a boolean you can set to stop the email from being sent.
In your code you would want to look at the recipients collection on the Item object to see who is going to be receiving the email.
For example:
Dim CurrRecip As Recipient
For Each CurrRecip in Item.Recipients
If InStr(1, CurrRecip.Address , "your search text here" , vbCompareText ) Then
debug.print "Message here..."
End If
Next CurrRecip
Hopefully that helps...