How to update a meeting? Error: Argument Not Optional - vba

After a recent Outlook update, this code started returning
"Compile Error:Argument Not Optional"
The line Set Travel = Items.Add is triggering the error.
Public Sub AddTravelTime()
Dim coll As VBA.Collection
Dim obj As Object
Dim Appt As Outlook.AppointmentItem
Dim Travel As Outlook.AppointmentItem
Dim Items As Outlook.Items
Dim Before&, After&
Dim Category$, Subject$
'1. Block minutes before and after the appointment
Before = 30
After = 30
'3. Assign this category
Category = "Meeting Cushion Time"
Set coll = GetCurrentItems
If coll.Count = 0 Then Exit Sub
For Each obj In coll
If TypeOf obj Is Outlook.AppointmentItem Then
Set Appt = obj
If TypeOf Appt.Parent Is Outlook.AppointmentItem Then
Set Items = Appt.Parent.Parent.Items
Else
Set Items = Appt.Parent.Items
End If
'4. Use the main appointment's subject
Subject = "Meeting Cushion Time"
If Before > 0 Then
Set Travel = Items.Add ' <------ Compile Error
Travel.Subject = Subject
Travel.Start = DateAdd("n", -Before, Appt.Start)
Travel.Duration = Before
Travel.Categories = Category
Travel.Save
End If
If After > 0 Then
Set Travel = Items.Add
Travel.Subject = Subject
Travel.Start = Appt.End
Travel.Duration = After
Travel.Categories = Category
Travel.Save
End If
End If
Next
End Sub
Private Function GetCurrentItems(Optional IsInspector As Boolean) As VBA.Collection
Dim coll As VBA.Collection
Dim Win As Object
Dim Sel As Outlook.Selection
Dim obj As Object
Dim i&
Set coll = New VBA.Collection
Set Win = Application.ActiveWindow
If TypeOf Win Is Outlook.Inspector Then
IsInspector = True
coll.Add Win.CurrentItem
Else
IsInspector = False
Set Sel = Win.Selection
If Not Sel Is Nothing Then
For i = 1 To Sel.Count
coll.Add Sel(i)
Next
End If
End If
Set GetCurrentItems = coll
End Function
The goal is to add a time buffer before and after each meeting.

The travel object is defined as an instance of the AppointmentItem class:
Dim Travel As Outlook.AppointmentItem
But in the code, you are trying to set another item type:
Set Travel = Items.Add
The default item type for a folder will be returned. Of course, it depends on the folder. But I suspect it is not an appointment item in your case.

If "Items.Add" is asking for more arguments, the implication is the items in that collection have more non-optional arguments, so the default items for that folder are not appointment items.
Option Explicit
Public Sub AddTravelTime()
Dim coll As VBA.Collection
Dim obj As Object
Dim Appt As AppointmentItem
Dim Travel As AppointmentItem
Dim Items As Items
Dim Before As Long
Dim After As Long
Dim Subject As String
' Block minutes before and after the appointment
Before = 30
After = 30
Set coll = GetCurrentItems
If coll.Count = 0 Then Exit Sub
For Each obj In coll
If TypeOf obj Is outlook.AppointmentItem Then
Set Appt = obj
Debug.Print "Appt.Subject: " & Appt.Subject
'https://learn.microsoft.com/en-us/office/vba/api/outlook.folder.defaultitemtype
'https://learn.microsoft.com/en-us/office/vba/api/outlook.olitemtype
If TypeOf Appt.Parent Is outlook.AppointmentItem Then
' recurring appointment
Debug.Print "Appt.Parent.Parent: " & Appt.Parent.Parent
Debug.Print Appt.Parent.Parent.DefaultItemType ' 1 = olAppointmentItem
If Appt.Parent.Parent.DefaultItemType = olAppointmentItem Then
Set Items = Appt.Parent.Parent.Items
Else
Debug.Print Appt.Parent.Parent.DefaultItemType
MsgBox "Default item in " & Appt.Parent.Parent & " is not appointment item."
Exit Sub
End If
Else
Debug.Print "Appt.Parent: " & Appt.Parent
Debug.Print Appt.Parent.DefaultItemType ' 1 = olAppointmentItem
If Appt.Parent.DefaultItemType = olAppointmentItem Then
Set Items = Appt.Parent.Items
Else
Debug.Print Appt.Parent.DefaultItemType
MsgBox "Default item in " & Appt.Parent & " is not appointment item."
Exit Sub
End If
End If
Subject = "Meeting Cushion Time"
If Before > 0 Then
Set Travel = Items.Add
Travel.Subject = Subject
Travel.Start = DateAdd("n", -Before, Appt.Start)
Travel.Duration = Before
Travel.Save
End If
If After > 0 Then
Set Travel = Items.Add
Travel.Subject = Subject
Travel.Start = Appt.End
Travel.Duration = After
Travel.Save
End If
End If
Next
End Sub
Private Function GetCurrentItems(Optional IsInspector As Boolean) As VBA.Collection
Dim coll As VBA.Collection
Dim Win As Object
Dim Sel As Selection
Dim obj As Object
Dim i As Long
Set coll = New VBA.Collection
Set Win = ActiveWindow
If TypeOf Win Is outlook.Inspector Then
IsInspector = True
coll.Add Win.CurrentItem
Else
IsInspector = False
Set Sel = Win.Selection
If Not Sel Is Nothing Then
For i = 1 To Sel.Count
coll.Add Sel(i)
Next
End If
End If
Set GetCurrentItems = coll
End Function

Related

Remove an email from outbox and re-edit

I have VBA code to delay sending messages by five minutes.
Dim obj As Object
Dim Mail As Outlook.MailItem
Dim WkDay As Integer
Dim MinNow As Integer
Dim SendHour As Integer
Dim SendDate As Date
Dim SendNow As String
Dim UserDeferOption As Integer
Function getActiveMessage() As Outlook.MailItem
Dim insp As Outlook.Inspector
If TypeOf Application.ActiveWindow Is Outlook.Inspector Then
Set insp = Application.ActiveWindow
End If
If insp Is Nothing Then
Dim inline As Object
Set inline = Application.ActiveExplorer.ActiveInlineResponse
If inline Is Nothing Then Exit Function
Set getActiveMessage = inline
Else
Set insp = Application.ActiveInspector
If insp.CurrentItem.Class = olMail Then
Set getActiveMessage = insp.CurrentItem
Else
Exit Function
End If
End If
End Function
Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
SendDate = Now()
SendHour = Hour(Now)
MinNow = Minute(Now)
Set obj = getActiveMessage()
If obj Is Nothing Then
'Do Nothing'
Else
If TypeOf obj Is Outlook.MailItem Then
Set Mail = obj
SendMin = 5
SendDate = DateAdd("n", SendMin, SendDate)
Mail.DeferredDeliveryTime = SendDate
End If
End If
Exit Sub
End Sub
I need a way to stop the item from sending. We can't delete it and start again as emails take a long time to compose and are highly detailed.
I'd like to add a button to the ribbon or context menu of Outlook 365, to re-open the email for editing and stop the deferred send.
I get
an object can't be found
Sub MoveEmail()
Dim OutboxFolder As Outlook.Folder
Set OutboxFolder = GetNamespace("MAPI").GetDefaultFolder(olFolderOutbox)
Set MoveFolder = GetNamespace("MAPI").GetDefaultFolder(olFolderInbox).Folders("Drafts")
Dim CurrentItem As Object
For Each CurrentItem In OutboxFolder.Items
CurrentItem.Move MoveFolder
Next CurrentItem
End Sub
Got it sorted, for anyone else...
Sub MoveEmail()
Dim myNamespace As Outlook.NameSpace
Set myNamespace = Application.GetNamespace("MAPI")
Set OutboxFolder = myNamespace.GetDefaultFolder(olFolderOutbox)
Set MoveFolder = myNamespace.GetDefaultFolder(olFolderDrafts)
Dim CurrentItem As Object
For Each CurrentItem In OutboxFolder.Items
CurrentItem.Move MoveFolder
Next CurrentItem
End Sub

Select a mailitem in ActiveExplorer

I have written a macro to open the path to a selected email in the results of the Outlook search.
The email is not automatically marked in the open folder so I search for the email in "ActiveExplorer". With .display, I can open the email, but I could not find a way to select the found email in "ActiveExplorer".
Public Sub MailOrdnerPfad()
Dim obj As Object
Dim Ordner As Outlook.MAPIFolder
Dim Betreff As String
Dim Mail As MailItem
Set obj = Application.ActiveWindow
If TypeOf obj Is Outlook.Inspector Then
Set obj = obj.CurrentItem
Else
Set obj = obj.Selection(1)
End If
Betreff = obj.ConversationTopic
Set Ordner = obj.Parent
Set Application.ActiveExplorer.CurrentFolder = Ordner
For Each Mail In Ordner.Items
If Mail.ConversationTopic = Betreff Then
Mail.Display
Exit For
End If
Next
End Sub
Clear the original selection then add the found item.
Option Explicit
Public Sub MailOrdnerPfad()
Dim obj As Object
Dim Ordner As Folder
Dim ordItem As Object
Dim Betreff As String
Dim myMail As MailItem
Set obj = ActiveWindow
If TypeOf obj Is Inspector Then
Set obj = obj.CurrentItem
Else
Set obj = obj.Selection(1)
End If
If obj.Class = olMail Then
Betreff = obj.ConversationTopic
Debug.Print "Betreff: " & Betreff
Set Ordner = obj.Parent
Set ActiveExplorer.CurrentFolder = Ordner
Debug.Print "Ordner.: " & Ordner
For Each ordItem In Ordner.items
If ordItem.Class = olMail Then
Set myMail = ordItem
Debug.Print "myMail.ConversationTopic: " & myMail.ConversationTopic
If myMail.ConversationTopic = Betreff Then
ActiveExplorer.ClearSelection
' myMail.Display
ActiveExplorer.AddToSelection myMail
Exit For
End If
End If
Next
End If
End Sub

Automatically remove the cancelled meetings

Whenever I receive meeting cancellation, I would like to remove the meeting cancellation request from my inbox and remove the meeting from the Calendar. Below code works for removing the email, but does not remove the meeting. I have to manually go to calendar and click on "Remove from Calendar". Any ideas?
Sub RemoveCancelledMeetingEmails()
Dim objInbox As Outlook.Folder
Dim objInboxItems As Outlook.Items
Dim i As Long
Set objInbox = Application.Session.GetDefaultFolder(olFolderInbox)
For Each Item In objInbox.Items
If TypeOf Item Is Outlook.MeetingItem Then
Dim objMeeting As Outlook.MeetingItem: Set objMeeting = Item
If objMeeting.Class = 54 Then
Dim objAppointment As Outlook.AppointmentItem
'Set objAppointment = objMeeting.GetAssociatedAppointment(True)
'objMeeting.Display
objMeeting.Delete
'Item.Delete
End If
End If
Next
End Sub
Uncommment the GetAssociatedAppointment line (change the parameter to false to avoid creating an appointment if it does not exist) and call objAppointment.Delete
Set olResCalendar = OpenMAPIFolder("\MailboxName\Calendar")
Sub RemoveCanceledAppointments()
Dim olResCalendar As Outlook.MAPIFolder, olApptItem As Outlook.AppointmentItem,
intCounter As Integer
'Change the path to the resource calendar on the next line
Set olResCalendar = OpenMAPIFolder("\MailboxName\Calendar")
For intCounter = olResCalendar.Items.Count To 1 Step -1
Set olApptItem = olResCalendar.Items(intCounter)
If Left(olApptItem.Subject, 9) = "Canceled:" Then
olApptItem.Delete
End If
Next
Set olApptItem = Nothing
Set olResCalendar = Nothing
End Sub
Function OpenMAPIFolder(szPath)
Dim app, ns, flr, szDir, i
Set flr = Nothing
Set app = CreateObject("Outlook.Application")
If Left(szPath, Len("\")) = "\" Then
szPath = Mid(szPath, Len("\") + 1)
Else
Set flr = app.ActiveExplorer.CurrentFolder
End If
While szPath <> ""
i = InStr(szPath, "\")
If i Then
szDir = Left(szPath, i - 1)
szPath = Mid(szPath, i + Len("\"))
Else
szDir = szPath
szPath = ""
End If
If IsNothing(flr) Then
Set ns = app.GetNamespace("MAPI")
Set flr = ns.Folders(szDir)
Else
Set flr = flr.Folders(szDir)
End If
Wend
Set OpenMAPIFolder = flr
End Function
Function IsNothing(Obj)
If TypeName(Obj) = "Nothing" Then
IsNothing = True
Else
IsNothing = False
End If
End Function
From: https://superuser.com/questions/663992/how-can-i-set-outlook-2010-to-automatically-remove-cancelled-meeting
Sharing the code that works now.
Sub deleteFromInbox()
Dim oMeetingItem As Outlook.MeetingItem
Dim oAppointmentItem As AppointmentItem
Set oInbox = Application.Session.GetDefaultFolder(olFolderInbox)
Set oItems = oInbox.Items.Restrict("[MessageClass] = 'IPM.Schedule.Meeting.Canceled'")
For Each oAppt In oItems
If TypeOf oAppt Is MeetingItem Then
Set oMeetingItem = oAppt
If Len(oAppt.Subject) > 0 And InStr(1, oAppt.Subject, "Canceled:") <> 0 Then
Set oAppointmentItem = oMeetingItem.GetAssociatedAppointment(False)
Debug.Print oAppt.Subject
If Not oAppointmentItem Is Nothing Then
oAppointmentItem.Delete
End If
oAppt.Delete
End If
End If
Next
End Sub

Remove duplicates if team email address in the recipients

We have a team email address that we CC for most correspondence, and then we all get a copy of all emails.
The problem is when we then reply all, and a team member has already been in the email chain that person will get the email 2 times.
This is what I tried.
Private Sub RemoveRecipientsWhenItemSend(Item As Outlook.MailItem)
Dim RemoveAddrList As VBA.Collection
Dim InfoAddrList As VBA.Collection
Dim Recipients As Outlook.Recipients
Dim aRecipient As Outlook.Recipient
Dim bRecipient As Outlook.Recipient
Dim i
Dim j
Dim a
Dim b
Dim info As Boolean
info = False
Set RemoveAddrList = New VBA.Collection
Set InfoAddrList = New VBA.Collection
InfoAddrList.Add "team#company.com"
RemoveAddrList.Add "member1#company.com"
RemoveAddrList.Add "member2#company.com"
Set Recipients = Item.Recipients
For i = Recipients.Count To 1 Step -1
Set aRecipient = Recipients.Item(i)
For j = 1 To InfoAddrList.Count
If LCase$(aRecipient.Address) = LCase$(InfoAddrList(j)) Then
For a = Recipients.Count To 1 Step -1
Set bRecipient = Recipients.Item(a)
For b = 1 To RemoveAddrList.Count
If LCase$(aRecipient.Address) = LCase$(RemoveAddrList(b)) Then
Recipients.Remove i
Exit For
End If
Next
Next
Exit For
End If
Next
Next
End Sub
Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
On Error Resume Next
RemoveRecipientsWhenItemSend Item
End Sub
A few Debug.Print statements proved helpful.
Option Explicit
Private Sub RemoveRecipientsWhenItemSend(Item As Outlook.mailitem)
Dim RemoveAddrList As VBA.Collection
Dim InfoAddrList As VBA.Collection
Dim Recipients As Outlook.Recipients
Dim aRecipient As Outlook.Recipient
Dim bRecipient As Outlook.Recipient
Dim i
Dim j
Dim a
Dim b
Dim info As Boolean
info = False
Set RemoveAddrList = New VBA.Collection
Set InfoAddrList = New VBA.Collection
InfoAddrList.Add "team#company.com"
RemoveAddrList.Add "member1#company.com"
RemoveAddrList.Add "member2#company.com"
Set Recipients = Item.Recipients
For i = Recipients.count To 1 Step -1
Set aRecipient = Recipients.Item(i)
For j = 1 To InfoAddrList.count
Debug.Print LCase$(aRecipient.Address)
Debug.Print LCase$(InfoAddrList(j))
If LCase$(aRecipient.Address) = LCase$(InfoAddrList(j)) Then
For a = Recipients.count To 1 Step -1
'Set bRecipient = Recipients.Item(a)
Set aRecipient = Recipients.Item(a)
For b = 1 To RemoveAddrList.count
Debug.Print vbCr & " a: " & a
Debug.Print " LCase$(aRecipient.Address): " & LCase$(aRecipient.Address)
Debug.Print " LCase$(RemoveAddrList(b)): " & LCase$(RemoveAddrList(b))
If LCase$(aRecipient.Address) = LCase$(RemoveAddrList(b)) Then
'Recipients.Remove i
Recipients.Remove a
Exit For
End If
Next
Next
Exit For
End If
Next
Next
End Sub
Private Sub RemoveRecipientsWhenItemSend_test()
RemoveRecipientsWhenItemSend ActiveInspector.currentItem
End Sub
Here is something I use to remove the duplicate recipients.
Set olemail = olapp.CreateItemFromTemplate(OutlookTemplate)
With olemail
' other stuff
' check duplicate recipients
' first resolve email address per global address book
For Each Recipient In .Recipients
Recipient.Resolve
Next
' go through each recipients and check for dup
If .Recipients.count > 1 Then
For i = .Recipients.count To 2 Step -1
For j = i - 1 To 1 Step -1
If .Recipients(i) = .Recipients(j) Then
.Recipients.Remove (i)
i = i - 1
End If
Next j
Next i
End If
end with

How to pass items to a function to set categories?

I am building a function to sort a number of automated messages received daily in a shared email inbox. I use a loop to go through each mail message in the inbox and an IF statement to filter/sort messages and then run this function:
Function MoveSort(olDestination As Outlook.Folder)
Dim StCategory
If oItems.Item(i).Categories = "" Then
oItems.Item(i).Categories = "Category"
End If
oItems.Item(i).UnRead = False
oItems.Item(i).Save
oItems.Item(i).Move olDestination
End Function
The Category is usually not getting assigned. (Sometimes it will seemingly randomly assign it to the first or last message.)
This is the main procedure:
Private i As Integer
Private oItems As Outlook.Items
Sub OrganizeIt()
Dim oNS As Outlook.NameSpace
Dim oInbox As Outlook.Folder
Dim oBStock As Outlook.Folder
Dim oCStock As Outlook.Folder
Dim oStock As Outlook.Folder
Dim SEmail As String
Dim SSubject As String
Set oNS = Application.GetNamespace("MAPI")
Set oInbox = oNS.folders("HelpDeskEmail").folders("Inbox")
Set oItems = oInbox.Items
Set oCStock = oInbox.folders("Folder1")
Set oBStock = oInbox.folders("Folder2")
For i = oItems.Count To 1 Step -1
SEmail = oItems.Item(i).SenderEmailAddress
SSubject = oItems.Item(i).Subject
If SEmail = "Email1#email.com" Or SSubject = "Sample Subject 1" Or _
Left(SSubject, 16) = "Sample Subject 2" Then
MoveSort oStock
ElseIf SEmail = "Email2#email.com" Then
MoveSort oBStock
ElseIf SEmail = "Email3#email.com" Then
MoveSort oCStock
End If
Next i
End Sub
This is multiple dot notation taken to its extreme - the following code sets Unread property on one object and calls Save on a completely different object that has no idea about anything else your code has previously done.
oItems.Item(i).UnRead = False
oItems.Item(i).Save
Do not use multiple dot notation and do not make i a global variable - pass the object as a parameter
Function MoveSort(olDestination As Outlook.Folder, Item as Object)
Dim StCategory
If Item.Categories = "" Then
Item.Categories = "Category"
End If
Item.UnRead = False
Item.Save
Item.Move olDestination
End Function
...
Dim Item as Object
For i = oItems.Count To 1 Step -1
set Item = oItems.Item(i)
SEmail = Item.SenderEmailAddress
SSubject = Item.Subject
If SEmail = "Email1#email..com" Or SSubject = "Sample Subject 1" Or _
Left(SSubject, 16) = "Sample Subject 2" Then
MoveSort oStock, Item
ElseIf SEmail = "Email2#email.com" Then
MoveSort oBStock, Item
ElseIf SEmail = "Email3#email.com" Then
MoveSort oCStock, Item
End If
Next i