Outlook VBA Stumbling Over "Undeliverable" Report - vba

I have VBA code that marks selected messages as read, assigns a category and moves them to a subfolder.
Mail Delivery System "Undeliverable" reports are not marked-as-read, categorized or moved.
I tried to duplicate the For Each loop to look for olReportItem. (I realize that it is inefficient to have two loops, but am just doing it this way for testing purposes so I can keep all the beta code in one section.)
Sub TestMoveToSubfolder()
'With selected emails: (1) mark as read, (2) assign category, (3) move to subfolder
On Error Resume Next
Dim thisFolder As Outlook.MAPIFolder
Dim objFolder As Outlook.MAPIFolder
Dim objItem As Outlook.MailItem
Dim objStore As Store
Set thisFolder = Application.ActiveExplorer.CurrentFolder
Set objStore = thisFolder.Store
Set objFolder = thisFolder.Folders("REFERENCE_DESIRED_FOLDER")
'Be sure target folder exists
If objFolder Is Nothing Then
MsgBox "I can't find the designated subfolder.", vbOKOnly + vbExclamation, "INVALID SUBFOLDER"
Exit Sub
End If
'Confirm at least one message is selected
If Application.ActiveExplorer.Selection.Count = 0 Then
Exit Sub
End If
'Loop through emails
For Each objItem In Application.ActiveExplorer.Selection
If objFolder.DefaultItemType = olMailItem Then
If objItem.Class = olMail Then
objItem.UnRead = False
objItem.Categories = "INSERT_DESIRED_CATEGORY"
objItem.Move objFolder
End If
End If
Next
'TEST SECTION to work with undeliverable reports
Dim objItem2 As Outlook.ReportItem
'Loop through nondelivery reports
For Each objItem2 In Application.ActiveExplorer.Selection
If objFolder.DefaultItemType = olMailItem Then
If objItem2.Class = olReportItem Then
objItem2.UnRead = False
objItem2.Categories = "INSERT_DESIRED_CATEGORY"
objItem2.Move objFolder
End If
End If
Next
Set objItem2 = Nothing
Set thisFolder = Nothing
Set objFolder = Nothing
Set objItem = Nothing
Set objStore = Nothing
End Sub

The problem is related to declaring the objItem in the following way:
Dim objItem As Outlook.MailItem
or
Dim objItem2 As Outlook.ReportItem
To be able to iterate over all items selected in Outlook you need to declare the objItem as object in the code.
Typically to find out the exact line of code causing the issue you need to remove the following line:
On Error Resume Next
There also no need to have two separate loops, you may combine two conditions into the single loop:
Dim objItem As Object
'Loop through emails
For Each objItem In Application.ActiveExplorer.Selection
' check for regular mail items
If objItem.Class = olMail Then
objItem.UnRead = False
objItem.Categories = "INSERT_DESIRED_CATEGORY"
objItem.Move objFolder
End If
' check for report items
If objItem.Class = olReportItem Then
objItem.UnRead = False
objItem.Categories = "INSERT_DESIRED_CATEGORY"
objItem.Move objFolder
End If
Next

As I said in my comment, no olReportItem class exists. Declaring objItem As Variant (or As Object) will allow iteration between all selection clases (in a unique iteration. Something like that:
Dim objItem
For Each objItem In appOutlook.ActiveExplorer.Selection
If objFolder.DefaultItemType = olMailItem Then
If objItem.Class = olMail Then
objItem.UnRead = False
objItem.Categories = "INSERT_DESIRED_CATEGORY"
objItem.Move objFolder
ElseIf objItem.Class = olReport Then
Stop
'do whatever you need here...
End If
End If
Next

For the record, the final working code is below. I don't want to mark this as the answer since that seems like I am trying to take credit for the work of #niton, #FaneDuru and #Eugene Astafiev, but thanks to their input the question has been answered and the problem is solved.
Sub TestMoveToSubfolder()
'With selected emails: (1) mark as read, (2) assign category, (3) move to subfolder
Dim thisFolder As Outlook.MAPIFolder
Dim objFolder As Outlook.MAPIFolder
Dim objItem As Object 'could also define as Variant
Dim objStore As Store 'used if you want to find subfolder of current mailbox
'set folder locations
Set thisFolder = Application.ActiveExplorer.CurrentFolder 'alternative is Set thisFolder = objItem.Parent
Set objStore = thisFolder.Store 'alternative is to bypass thisFolder and use Set objStore = objItem.Parent.MAPIFolder.Store
On Error Resume Next
Set objFolder = thisFolder.Folders("REFERENCE_DESIRED_FOLDER")
On Error GoTo 0
'Be sure target folder exists
If objFolder Is Nothing Then
MsgBox "I can't find the designated subfolder.", vbOKOnly + vbExclamation, "INVALID FOLDER"
Exit Sub
End If
'Require that this procedure be called only when a message is selected
If Application.ActiveExplorer.Selection.Count = 0 Then
Exit Sub
End If
'Loop through selected items
For Each objItem In Application.ActiveExplorer.Selection
If objFolder.DefaultItemType = olMailItem Then
If objItem.Class = olMail Then
objItem.UnRead = False
objItem.Categories = "INSERT_DESIRED_CATEGORY"
objItem.Save
If thisFolder <> objFolder Then objItem.Move objFolder
ElseIf objItem.Class = olReport Then
objItem.UnRead = False
objItem.Categories = "INSERT_DESIRED_CATEGORY"
objItem.Save
If thisFolder <> objFolder Then objItem.Move objFolder
End If
End If
Next
'Clean up
Set thisFolder = Nothing
Set objFolder = Nothing
Set objItem = Nothing
Set objStore = Nothing
End Sub

Related

How to send mail based on a draft then keep the draft?

We are updating mails from the drafts folder and sending them a few times a day.
I want to open a selected mail resend it save it so it goes back to drafts and then close it.
I tried below
Sub DRAFT()
Dim myItem As Outlook.MailItem
Dim objInsp As Outlook.Inspector
Dim objActionsMenu As Office.CommandBarControl
Dim olResendMsg As Outlook.MailItem
' get current item & open if needed
On Error Resume Next
Select Case TypeName(Application.ActiveWindow)
Case "Explorer"
Set myItem = Application.ActiveExplorer.Selection.Item(1)
myItem.Display
Case "Inspector"
Set myItem = Application.ActiveInspector.CurrentItem
Case Else
End Select
On Error GoTo 0
If myItem Is Nothing Then
MsgBox "Could not use current item. Please select or open a single email.", _
vbInformation
GoTo exitproc
End If
' run the resend command
Set objInsp = myItem.GetInspector
objInsp.CommandBars.ExecuteMso ("ResendThisMessage")
' save orig email
myItem.Save
' close orig email
myItem.Close
exitproc:
Set myItem = Nothing
Set objInsp = Nothing
Set objActionsMenu = Nothing
Set olResendMsg = Nothing
End Sub
You need to pass a OlInspectorClose enumeration value to the MailItem.Close method. It indicates the close behavior, i.e. the save mode. If the item displayed within the inspector has not been changed, this argument has no effect.
Name Value Description
olDiscard 1 Changes to the document are discarded.
olPromptForSave 2 User is prompted to save documents.
olSave 0 Documents are saved.
So, your code should like that:
' close orig email
myItem.Close olSave
Instead of executing the ribbon control programmatically using the CommandBars.ExecuteMso method you may try to create a cope of the source item and then send it.
The ExecuteMso method is useful in cases where there is no object model for a particular command. Works on controls that are built-in buttons, toggleButtons and splitButtons. On failure it returns E_InvalidArg for an invalid idMso, and E_Fail for controls that are not enabled or not visible.
Instead, you may use the MailItem.Copy method which creates another instance of an object.
Sub CopyItem()
Dim myNameSpace As Outlook.NameSpace
Dim myFolder As Outlook.Folder
Dim myNewFolder As Outlook.Folder
Dim myItem As Outlook.MailItem
Dim myCopiedItem As Outlook.MailItem
Set myNameSpace = Application.GetNamespace("MAPI")
Set myFolder = myNameSpace.GetDefaultFolder(olFolderInbox)
Set myNewFolder = myFolder.Folders.Add("Saved Mail", olFolderDrafts)
Set myItem = Application.CreateItem(olMailItem)
myItem.Subject = "Speeches"
Set myCopiedItem = myItem.Copy
myCopiedItem.To = "email#address.com"
myCopiedItem.Send()
End Sub
Although there is a mistake in myItem.Close, you cannot resend mail that has not been sent.
Option Explicit
Sub SendMailBasedOnPermanentDraft()
Dim myItem As MailItem
Dim objInsp As Inspector
Dim myCopyOfUnsentItemInDrafts As MailItem
' get current item & open if needed
On Error Resume Next
Select Case TypeName(ActiveWindow)
Case "Explorer"
Set myItem = ActiveExplorer.Selection.Item(1)
Case "Inspector"
Set myItem = ActiveInspector.CurrentItem
Case Else
End Select
On Error GoTo 0
If myItem Is Nothing Then
MsgBox "Could not use current item. Please select or open a single email.", vbInformation
GoTo exitProc
End If
If myItem.Sent = False Then
Set myCopyOfUnsentItemInDrafts = myItem.copy
With myCopyOfUnsentItemInDrafts
.Subject = "Copied " & Now & ": " & myItem.Subject
.Save
.Display ' change to .Send
End With
Else
MsgBox "Select or open a single unsent email.", vbInformation
End If
exitProc:
Set myItem = Nothing
Set objInsp = Nothing
Set myCopyOfUnsentItemInDrafts = Nothing
End Sub

My VBA loop is not starting at the beginning of a subfolder in Outlook

I have the below code that runs through a folder looking for unread messages from a specific person with a specific subject. The loop is not beginning at the most recent emails. It's beginning a month ago where all the messages are read.
Sub MovingAttachmentsIntoNetworkFolders()
Dim olApp As Outlook.Application
Dim objNS As Outlook.NameSpace
Dim olFolder As Outlook.MAPIFolder
Set olApp = Outlook.Application
Set objNS = olApp.GetNamespace("MAPI")
Set olFolder = objNS.GetDefaultFolder(olFolderInbox).Folders("Email Subfolder") 'Specify Folder here
On Error GoTo ErrorHandler
For Each Item In olFolder.Items
Debug.Print Item.ReceivedTime
If Item.UnRead = True Then
If TypeOf Item Is Outlook.MailItem Then
Dim oMail As Outlook.MailItem: Set oMail = Item
Debug.Print Item.SenderEmailAddress
Debug.Print Item.Subject
Debug.Print Item.Attachments.Count
If Item.Sender = "emailaddress#email.com" And _
Item.Subject = "EmailSubject" And _
Item.Attachments.Count = 1 Then
'Set folder to save in.
Dim olDestFldr As Outlook.MAPIFolder
Dim myAttachments As Outlook.Attachments
Dim Att As String
'location to save in. Can be root drive or mapped network drive.
Const attPath As String = "mappednetworkdrive"
' save attachment
Set myAttachments = Item.Attachments
Att = myAttachments.Item(1).FileName
Debug.Print Att & "\" & Format(Item.ReceivedTime, "mm-dd-yyyy")
myAttachments.Item(1).SaveAsFile Format(Item.ReceivedTime, "mm.dd.yyyy") & " " & Att
' mark as read
Item.UnRead = False
End If
End If
End If
Next
ProgramExit:
Exit Sub
ErrorHandler:
MsgBox Err.Number & " - " & Err.Description
Resume ProgramExit
End Sub
Any reason why my code is behaving this way?
For a For Each loop, you can sort a collection of the items in the folder by ReceivedTime as described here Email data exported to Excel - Sort by Received Date
Note: Untested code to demonstrate how to sort
Option Explicit
Sub MovingAttachmentsIntoNetworkFolders()
Dim objNS As NameSpace
Dim olFolder As Folder
dim objItem as object
dim fldItems as items
Set objNS = GetNamespace("MAPI")
Set olFolder = objNS.GetDefaultFolder(olFolderInbox)
'Specify Folder here
Set olFolder = olFolder.Folders("Email Subfolder")
On Error GoTo ErrorHandler
' https://stackoverflow.com/questions/14948295/email-data-exported-to-excel-sort-by-received-date
set fldItems = olFolder.Items
fldItems.Sort "ReceivedTime", true
For Each objItem In fldItems
Debug.Print objItem.ReceivedTime
If objItem.UnRead = True Then
If TypeOf objItem Is MailItem Then
Debug.Print objItem.SenderEmailAddress
Debug.Print objItem.Subject
Debug.Print objItem.Attachments.Count
If objItem.Sender = "emailaddress#email.com" And _
objItem.Subject = "EmailSubject" And _
objItem.Attachments.Count = 1 Then
' mark as read
objItem.UnRead = False
End If
End If
End If
set objItem = Nothing
Next
ProgramExit:
Set objNS = Nothing
Set olFolder = Nothing
set fldItems = Nothing
set objItem = Nothing
Exit Sub
ErrorHandler:
MsgBox Err.Number & " - " & Err.Description
Resume ProgramExit
End Sub
If code is in Outlook there is no need to reference Outlook.
Avoid using Item and olMail for variable names as they already have a purpose.

How do I move an email in Outlook to a subfolder?

I am trying to create a macro that will move items in my Outlook inbox to a subfolder of another folder that is on the same level as the Inbox (i.e., the parent folder is not a sub-folder of the inbox). This is the code I am using:
Sub EventRequests()
On Error Resume Next
Dim ns As Outlook.NameSpace
Dim moveToFolder As Outlook.MAPIFolder
Dim objItem As Outlook.MailItem
Set ns = Application.GetNamespace("MAPI")
'Define path to the target folder
Set moveToFolder = ns.Folders("Events").Folders("Event Requests")
If Application.ActiveExplorer.Selection.Count = 0 Then
MsgBox ("Select an E-mail first")
Exit Sub
End If
If moveToFolder Is Nothing Then
MsgBox "Target folder not found!", vbOKOnly + vbExclamation, "Move Macro Error"
End If
For Each objItem In Application.ActiveExplorer.Selection
If moveToFolder.DefaultItemType = olMailItem Then
If objItem.Class = olMail Then
objItem.Move moveToFolder
End If
End If
Next
Set objItem = Nothing
Set moveToFolder = Nothing
Set ns = Nothing
End Sub
When I run the code I get an error that says "Target folder not found!" I tried
Set moveToFolder = ns.GetDefaultFolder(olFolderInbox).Folders("Events").Folders("Event Requests")and Set MoveToFolder = ns.Folders("Mailbox - my name").Folders(targetFolder) but neither of those worked. I have a different macro set up that moves messages in my inbox to a folder that is a subfolder of my inbox and it works fine:
Set moveToFolder = ns.GetDefaultFolder(olFolderInbox).Folders("Completed")
How do I fix the target path so that it points to the correct subfolder?
I'm going to go ahead and post an answer to my own question so that if other people in the future have this issue they can see the code I arrived at that works:
Sub EventRequests()
Dim ns As Outlook.NameSpace
Dim moveToFolder As Outlook.MAPIFolder
Dim objItem As Outlook.MailItem
Set ns = Application.GetNamespace("MAPI")
On Error GoTo 0
Set moveToFolder = ns.GetDefaultFolder(olFolderInbox).Parent.Folders("Events").Folders("Event Requests")
If Application.ActiveExplorer.Selection.Count = 0 Then
MsgBox ("Select an E-mail first")
Exit Sub
End If
If moveToFolder Is Nothing Then
MsgBox "Target folder not found!", vbOKOnly + vbExclamation, "Move Macro Error"
End If
For Each objItem In Application.ActiveExplorer.Selection
If moveToFolder.DefaultItemType = olMailItem Then
If objItem.Class = olMail Then
objItem.Move moveToFolder
End If
End If
Next
Set objItem = Nothing
Set moveToFolder = Nothing
Set ns = Nothing
End Sub

Move e-mails by senderemailaddress outlook macro

I want to move some messages from Inbox to a subfolder but this code (that I have copied from other forum) is not working. Can you tell me what is going wrong? Do you think it is not working because of the fact that I have two different accounts in this Outlook?
Public Sub Move_Items()
'// Declare your Variables
Dim Inbox As Outlook.MAPIFolder
Dim SubFolder As Outlook.MAPIFolder
Dim olNs As Outlook.NameSpace
Dim Item As Object
Dim Items As Outlook.Items
Dim lngCount As Long
On Error GoTo MsgErr
Set Inbox Reference
Set olNs = Application.GetNamespace("MAPI")
Set Inbox = Application.ActiveExplorer.CurrentFolder
Set Items = Inbox.Items
'// Loop through the Items in the folder backwards
For lngCount = Inbox.Items.Count To 1 Step -1
Set Item = Inbox.Items.Item(lngCount)
If Item.Class = olMail Then
Select Case Item.SenderEmailAddress
'// Email_One
Case "bb"
// Set SubFolder of Inbox
Set SubFolder = Inbox.Folders("BB")
Set Item = Items.Find("[SenderEmailAddress] = 'bb#gmail.com'")
If TypeName(Item) <> "Nothing" Then
// Mark As Read
Item.UnRead = False
// Move Mail Item to sub Folder
Item.Move SubFolder
End If
'// Email_Two
Case "aa"
'// Set SubFolder of Inbox
Set SubFolder = Inbox.Folders("AA")
Set Item = Items.Find("[SenderEmailAddress] = 'aa#gmail.com'")
If TypeName(Item) <> "Nothing" Then
'// Mark As Read
Item.UnRead = False
'// Move Mail Item to sub Folder
Item.Move SubFolder
End If
Case Else:
Exit Sub
End Select
End If
Next lngCount
MsgErr_Exit:
Set Inbox = Nothing
Set SubFolder = Nothing
Set olNs = Nothing
Set Item = Nothing
Set Items = Nothing
Exit Sub
'// Error information
MsgErr:
MsgBox "An unexpected Error has occurred." _
& vbCrLf & "Error Number: " & Err.Number _
& vbCrLf & "Error Description: " & Err.Description _
, vbCritical, "Error!"
Resume MsgErr_Exit
End Sub
Your Select Case is not set correctly-
Case "bb" should be Case "bb#gmail.com" & Case "aa" should be Case "aa#gmail.com"
also Set SubFolder = Inbox.Folders("BB") BB should be your subfolder name
__
Option Explicit
Public Sub Move_Items()
'// Declare your Variables
Dim Inbox As Outlook.MAPIFolder
Dim SubFolder As Outlook.MAPIFolder
Dim Folder As Outlook.MAPIFolder '<- has been added
Dim olNs As Outlook.NameSpace
Dim Item As Outlook.MailItem
Dim Items As Outlook.Items
Dim lngCount As Long
' On Error GoTo MsgErr
'// Set Inbox Reference
Set olNs = Application.GetNamespace("MAPI")
Set Inbox = olNs.GetDefaultFolder(olFolderInbox)
Set Folder = Application.Session.PickFolder
Set Items = Inbox.Items
'// Loop through the Items in the folder backwards
For lngCount = Inbox.Items.Count To 1 Step -1
Set Item = Inbox.Items.Item(lngCount)
Debug.Print Item.Subject
If Item.Class = olMail Then
Select Case Item.SenderEmailAddress
' // Email_One
Case "bb#gmail.com"
' // Set SubFolder of Inbox
Set SubFolder = Inbox.Folders("Temp")
Set Item = Items.Find("[SenderEmailAddress] = 'bb#gmail.com'")
If TypeName(Item) <> "Nothing" Then
' // Mark As Read
Item.UnRead = False
' // Move Mail Item to sub Folder
Item.Move SubFolder
End If
' // Email_Two
Case "aa#gmail.com"
' // Set SubFolder of Inbox
Set SubFolder = Inbox.Folders("Temp")
Set Item = Items.Find("[SenderEmailAddress] = 'aa#gmail.com'")
If TypeName(Item) <> "Nothing" Then
' // Mark As Read
Item.UnRead = False
' // Move Mail Item to sub Folder
Item.Move SubFolder
End If
End Select
End If
Next lngCount
MsgErr_Exit:
Set Inbox = Nothing
Set SubFolder = Nothing
Set olNs = Nothing
Set Item = Nothing
Set Items = Nothing
Exit Sub
'// Error information
MsgErr:
MsgBox "An unexpected Error has occurred." _
& vbCrLf & "Error Number: " & Err.Number _
& vbCrLf & "Error Description: " & Err.Description _
, vbCritical, "Error!"
Resume MsgErr_Exit
End Sub

how to pull received time from all emails in outlook mailbox

I have most of this worked out already, but need assistance. I want to store all of the received times of the emails from various outlook folders. All of the folders are inside the same folder so I have an array to go through each of these. I need the times stored into a variable that I can then display in or write.console. There will be hundreds of times to display. The variable is Totalmsg that I want these times stored in, then displayed once complete.
Sub EmailArrivalTimes()
Dim objOutlook As Object, objnSpace As Object, objFolder As MAPIFolder
Dim MailItem
Dim EmailCount() As Integer, arrNames
Set objOutlook = CreateObject("Outlook.Application")
Set objnSpace = objOutlook.GetNamespace("MAPI")
arrNames = Array ("Andrew", "Ashton", "Becca", "Beth", "Bree", "Brittany", "Cecilia", "Chance", "Christina J.", "Christine", "Dustin", "James", "Jeff", "Jenni", "Jennifer W.", "Josh", "Josie", "Kara", "Lisa", "Megan", "Misti", "Nathan", "Paul", "Sam", "Shane", "Shawna") 'add other names here...
ReDim EmailCount(LBound(arrNames) To UBound(arrNames))
For x = LBound(arrNames) To UBound(arrNames)
On Error Resume Next
Set objFolder = objnSpace.Folders("Mailbox - IT Support Center"). _
Folders("Onshore - " & arrNames(x)).Folders("completed")
On Error GoTo 0
ArrivalTime = 0
Dim Totalmsg
If Not objFolder Is Nothing Then
For Each MailItem In objFolder.Items
Totalmsg = MailItem.ReceivedTime
Next
End If
Set OutMail = Nothing
Set OutApp = Nothing
Set objFolder = Nothing
Set objnSpace = Nothing
Set objOutlook = Nothing
End Sub
Right now you are overwriting the value of TotalMsg at each iteration in this loop:
If Not objFolder Is Nothing Then
For Each MailItem In objFolder.Items
Totalmsg = MailItem.ReceivedTime
Next
End If
You will want to append to it, instead:
If Not objFolder Is Nothing Then
For Each MailItem In objFolder.Items
Totalmsg = TotalMsg & vbCRLF & MailItem.ReceivedTime
Next
End If
Debug.Print TotalMsg
'Note: this will likely exceed what can fit in the console window, _
' but you can instead write the string to a text file/etc.