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
Related
I am trying to download the email attachments in Outlook inbox based on received date. My code downloads attachments, however it skips files.
For example: I was trying to loop the email from the latest email (Received date:01/14/2019). After looping around 10-15 emails, it suddenly jumps to read the email received on 12/07/2018.
Sub saveemailattachment()
'Application setup
Dim objOL As Outlook.Application
Set objOL = New Outlook.Application
Dim ONS As Outlook.Namespace
Set ONS = objOL.GetNamespace("MAPI")
Dim olfolder As Outlook.Folder
Set olfolder = ONS.GetDefaultFolder(olFolderInbox)
Dim olmail As Outlook.MailItem
Set olmail = objOL.CreateItem(olMailItem)
Dim olattachment As Outlook.Attachment
Dim i As Long
Dim filename As String
Dim VAR As Date
'Loop through all item in Inbox
For i = olfolder.Items.Count To 1 Step -1 'Iterates from the end backwards
Set olmail = olfolder.Items(i)
For Each olmail In olfolder
VAR = Format(olmail.ReceivedTime, "MM/DD/YYYY")
filename = olmail.Subject
If VAR = "1/14/2019" Then
For Each olattachment In olmail.Attachments
olattachment.SaveAsFile "C:\Users\Rui_Gaalh\Desktop\Email attachment\" & olattachment.filename
Next
Else
End If
'Mark email as read
olmail.UnRead = False
DoEvents
olmail.Save
Next
Next
MsgBox "DONE"
End Sub
Do not loop through all items in a folder - some folders can have ten of thousands of messages. Use Items.Find/FindNext or Items.Restrict with a query like "[ReceivedTime] >= '2019-01-14' AND [ReceivedTime] < '2019-01-15'".
In case of Items.Find/FindNext, you won't have a problem with skipped emails. In case of Items.Restrict, use a down loop from count down to 1 step -1.
If you are just trying to save Email Attachments that was received on "1/14/2019" then No need for
For Each olmail In olfolder
Next
When you are already using
For i = olfolder.Items.Count To 1 Step -1
next
Here is another one objOL.CreateItem(olMailItem)?? remove it, also Dim olmail as a generic Object - there are objects other than MailItem in your Inbox.
Dim olmail As Outlook.MailItem
Set olmail = objOL.CreateItem(olMailItem)
Set olMail with in the loop then check if the olMail is MailItem
Example
Option Explicit
Sub saveemailattachment()
'Application setup
Dim objOL As Outlook.Application
Set objOL = New Outlook.Application
Dim ONS As Outlook.NameSpace
Set ONS = objOL.GetNamespace("MAPI")
Dim olfolder As Outlook.Folder
Set olfolder = ONS.GetDefaultFolder(olFolderInbox)
Dim olmail As Object
Dim olattachment As Outlook.attachment
Dim i As Long
Dim filename As String
Dim VAR As Date
'Loop through all item in Inbox
For i = olfolder.items.Count To 1 Step -1 'Iterates from the end backwards
DoEvents
Set olmail = olfolder.items(i)
If TypeOf olmail Is Outlook.MailItem Then
VAR = Format(olmail.ReceivedTime, "MM/DD/YYYY")
filename = olmail.Subject
If VAR = "1/14/2019" Then
For Each olattachment In olmail.Attachments
olattachment.SaveAsFile _
"C:\Users\Rui_Gaalh\Desktop\Email attachment\" _
& olattachment.filename
Next
'Mark email as read
olmail.UnRead = False
End If
End If
Next
MsgBox "DONE"
End Sub
You should also look into Items.Restrict method
https://stackoverflow.com/a/48311864/4539709
Items.Restrict method is an alternative to using the Find method or FindNext method to iterate over specific items within a collection. The Find or FindNext methods are faster than filtering if there are a small number of items. The Restrict method is significantly faster if there is a large number of items in the collection, especially if only a few items in a large collection are expected to be found.
Filtering Items Using a String Comparison that DASL filters support includes equivalence, prefix, phrase, and substring matching. Note that when you filter on the Subject property, prefixes such as "RE: " and "FW: " are ignored.
Thanks for all your suggestions. The code works perfectly. Please find the final code below:
Option Explicit
Sub saveemailattachment()
'Application setup
Dim objOL As Outlook.Application
Set objOL = New Outlook.Application
Dim ONS As Outlook.Namespace
Set ONS = objOL.GetNamespace("MAPI")
Dim olfolder As Outlook.Folder
Set olfolder = ONS.GetDefaultFolder(olFolderInbox)
Dim olmail As Object
Dim olattachment As Outlook.Attachment
Dim i As Long
Dim InboxMsg As Object
Dim filename As String
'Set variables
Dim Sunday As Date
Dim Monday As Date
Dim Savefolder As String
Dim VAR As Date
Dim Timestamp As String
Monday = ThisWorkbook.Worksheets(1).Range("B2")
Sunday = ThisWorkbook.Worksheets(1).Range("B3")
Savefolder = ThisWorkbook.Worksheets(1).Range("B4")
'Loop through all item in Inbox
For i = olfolder.Items.Count To 1 Step -1 'Iterates from the end backwards
DoEvents
Set olmail = olfolder.Items(i)
Application.Wait (Now + TimeValue("0:00:01"))
'Check if olmail is emailitem
If TypeOf olmail Is Outlook.MailItem Then
'Set time fram
VAR = olmail.ReceivedTime 'Set Received time
Timestamp = Format(olmail.ReceivedTime, "YYYY-MM-DD-hhmmss") 'Set timestamp format
If VAR <= Sunday And VAR >= Monday Then
For Each olattachment In olmail.Attachments
Application.Wait (Now + TimeValue("0:00:01"))
'Download excel file and non-L10 file only
If (Right(olattachment.filename, 4) = "xlsx" Or Right(olattachment.filename, 3) = "xls")Then
'Set file name
filename = Timestamp & "_" & olattachment.filename
'Download email
olattachment.SaveAsFile Savefolder & "\" & filename
Application.Wait (Now + TimeValue("0:00:02"))
End If
Next
Else
End If
'Mark email as read
olmail.UnRead = False
DoEvents
olmail.Save
Else
End If
Next
MsgBox "DONE"
End Sub
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
I am trying to look for an email that is sent from a specific email address, and then, everyday between 09:00 and 11:00:00, forward all the emails from this specific email address to a second email address.
I'm getting the following error.
Sub Search_Inbox()
Dim myOlApp As New Outlook.Application
Dim myNameSpace As Outlook.NameSpace
Dim myInbox As Outlook.MAPIFolder
Dim myitems As Outlook.Items
Dim myitem As Object
Dim Found As Boolean 'this is a boolean to check if the code found the emails or not
Dim Str_Address As String 'this is a String for an Email Address
Dim Mail_Value As MailItem 'this is where the email adresses will be stored
Dim Bool_Time As Boolean 'used to hold the time values
Dim Count As Integer 'used as the count for the array
Dim emails_forward(Count) As Integer 'used to hold all the emails to be forwarded when it is 11:00
Set myNameSpace = myOlApp.GetNamespace("MAPI")
Set myInbox = myNameSpace.GetDefaultFolder(olFolderInbox)
Set myitems = myInbox.Items
Found = False
For Each myitem In myitems
'below is the selected time period
If Bool_Time = (Time >= #9:00:00 AM#) And (Time <= #10:59:59 AM#) Then
If myitem.Class = olMail Then
If InStr(1, myitem.Mail_Value, "email address to search for") > 0 Then
Forward_Emails (Mail_Value)
Debug.Print "Found"
Found = True
End If
End If
End If
Next myitem
End Sub
Function Forward_Emails(Email_to_Forward As Outlook.MailItem)
Set Email_to_Forward = Item.Forward
Email_to_Forward.Recipients.Add "email address to forward to after"
Email_to_Forward.Save
Email_to_Forward.Send
Set Email_to_Forward = Nothing
End Function
Declare the array with ReDim, example: ReDim emails_forward(Count) As Integer
MSDN Constant expression required
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.
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