How to delete all appointments? - vba

I am trying to delete all appointments from an Excel VBA (Excel 2010) macro.
I get an Error 13 (Type Mismatch) on olFolder.Items.GetFirst.
It ran a few weeks ago.
Sub DeleteAllAppointments()
Dim olApp As Object
Application.ScreenUpdating = False
Set olApp = CreateObject("Outlook.Application")
Dim olApptItem As Outlook.AppointmentItem
Dim olMeetingItem As Outlook.MeetingItem
Dim olNameSpace As Outlook.Namespace
Dim olFolder As Outlook.MAPIFolder
Dim olObject As Object
Dim olItems As Items
Dim i As Double
Set olNameSpace = olApp.GetNamespace("MAPI")
Set olFolder = olNameSpace.GetDefaultFolder(olFolderCalendar)
Set olItems = olFolder.Items
Set olApptItem = olFolder.Items.GetFirst
For i = 1 To olItems.Count
If olItems.Count > 1 Then
olApptItem.Delete
Set olApptItem = olFolder.Items.GetNext
Else
Set olApptItem = olFolder.Items.GetLast
olApptItem.Delete
End If
Next
End Sub

As already mentioned you should delete them in reverse order - as they are re-indexed each time and you eventually try to refer to an item that doesn't exist.
You don't need to Set the next item in the loop as you can use Remove(i) to delete a particular item:
For i = olItems.Count To 1 Step -1
If TypeOf olItems(i) Is olApp.AppointmentItem Then
olItems.Remove (i)
End If
Next i
However, this code will delete EVERY appointment, because practically everything within the calendar is an AppointmentItem. If you don't want to delete, for example, a Meeting then you need to read some property such as MeetingStatus, which is 1 for a Meeting and 0 for a Non-Meeting:
For i = olItems.Count To 1 Step -1
If TypeOf olItems(i) Is olApp.AppointmentItem Then
If olItems(i).MeetingStatus = 0 Then
olItems.Remove (i)
End If
End If
Next i
From Excel though, using olAppointment may be preferable to AppointmentItem because you can substitute the numeric value of 26 if necessary: If olItems(i).Class = 26.

Usually that means that you actually have some items in your folder that are not an Appointment item. You need to test what the item is before assuming that it is an appointment. This is true even when the folder is set to only contain appointment items.
Dim myItem As Object
Dim olfolder As Outlook.folder
Dim apptItem As AppointmentItem
Set olfolder = Application.Session.GetDefaultFolder(olFolderCalendar)
For i = olfolder.Items.Count To 1 Step -1
Set myItem = olfolder.Items(i)
If myItem.Class = olAppointment Then
Set apptItem = myItem
'code here
End If
Next
When deleting items it's usually best to start high and iterate backwards. Delete as you go.

I know the request is a bit old, but I wanted to contribute with a code I have written which may help.
Sub CalendarCleanup()
Dim tmpCalendarFolder As Outlook.MAPIFolder
Dim i As Long
Set tmpCalendarFolder = Application.GetNamespace("MAPI").GetDefaultFolder(olFolderCalendar)
' If you want to target a specific folder, you can use this code
'Set tmpCalendarFolder = Application.GetNamespace("MAPI").Folders("YOUR INBOX NAME").Folders("YOUR CALENDAR FOLDER")
'For i = 1 to tmpCalendarFolder.Items.Count Step -1
For i = tmpCalendarFolder.Items.Count to 1 Step -1
tmpCalendarFolder.Items(i).Delete
Next i
End Sub
Please make sure the correct folder is selected (tmpCalendarFolder) before running the code... or at least make some tests before running on a "production" environment, as you are deleting items.
EDIT: code adjusted as per comments below

Related

Loop through Outbox with Inbox, Delete message with same subject line from outbox

Im trying to look through 2 different boxes(inbox & Outbox), compare the subject and delete the message in the outbox when a match is found. What am I doing incorrectly? Do I need to create another Folder object for each box? EDIT Im getting a "runtime error 13; type mismatch"
Sub DEID()
Dim objNS As Outlook.NameSpace
Dim objFolder As Outlook.MAPIFolder
Set objNS = GetNamespace("MAPI")
Set objFolder = objNS.Folders.GetFirst
Set objIFolder = objFolder.Folders("Inbox")
Set objOFolder = objFolder.Folders("Outbox")
Dim Item, OItem As Outlook.MailItem
For Each Item In objIFolder.Items
Set ISub = Right(CStr(Item.Subject), Len(Item.Subject) - 6)
Set ISub = CStr(ISub)
For Each OItem In objOFolder.Items
Set OSub = Right(CStr(OItem.Subject), Len(OItem.Subject) - 6)
Set ISub = CStr(OSub)
If StrComp(ISub = OSub, 1) = 0 Then
OItem.Delete
End If
Next OItem
Next Item
End Sub
One thing that jumps out at me is you are using a set command on a value type (subject, which is a string), which you don't need and should cause an error.
Dim Item, OItem As Outlook.MailItem
Dim ISub, OSub As String
For Each Item In objIFolder.Items
ISub = Right(CStr(Item.Subject), Len(Item.Subject) - 6)
ISub = CStr(ISub)
For Each OItem In objOFolder.Items
OSub = Right(CStr(OItem.Subject), Len(OItem.Subject) - 6)
ISub = CStr(OSub)
If StrComp(ISub = OSub, 1) = 0 Then
OItem.Delete
End If
Next OItem
Next Item
One other observation... This line:
ISub = CStr(OSub)
Seems to me like it will force the next condition to always be true. Unless I misunderstand, that seems like a mistake.
I also think the String conversion are unnecessary since subject is already a string.
This would be my final version:
Dim objNS As Outlook.NameSpace
Dim objFolder As Outlook.MAPIFolder
Set objNS = GetNamespace("MAPI")
Set objFolder = objNS.Folders.GetFirst
Set objIFolder = objFolder.Folders("Inbox")
Set objOFolder = objFolder.Folders("Outbox")
Dim Item, OItem As Outlook.MailItem
Dim ISub, OSub As String
For Each Item In objIFolder.Items
ISub = Right(Item.Subject, Len(Item.Subject) - 6)
For Each OItem In objOFolder.Items
OSub = Right(OItem.Subject, Len(OItem.Subject) - 6)
If ISub = OSub Then
OItem.Delete
End If
Next OItem
Next Item
Firstly, you are dimming Item and OItem as Outlook.MailItem - you can have other items in the Inbox folder (hence the Type Mismatch error), such as ReportItem or MeetingItem. Dim these variables as a generic Object.
Secondly, you are deleting items in a collection while you are looping through it. Do not do that - use a down loop (for i = Items.Count to 1 step -1).
Thirdly, do not loop through all items in a folder - this is hugely inefficient, let Outlook do the job - for the inner use Items.Find / FindNext or Items.Restrict with a query like #SQL="http://schemas.microsoft.com/mapi/proptag/0x0E1D001F" like '%some value%'.
For the outer loop, again, dd not loop, retrieve all subjects in a single call using MAPIFolder.GetTable() / Table.Columns.Add / Table.GetArray / etc. - see https://learn.microsoft.com/en-us/dotnet/api/microsoft.office.interop.outlook.table?view=outlook-pia

Delete email from inbox and also delete it from deleted-items folder via rule->script

I created a rule, that starts a VBA-script depending on the subject of a received email (Rule: Subject "MY_SUBJECT" -> start script).
The VBA script is then doing some stuff and then it should finally delete the original email.
This part is easy:
Sub doWorkAndDeleteMail(Item As Outlook.MailItem)
' doSomething:
' delete email from inbox
Item.Delete
End Sub
Now the email will sit in the deleted-items-folder. But what I need to achieve is, to also delete this mail from the deleted-items folder. Since I know the subject of this mail (because this triggered my rule in the first place), I tried the following approach:
Sub doWorkAndDeleteMail(Item As Outlook.MailItem)
' doSomething:
' delete email from inbox
Item.Delete
End Sub
' delete email from deleted items-folder
Dim deletedFolder As Outlook.Folder
Set deletedFolder = Application.GetNamespace("MAPI"). _
GetDefaultFolder(olFolderDeletedItems)
Dim i As Long
For i = myFolder.Items.Count To 1 Step -1
If (deletedFolder.Items(i).Subject) = "MY_SUBJECT" Then
deletedFolder.Items(i).Delete
Exit For
End If
Next if
End Sub
Well, this basically works: The mail with this subject will be found in the deleted-items-folder and it will be deleted, yes.
But sadly it does not work as expected:
This permanent deletion only works once I start the script a second time.
So the email which is triggering my script will never be deleted permanently in this script's actual run, but only in the next run (once the next email with the trigger-subject for my rule is received - but then this very next email won't be deleted, again).
Do you have any idea what I am doing wrong here? It somehow looks like I need to refresh my deleted-items folder somehow. Or do I have to comit my first Item.Delete somehow explicitly?
The problem was not recreated, but try stepping through this then run normally if it appears to do what you want.
Sub doWorkAndDeleteMail(Item As mailitem)
Dim currFolder As Folder
Dim DeletedFolder As Folder
Dim i As Long
Dim mySubject As String
Set currFolder = ActiveExplorer.CurrentFolder
mySubject = Item.Subject
Debug.Print mySubject
Set DeletedFolder = GetNamespace("MAPI").GetDefaultFolder(olFolderDeletedItems)
Set ActiveExplorer.CurrentFolder = DeletedFolder
Debug.Print "DeletedFolder.count before delete: " & DeletedFolder.Items.count
' delete email from deleted items-folder
Item.Delete
Debug.Print "DeletedFolder.count after delete: " & DeletedFolder.Items.count
' If necessary
'DoEvents
For i = DeletedFolder.Items.count To 1 Step -1
Debug.Print DeletedFolder.Items(i).Subject
If (DeletedFolder.Items(i).Subject) = mySubject Then
Debug.Print DeletedFolder.Items(i).Subject & " *** found ***"
DeletedFolder.Items(i).Delete
Exit For
End If
Next
Set ActiveExplorer.CurrentFolder = currFolder
End Sub
Tim Williams suggested another existing thread. I had a look at that already before and decided that appoach would be exactly the same representation of my bug. I did try it out, though (to show my motiviation :) ), but the behaviour is - as expected - exactly the same: Again the final deletion only works once the next time the script is triggered via rule:
Sub doWorkAndDeleteMail(Item As Outlook.MailItem)
' First set a property to find it again later
Item.UserProperties.Add "Deleted", olText
Item.Save
Item.Delete
'Now go through the deleted folder, search for the property and delete item
Dim objDeletedFolder As Outlook.Folder
Dim objItem As Object
Dim objProperty As Variant
Set objDeletedFolder = Application.GetNamespace("MAPI"). _
GetDefaultFolder(olFolderDeletedItems)
For Each objItem In objDeletedFolder.Items
Set objProperty = objItem.UserProperties.Find("Deleted")
If TypeName(objProperty) <> "Nothing" Then
objItem.Delete
End If
Next
End Sub
I would be really glad to get some help here. I also wanted to comment on that other thread, but my reputation is not enough, yet.
Try something like this, code goes under ThisOutlookSession
Private WithEvents Items As Outlook.Items
Private Sub Application_Startup()
Dim olNs As Outlook.NameSpace
Dim DeletedFolder As Outlook.MAPIFolder
Set olNs = Application.GetNamespace("MAPI")
Set DeletedFolder = olNs.GetDefaultFolder(olFolderDeletedItems)
Set Items = DeletedFolder.Items
End Sub
Private Sub Items_ItemAdd(ByVal Item As Object)
Dim olNs As Outlook.NameSpace
Dim DeletedFolder As Outlook.MAPIFolder
Dim Items As Outlook.Items
Dim Filter As String
Dim i As Long
Set olNs = Application.GetNamespace("MAPI")
Set DeletedFolder = olNs.GetDefaultFolder(olFolderDeletedItems)
Filter = "[Subject] = 'MY_SUBJECT'"
Set Items = DeletedFolder.Items.Restrict(Filter)
If TypeOf Item Is Outlook.MailItem Then
For i = Items.Count To 1 Step -1
DoEvents
Items.Remove i
Next
End If
End Sub
Edit
Sub doWorkAndDeleteMail(Item As Outlook.MailItem)
' First set a property to find it again later
Item.UserProperties.Add "Deleted", olText
Item.Save
Item.Delete
'Now go through the deleted folder, search for the property and delete item
Dim olNs As Outlook.NameSpace
Dim DeletedFolder As Outlook.MAPIFolder
Dim Items As Outlook.Items
Dim Filter As String
Dim i As Long
Set olNs = Application.GetNamespace("MAPI")
Set DeletedFolder = olNs.GetDefaultFolder(olFolderDeletedItems)
Filter = "[Subject] = 'MY_SUBJECT'"
Set Items = DeletedFolder.Items.Restrict(Filter)
If TypeOf Item Is Outlook.MailItem Then
For i = Items.Count To 1 Step -1
DoEvents
Items.Remove i
Next
End If
End Sub
the Mailbox folder that you get can be used as a collection, meaning that you can remove the item directly, you will need the collection to be sent to the function but that should be managable :)
Sub doWorkAndDeleteMail(Mailbox As Outlook.Folder, Item As Outlook.MailItem)
' doSomething:
' delete email from inbox
For Ite = 1 To Mailbox.Items.Count
If Mailbox.Items(Ite).EntryID = Item.EntryID Then
Mailbox.Items.Remove Ite
Exit For
End If
Next
End Sub
Remember that IF you want to Delete more than 1 Item per call of "For Ite = 1 To Mailbox.Items.Count", you will need to subtract 1 from the check of the item within the For segment since when you remove a mail from it, it will reduce the rest of the mails index number by 1.
Hope you can still use this :)
Regards Sir Rolin

How do I create a macro to move the oldest 20 emails from the bottom of my inbox to another folder in outlook?

I'm trying to move the bottom 20 emails to another folder in Outlook to another folder where the macro runs. I'm able to move then when selected but I don't want to have to select 20 from the bottom (oldest) first. I'd like to automate this bit too.
Any help would be appreciated.
Here's what I have so far but it moves the most recent mail only, regardless of how the inbox is sorted:
Public Sub Move_Inbox_Emails()
Dim outApp As Object
Dim outNS As Object
Dim inboxFolder As Object
Dim destFolder As Object
Dim outEmail As Object
Dim inboxItems As Object
Dim i As Integer
Dim inputNumber As String
Dim numberToMove As Integer
inputNumber = InputBox("Enter number of emails to move")
On Error Resume Next
numberToMove = CInt(inputNumber)
On Error GoTo 0
If numberToMove < 1 Then Exit Sub
Set outApp = CreateObject("Outlook.Application")
Set outNS = outApp.GetNamespace("MAPI")
Set inboxFolder = outNS.GetDefaultFolder(olFolderInbox)
Set destFolder = inboxFolder.Parent.Folders("Mobus") 'Test folder at same level as Inbox
'Sort Inbox items by Received Time
Set itemsCol = inboxFolder.Items
itemsCol.Sort "[ReceivedTime]", False
'Loop through sorted items for the number entered by the user, up to the number of items in the Inbox
For i = inboxFolder.Items.Count To inboxFolder.Items.Count - numberToMove + 1 Step -1
If inboxFolder.Items(i).Class = OlObjectClass.olMail Then
Set outEmail = inboxFolder.Items(i)
'Debug.Print outEmail.ReceivedTime, outEmail.subject
outEmail.Move destFolder
End If
Next
End Sub
I've solved this now with some ideas from the commentors, thanks very much. This code now prompts for how many to move and takes them from the oldest first:
Public Sub Move_Inbox_Emails_From_Excel()
Dim outApp As Object
Dim outNS As Object
Dim inboxFolder As Object
Dim destFolder As Object
Dim outEmail As Object
Dim inboxItems As Object
Dim i As Integer
Dim inputNumber As String
Dim numberToMove As Integer
inputNumber = InputBox("Enter number of emails to move")
On Error Resume Next
numberToMove = CInt(inputNumber)
On Error GoTo 0
If numberToMove < 1 Then Exit Sub
Set outApp = CreateObject("Outlook.Application")
Set outNS = outApp.GetNamespace("MAPI")
Set inboxFolder = outNS.GetDefaultFolder(olFolderInbox)
Set destFolder = inboxFolder.Parent.Folders("Mobus") 'Test folder at same level as Inbox
'Sort Inbox items by Received Time
Set inboxItems = inboxFolder.Items
'inboxItems.Sort "[ReceivedTime]", False 'ascending order (oldest first)
inboxItems.Sort "[ReceivedTime]", True 'descending order (newest first)
'Loop through sorted items for the number entered by the user, up to the number of items in the Inbox
For i = inboxFolder.Items.Count To inboxFolder.Items.Count - numberToMove + 1 Step -1
Set outEmail = inboxItems(i)
'Debug.Print i, outEmail.Subject
outEmail.Move destFolder
Next
End Sub
Sort the Items collection by ReceivedTime property, loop though the last 20 items (use a down loop - step -1) and move the items.

Using ReceivedTime in Outlook VBA to count yesterday's mail

I want to flash up a message box with the amount of mail received yesterday.
The code I have at the moment is:
Public Sub YesterdayCount()
Set ns = Application.GetNamespace("MAPI")
Set outApp = CreateObject("Outlook.Application")
Set outNS = outApp.GetNamespace("MAPI")
Dim Items As Outlook.Items
Dim MailItem As Object
Dim yestcount As Integer
yestcount = 0
Set Folder = outNS.Folders("Correspondence Debt Advisor Queries").Folders("Inbox")
Set Items = Folder.Items
For Each Item In Items
If MailItem.ReceivedTime = (Date - 1) Then
yestcount = yestcount + 1
End If
Next
MsgBox yestcount
End Sub
The problem is with the line:
If MailItem.ReceivedTime = (Date - 1) Then
The error says that an object variable is not set, but I can't fathom this after researching.
You almost got it. You basically never set the MailItem nor qualified it to the Item, and since ReceivedTime is Date / Time format, it will never equal a straight Date.
See the code below. I added some features to sort by ReceivedTime, then Exit the loop once it passes yesterday's date. I also cleaned up some of the variable naming so it will not be confused with inherent Outlook Object naming conventions.
Public Sub YesterdayCount()
Dim outNS As Outlook.NameSpace
Set outNS = Application.GetNamespace("MAPI")
Dim olFolder As Outlook.Folder
Set olFolder = outNS.Folders("Correspondence Debt Advisor Queries").Folders("Inbox")
Dim olItems As Outlook.Items
Set olItems = olFolder.Items
olItems.Sort "[ReceivedTime]", True
Dim yestcount As Integer
yestcount = 0
Dim item As Object
For Each item In olItems
'commented code works for MailItems
'Dim olMail As Outlook.MailItem
'Set olMail = item
Dim dRT As Date
'dRT = olMail.ReceivedTime
dRT = item.ReceivedTime
If dRT < Date And dRT > Date - 2 Then
If dRT < Date - 1 Then Exit For
yestcount = yestcount + 1
End If
Next
MsgBox yestcount
End Sub

Set custom value when item moved to folder in outlook

I'm looking to set a Date on a field anytime an email is moved into a specific folder.
the field is custom called "Completed Date".
Could I get a little help on VBA code to set a custom field (date) when an item is moved into a folder (folder name is "Completed").
I'm ultimately looking to report on the time an item (custom form email) was received to the time it was completed (as per the action of moving the email to a completed folder.
Very rudimentary ticketing system, I'm very aware :) .
thanks,
A
Use ItemAdd http://www.outlookcode.com/article.aspx?id=62 where you reference the "Completed" folder.
Combine it with code like this http://www.vbaexpress.com/forum/showthread.php?5738-Need-to-Add-a-Userdefined-Property-to-Mail-Items
SAMPLE CODE
Change it so you do not update all items in the folder just the one item that triggered ItemAdd.
Option Explicit
Sub AddAUserDefinedProperty()
Dim olApplication As Outlook.Application
Dim olNameSpace As Outlook.NameSpace
Dim olFolder As Outlook.MAPIFolder
Dim olItem As Object
Dim strDomain As String
Dim olProperty As Outlook.UserProperty
Set olApplication = New Outlook.Application
Set olNameSpace = olApplication.GetNamespace("Mapi")
Set olFolder = olNameSpace.GetDefaultFolder(olFolderJunk)
For Each olItem In olFolder.Items
strDomain = Mid(olItem.SenderEmailAddress, _
InStr(1, olItem.SenderEmailAddress, "#") + 1)
Set olProperty = olItem.UserProperties.Add("Domain", olText)
olProperty.Value = strDomain
Debug.Print olItem.SenderEmailAddress, olProperty.Value
olItem.Save
Next olItem
Set olApplication = Nothing
Set olNameSpace = Nothing
Set olFolder = Nothing
Set olProperty = Nothing
End Sub
Even more reference material here http://www.codeproject.com/Articles/427913/Using-User-Defined-Fields-in-Outlook