I want to mark all unanswered emails, older than three days, with a flag and move them into a folder named "mini". The source is "Posteingang" (German for inbox).
Sub Mails_verschieben()
Set myaccount = Application.GetNamespace("MAPI").DefaultStore
Set mynamespace = Application.GetNamespace("MAPI")
Dim ursprung As MAPIFolder
Dim ziel As MAPIFolder
Set ursprung = Session.Folders(myaccount.DisplayName).Folders("Posteingang")
Set ziel = Session.Folders(myaccount.DisplayName).Folders("mini")
For i = ursprung.Items.Count To 1 Step -1 'alle emails im Postfach durchgehen
With ursprung.Items(i)
If .ReceivedTime < Date - 3 And ursprung.Items(i) = .LastModificationTime Then
.FlagIcon = 5
.FlagStatus = olFlagMarked
.Save
ursprung.Items(i).Move ziel 'in Ordner verschieben
End If
End With
Next i
End Sub
I get
Object Doesn't Support this Property or Method
at
If .ReceivedTime < Date - 3 And ursprung.Items(i) = .LastModificationTime Then
I want also to run this script automatically but found nothing.
I modified my code:
Sub Mails_verschieben()
Set myaccount = Application.GetNamespace("MAPI").DefaultStore
Set mynamespace = Application.GetNamespace("MAPI")
Dim ursprung As MAPIFolder
Dim ziel As MAPIFolder
Dim MailX As MailItem
Set ursprung = mynamespace.GetDefaultFolder(olFolderInbox)
Set ziel = Session.Folders(myaccount.DisplayName).Folders("mini")
For i = ursprung.Items.Count To 1 Step -1 'alle emails im Postfach durchgehen
For Each MailX In ursprung.Items(i)
If MailX.ReceivedTime < Date - 3 And ursprung.Items(i) = MailX.LastModificationTime Then
MailX.FlagIcon = 5
MailX.FlagStatus = olFlagMarked
MailX.Save
ursprung.Items(i).Move ziel 'in Ordner verschieben
End If
Next
Next i
End Sub
Also getting error.
First, please remember that an Outlook folder may contain different item types - mails, appointments, documents and etc. Check the item type at runtime to make sure you deal with mail item before accessing their properties. For example:
For x = 1 To Items.Count
If Items.Item(x).Class = OlObjectClass.olMail Then
' For mail item, use the SenderName property.
End If
Next
Second, to get the standard/default Inbox folder you don't need to use the following code:
Set ursprung = Session.Folders(myaccount.DisplayName).Folders("Posteingang")
Instead, use the NameSpace.GetDefaultFolder method which returns a Folder object that represents the default folder of the requested type for the current profile.
Set ursprung = mynamespace.GetDefaultFolder(olFolderInbox)
Third, instead of iterating over all items in a folder:
For i = ursprung.Items.Count To 1 Step -1 'alle emails im Postfach durchgehen
With ursprung.Items(i)
You need to use the Find/FindNext or Restrict methods of the Items class. 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
There appears to be an unneeded condition in
If MailX.ReceivedTime < Date - 3 And ursprung.Items(i) = MailX.LastModificationTime Then
Option Explicit ' Consider this mandatory
' Tools | Options | Editor tab
' Require Variable Declaration
' If desperate declare as Variant
Sub Mails_verschieben2()
Dim ursprung As Folder
Dim ziel As Folder
Dim ursprungItems As Items
Dim i As Long
' Not usual
Dim myDefaultStore As Store
Set myDefaultStore = Session.defaultStore
Set ursprung = Session.Folders(myDefaultStore.DisplayName).Folders("Posteingang")
'Set ursprung = Session.Folders(myDefaultStore.DisplayName).Folders("Inbox")
Debug.Print ursprung.name
' Standard
Set ursprung = Session.GetDefaultFolder(olFolderInbox)
Debug.Print ursprung.name
'Folder at same level as Inbox
Set ziel = ursprung.Parent.Folders("mini")
Debug.Print ziel.name
Set ursprungItems = ursprung.Items
ursprungItems.Sort "[ReceivedTime]", True ' newest first
' You could use .Restrict but in normal sized inboxes
' the time saved may not be noticeable.
For i = ursprungItems.count To 1 Step -1 'alle emails im Postfach durchgehen
' Verify that the item is a mailitem
' before attempting to return mailitem properties
If TypeOf ursprungItems(i) Is mailItem Then
With ursprungItems(i)
If .ReceivedTime < Date - 3 Then
'.FlagIcon = 5
'.FlagStatus = olFlagMarked
'.Save
'.Move ziel 'in Ordner verschieben
Debug.Print "Older mail."
Debug.Print " Subject: " & .Subject
Debug.Print " ReceivedTime: " & .ReceivedTime
Else
Debug.Print "Newer mail."
Debug.Print " Subject: " & .Subject
Debug.Print " ReceivedTime: " & .ReceivedTime
Exit For ' Stop when newer mail encountered.
End If
End With
Else
Debug.Print "Non-mailitem ignored."
End If
Next i
Debug.Print "Done."
End Sub
Related
I get a 430 error running code on a subfolder of a shared inbox.
Sub GetEmails()
'Add Tools->References->"Microsoft Outlook nn.n Object Library"
'nn.n varies as per our Outlook Installation
Const NUM_DAYS As Long = 34
Dim OutlookApp As Outlook.Application
Dim i As Long
Dim Folder As Outlook.MAPIFolder
Dim itm As Object
Dim iRow As Long, oRow As Long, ws As Worksheet, sBody As String
Dim mailboxName As String, inboxName As String, subfolderName As String
mailboxName = "mailboxname"
inboxName = "Inbox"
subfolderName = "subfoldername"
Set OutlookApp = New Outlook.Application
On Error Resume Next
Set Folder = OutlookApp.Session.Folders(mailboxName) _
.Folders(inboxName).Folders(subfolderName)
On Error GoTo 0
If Folder Is Nothing Then
MsgBox "Source folder not found!", vbExclamation, _
"Problem with export"
Exit Sub
End If
Set ws = ThisWorkbook.Worksheets(1)
'add headers
ws.Range("A1").Resize(1, 4).Value = Array("Sender", "Subject", "Date", "Body")
iRow = 2
Folder.Items.Sort "Received"
For Each itm In Folder.Items
If TypeOf itm Is Outlook.MailItem Then 'check it's a mail item (not appointment, etc)
If Date - itm.ReceivedTime <= NUM_DAYS Then
sBody = Left(Trim(itm.Body), 150) 'first 150 chars of Body
sBody = Replace(sBody, vbCrLf, "; ") 'remove newlines
sBody = Replace(sBody, vbLf, "; ")
ws.Cells(iRow, 1).Resize(1, 4).Value = _
Array(itm.SenderName, itm.Subject, itm.ReceivedTime, sBody)
iRow = iRow + 1
End If
End If
Next itm
MsgBox "Outlook Mails Extracted to Excel"
End Sub
I tried changing "itm" to "item". It works on the regular inbox. The issue happens when I try to pull from a subfolder.
I tried Debug Print. I don't know if I'm putting it in the right place.
The 430 error happens on the line:
If Date - itm.ReceivedTime <= NUM_DAYS Then
If I try to pull 30 days worth of data, it will only pull like the last seven days. So it works but it is limited.
First of all, the Sort method deals with non-existsing property:
Folder.Items.Sort "Received"
You need to use the ReceivedTime property instead.
Second, the sorted collection is lost and you continue dealing with unsorted one.
Folder.Items.Sort "Received"
For Each itm In Folder.Items
Asking each time the Items property returns a new Items instance. So, you need to get an instance once and then re-use in the code. Only by following this way you will preserve the sorting order.
The 430 error happens on the line:
If Date - itm.ReceivedTime <= NUM_DAYS Then
The error code indicates that Class doesn't support Automation (Error 430) which don't tell us anything meaningful.
Anyway, calculating dates that way to get items for specific dates in Outlook is not the best and proper way. Instead, you need to consider using the Find/FindNext or Restrict methods of the Items class which allows getting/dealing with items that correspond to your conditions only. Read more about these methods in the articles I wrote for the technical blog:
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
For example, you could use the following search criteria to get items for a specific timeframe:
'This filter uses urn:schemas:httpmail namespace
strFilter = AddQuotes("urn:schemas:httpmail:datereceived") _
& " > '" & datStartUTC & "' AND " _
& AddQuotes("urn:schemas:httpmail:datereceived") _
& " < '" & datEndUTC & "'"
See Filtering Items Using a Date-time Comparison for more information.
in Outlook I would like to have a FollowUp-Solution that checks a specific folder (Source Folder) if there are mails older than 1 days and moves them in another specific folder (Target Folder).
My problem is that it seems as my code isn't looping the SourceFolder properly. Some mails are moved but some old mails are still in the SourceFolder.
When I restart the Code some of the remaining mails are moved now but still some remain in the SourceFolder.
I tried to loop the Items in other ways (with; for each; do) but I guess my vba understanding is too bad to get a working solution.
Sub MoveFollowUpItems()
Dim FolderTarget As Folder
Dim FolderSource As Folder
Dim Item As Object
Dim FolderItems As Outlook.Items
Set FolderTarget = Application.GetNamespace("MAPI").GetDefaultFolder(olFolderInbox)
Set FolderSource = Application.GetNamespace("MAPI").GetDefaultFolder(olFolderInbox).Folders("FollowUp")
Set FolderItems = FolderSource.Items
For Each Item In FolderItems
If Item.ReceivedTime < Date - 1 Then '
Item.Move FolderTarget
End If
Next
End Sub
Does anyone know how to handle the propper looping?
For Each Loop is a great but When moving/deleting items Loop Through in Reverse Order you know count down (ie 3,2,1). In order to do this, you can incorporate Step -1 into your loop statement.
Also to improve your loop try using Items.Restrict Method (Outlook) on your date filter
Example
Option Explicit
Sub MoveFollowUpItems()
Dim FolderTarget As Folder
Dim FolderSource As Folder
Dim FolderItems As Outlook.Items
Set FolderTarget = Application.GetNamespace("MAPI").GetDefaultFolder(olFolderInbox)
Set FolderSource = Application.GetNamespace("MAPI").GetDefaultFolder(olFolderInbox).Folders("FollowUp")
Dim Filter As String
Filter = "#SQL=" & Chr(34) & "urn:schemas:httpmail:datereceived" & _
Chr(34) & " <= 'Date - 1' "
Set FolderItems = FolderSource.Items.Restrict(Filter)
Debug.Print FolderItems.Count
Dim i As Long
For i = FolderItems.Count To 1 Step -1
Debug.Print FolderItems(i) 'Immediate Window
' FolderItems(i).Move FolderTarget
Next
End Sub
I am using the following script to pull in the fields I need for a project from the Global Address Book in excel, and it is functioning properly, but I would like to add a field that includes the floor number that an individual sits on. Does anyone know how to add this field? I have tried all of the fields withing the GetExchangeUser object group. Please let me know! I would be very grateful!!
Sub GetOutlookAddressBook()
' Need to add reference to Outlook
'(In VBA editor Tools References MS Outlook #.# Library)
' Adds addresses to existing Sheet called Address and
' defines name Addresses containing this list
' For use with data Validation ListBox (Source as =Addresses)
On Error GoTo 0
Dim objOutlook As Outlook.Application
Dim objAddressList As Outlook.AddressList
Dim objAddressEntry As Outlook.AddressEntry
Dim lngCounter As Long
Application.ScreenUpdating = False
' Setup connection to Outlook application
Set objOutlook = CreateObject("Outlook.Application")
Set objAddressList = objOutlook.Session.AddressLists("Global Address List")
Application.EnableEvents = False
'Application.DisplayAlerts = False
' Clear existing list
Sheets("Address").Range("A:A").Clear
'Step through each contact and list each that has an email address
For Each objAddressEntry In objAddressList.AddressEntries
If objAddressEntry.AddressEntryUserType = olExchangeUserAddressEntry Then
lngCounter = lngCounter + 1
Application.StatusBar = "Address no. " & lngCounter & " ... " & objAddressEntry.Address
Sheets("Address").Cells(lngCounter, 1) = objAddressEntry.GetExchangeUser.Alias
Sheets("Address").Cells(lngCounter, 2) = objAddressEntry.GetExchangeUser.Name
Sheets("Address").Cells(lngCounter, 3) = objAddressEntry.GetExchangeUser.CompanyName
Sheets("Address").Cells(lngCounter, 4) = objAddressEntry.GetExchangeUser.Address
Sheets("Address").Cells(lngCounter, 5) = objAddressEntry.GetExchangeUser.Department
Sheets("Address").Cells(lngCounter, 6) = objAddressEntry.GetExchangeUser.JobTitle
Sheets("Address").Cells(lngCounter, 7) = objAddressEntry.GetExchangeUser.OfficeLocation
DoEvents
End If
Next objAddressEntry
' Define range called "Addresses" to the list of emails
'Sheets("Address").Cells(1, 1).Resize(lngCounter, 1).Name = "Addresses"
'error:
Set objOutlook = Nothing
Application.StatusBar = False
Application.EnableEvents = False
End Sub
Thanks!!
Lacey
.OfficeLocation is about it :), there is no floor number property available.
How can I copy a recurring appointment in outlook 2013 with VBA? I've tried copying the RecurrencePattern Object from the source item to the destination item (cAppt), but this sets the start date to the next immediate calendar interval (e.g. if it is 4:12 now, the recurring series is set to start at today at 4:30) instead of the actual start date of the original item. Any hints on how to do this?
Private Sub curCal_ItemAdd(ByVal Item As Object)
Dim cAppt As AppointmentItem
Dim oPatt As RecurrencePattern
Dim cPatt As RecurrencePattern
Dim moveCal As AppointmentItem
' On Error Resume Next
'only copy items not marked as private
If Item.Sensitivity <> olPrivate Then
Item.Body = Item.Body & "[" & GetGUID & "]"
Item.Save
Set cAppt = Application.CreateItem(olAppointmentItem)
If Item.IsRecurring Then
Set cPatt = cAppt.GetRecurrencePattern
cPatt = Item.GetRecurrencePattern
End If
With cAppt
.Subject = Item.Subject
.Start = Item.Start
.Duration = Item.Duration
.Location = Item.Location
.Body = Item.Body
End With
' set the category after it's moved to force EAS to sync changes
Set moveCal = cAppt.Move(newCalFolder)
moveCal.Categories = "moved"
moveCal.Save
End If
End Sub
Try to use AppointmentItem.Copy instead of Application.CreateItem.
I know this is a very old post, but I wanted to share my findings on why OP's original VBScript didn't work.
AppointmentItem.Copy can work, but depending on when it's used it can cause VBScript to break (e.g. copying an appointment to a shared calendar automatically when its added to your personal). Application.CreateItem does not have this drawback.
After doing some testing, I can confirm (in Outlook 2016 anyway) that GetRecurrencePattern method captures all relevant attributes except the StartTime property. As a result, the start time is set to a default of the next immediate time frame on your calendar.
To fix this, you can change the script as follows:
Private Sub curCal_ItemAdd(ByVal Item As Object)
Dim cAppt As AppointmentItem
'Dim oPatt As RecurrencePattern --unnecessary declaration, can delete.
Dim cPatt As RecurrencePattern
Dim moveCal As AppointmentItem
' On Error Resume Next
'only copy items not marked as private
If Item.Sensitivity <> olPrivate Then
Item.Body = Item.Body & "[" & GetGUID & "]"
Item.Save
Set cAppt = Application.CreateItem(olAppointmentItem)
If Item.IsRecurring Then
Set cPatt = cAppt.GetRecurrencePattern
cPatt = Item.GetRecurrencePattern
cPatt.StartTime = Item.Start 'Add appointment time as StartTime.
cPatt.Duration = Item.Duration 'need to define Duration (or EndTime) after changing StartTime.
End If
With cAppt
.Subject = Item.Subject
.Start = Item.Start
.Duration = Item.Duration
.Location = Item.Location
.Body = Item.Body
End With
' set the category after it's moved to force EAS to sync changes
Set moveCal = cAppt.Move(newCalFolder)
moveCal.Categories = "moved"
moveCal.Save
End If
End Sub
Also, not sure if OP needed to give credit, but credit where credit is due the code is mostly copypasta from http://www.slipstick.com/developer/copy-new-appointments-to-another-calendar-using-vba/
I've been trying to delete the attachments in Outlook after copying them using for each loop. It just deletes the very first attachment after copying it but does not go for the second attachment to work on! It just goes down to the End Sub.
Private Sub Items_ItemAdd(ByVal item As Object)
On Error GoTo ErrorHandler
'Only act if it's a MailItem
Dim Msg As Outlook.MailItem
If TypeName(item) = "MailItem" Then
Set Msg = item
'Change variables to match need. Comment or delete any part unnecessary.
'If (Msg.SenderName = "Name Of Person") And _
'(Msg.Subject = "Subject to Find") And _
'(Msg.Attachments.Count >= 1) Then
'Set folder to save in.
Dim olDestFldr As Outlook.MAPIFolder
Dim myAttachments As Outlook.Attachments
Dim olAttch As Outlook.Attachment
Dim Att As String
'location to save in. Can be root drive or mapped network drive.
Const attPath As String = "C:\Users\pkshahbazi\Documents\EmailAttachments\"
Set myAttachments = Msg.Attachments
For Each olAttch In myAttachments
Att = olAttch.DisplayName
If Right(olAttch.FileName, 3) = "zip" Then
olAttch.SaveAsFile attPath & Att
olAttch.Delete
End If
Next olAttch
Msg.UnRead = False
End If
ProgramExit:
Exit Sub
ErrorHandler:
MsgBox Err.Number & " - " & Err.Description
Resume ProgramExit
End Sub
I figured out that the OlAttch.delete statement confuses the For Each loop.
Any idea how I can delete the attachments.
In your previous question we changed from an indexed loop to a non-indexed loop, because you did not have any .Delete requirement. Unfortunately, deleting items from a collection requires an indexed iteration.
This is because, when you have 3 items:
Item 1 = Attachment 1
Item 2 = Attachment 2
Item 3 = Attachment 3
Then when you delete the first item (Item 1/Attachment 1), it takes you to item 2, but when the delete happens, you are left with the collection that looks like:
Item 1 = Attachment 2
Item 2 = Attachment 3
So your loop will delete items 1 and 3, but it will never touch item 2.
The simplest way to fix this for you, without using an indexed loop and re-writing your script, is to just add another loop to do the delete method.
#Enderland provides the example for this. I will not duplicate his effort, but I did want to explain what is happening for you. This is always the case when deleting items from a collection, you have to step through the collection in reverse order.
Try this. I added code/comments to iterate through and remove all the attachments after you do your saving. The reasons you should do this are explained very well here by David Zemens.
You also should get in the habit of saving messages you modify in Outlook VBA as sometimes this is important, sometimes it's not, but it can confuse the heck out of you if you don't use Save when you need to.
'location to save in. Can be root drive or mapped network drive.
Const attPath As String = "C:\Users\pkshahbazi\Documents\EmailAttachments\"
Set myAttachments = Msg.Attachments
For Each olAttch In myAttachments
Att = olAttch.DisplayName
If Right(olAttch.FileName, 3) = "zip" Then
olAttch.SaveAsFile attPath & Att
'olAttch.Delete
End If
Next olAttch
'iterate through all attachments, going backwards
dim j as integer
For j = Msg.Attachments.Count To 1 Step -1
Msg.Attachments.Remove (j)
Next j
'make sure to save your message after this
Msg.save
Msg.UnRead = False
End If