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

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.

Related

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.

Outlook Macro to delete old messages when a new message with same subject arrives

Am trying to write a outlook VB macro, to achieve following:
Triggers when a new email arrives.
Go to a folder inside Inbox - temp1.
Check if there is an existing email which matches the subject of
this new email.
Delete the old email.
Code:
Option Explicit
Private objNS As Outlook.NameSpace
Private WithEvents objItems As Outlook.Items
Private Sub Application_Start()
Dim olApp As Outlook.Application
Dim objWatchFolder As Outlook.Folder
Set olApp = Outlook.Application
Set objNS = Application.GetNamespace("MAPI")
'Set the folder and items to watch:
Set objWatchFolder = objNS.GetDefaultFolder(olFolderInbox).Folders("temp1")
Set objItems = objWatchFolder.Items
Set objWatchFolder = Nothing
End Sub
Private Sub objItems_ItemAdd(ByVal Item As Object)
Dim intCount As Integer
Dim objVariant As Variant
For intCount = objItems.Count To 1 Step -1
Set objVariant = objItems.Item(intCount)
If objVariant.Subject = Item.Subject And objVariant.SentOn < Item.SentOn
Then
objVariant.Delete
Else
End If
Next
End Sub
Issue:
Macro not getting triggered.
Notes:
Have Trust center settings updated to enable macros.
Have added this code in Class Module
When I do F5, it doesn't show any MACRO that it can run.
Seeking some expert help pls!
(1) You need to handle the NewMailEx event of the Application class which is fired when a new item is received in the Inbox. The NewMailEx event fires when a new message arrives in the Inbox and before client rule processing occurs. You can use the Entry ID returned in the EntryIDCollection array to call the NameSpace.GetItemFromID method and process the item. Use this method with caution to minimize the impact on Outlook performance. However, depending on the setup on the client computer, after a new message arrives in the Inbox, processes like spam filtering and client rules that move the new message from the Inbox to another folder can occur asynchronously. You should not assume that after these events fire, you will always get a one-item increase in the number of items in the Inbox.
(2) It looks like you already know how to get the a subfolder of Inbox:
Set objWatchFolder = objNS.GetDefaultFolder(olFolderInbox).Folders("temp1")
(3) To find items with the same subject you need to use the Find/FindNext or Restrict methods of the Items class instead of iterating over all items in the folder. Read more about these methods in the following articles:
How To: Use Find and FindNext methods to retrieve Outlook mail items from a folder (C#, VB.NET)
How To: Use Restrict method to retrieve Outlook mail items from a folder
Also if you need to find items in multiple folders you may find the AdvancedSearch method of the Application class helpful. The key benefits of using the AdvancedSearch method in Outlook are:
The search is performed in another thread. You don’t need to run another thread manually since the AdvancedSearch method runs it automatically in the background.
Possibility to search for any item types: mail, appointment, calendar, notes etc. in any location, i.e. beyond the scope of a certain folder. The Restrict and Find/FindNext methods can be applied to a particular Items collection (see the Items property of the Folder class in Outlook).
Full support for DASL queries (custom properties can be used for searching too). You can read more about this in the Filtering article in MSDN. To improve the search performance, Instant Search keywords can be used if Instant Search is enabled for the store (see the IsInstantSearchEnabled property of the Store class).
You can stop the search process at any moment using the Stop method of the Search class.
See Advanced search in Outlook programmatically: C#, VB.NET for more information.
(4) Use the Delete method for removing items.
Items.ItemAdd Event (Outlook) describes how to apply the ItemAdd event in a Class module. You would then use Application_Startup in ThisOutlookSession to initialize objItems.
What you have is code for the ThisOutlookSession module.
You are watching the ItemAdd event on the temp1 folder, not the Inbox.

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