How to move mail to a folder based on attachment filename? - vba

I need a rule (or most probably a VBA macro) to sort my mails. In case I have per say "REPORT" in the filename of the attachment of a newly received mail than I would like to move that mail to a different folder, let say "REPORTS" folder.
How can I achieve this?
I already to set a rule on the mail header but that did not seem to solve the matter.
Thanks in advance!

Used code from http://www.outlookcode.com/article.aspx?id=62 and http://blog.saieva.com/2010/03/27/move-messages-to-folders-with-outlook-vba/
'code goes in "ThisOutlookSession" module
Private Sub Application_NewMailEx(ByVal EntryIDCollection As String)
Dim arr() As String
Dim i As Integer
Dim ns As Outlook.NameSpace
Dim itm As MailItem
Dim m As Outlook.MailItem
Dim att As Outlook.Attachment
On Error Resume Next
Set ns = Application.Session
arr = Split(EntryIDCollection, ",")
For i = 0 To UBound(arr)
Set itm = ns.GetItemFromID(arr(i))
If itm.Class = olMail Then
Set m = itm
If m.Attachments.Count > 0 Then
For Each att In m.Attachments
If UCase(att.FileName) Like "*REPORT*" Then
MoveToFolder m, "MoveTest"
Exit For
End If
Next att
End If
End If
Next
Set ns = Nothing
Set itm = Nothing
Set m = Nothing
End Sub
Sub MoveToFolder(mItem As MailItem, folderName)
'###you need to edit this for your account name###
Const mailboxNameString As String = "Mailbox - firstname lastname"
Dim olApp As New Outlook.Application
Dim olNameSpace As Outlook.NameSpace
Dim olDestFolder As Outlook.MAPIFolder
Set olNameSpace = olApp.GetNamespace("MAPI")
Set olDestFolder = olNameSpace.Folders(mailboxNameString).Folders(folderName)
Debug.Print "[" & Date & " " & Time & "] " & _
": folder = " & folderName & _
"; subject = " & mItem.Subject & "..."
mItem.Move olDestFolder
End Sub

Related

Saving attachments either returns 91 error or does not save

I'm trying to set up a macro in ThisOutlookSession to save attachments to file.
I previously used rules and 'run a script', but it is not enabled for all users.
The below code either returns a 91 error (object or variable not set), or it runs without error, but doesn't save.
The code is looking at a subfolder, to save all attachments to a location based on subject. The emails are sent to the subfolder through a rule.
I want to rename the attachments based on the ReceivedTime, and I think this is where the issue arises. If I use Msg.ReceivedTime, I get the 91 error. If I use Item.ReceivedTime, there is no error, but the file is not saved.
Here is the source where I derived most of the code and customized. https://www.tachytelic.net/2017/10/how-to-run-a-vba-macro-when-new-mail-is-received-in-outlook/
Private WithEvents folderItems As Outlook.Items
Private Sub Application_Startup()
Dim outlookApp As Outlook.Application
Dim objectNS As Outlook.NameSpace
Set outlookApp = Outlook.Application
Set objectNS = outlookApp.GetNamespace("MAPI")
Set folderItems = objectNS.GetDefaultFolder(olFolderInbox).Folders("Operations").Folders("Test").Items
End Sub
Private Sub folderItems_ItemAdd(ByVal Item As Object)
On Error GoTo ErrorHandler
Dim att As Outlook.Attachment
Dim msg As Outlook.MailItem
Dim filepath As String, filedate As String
filepath = "C:\Documents\"
filedate = Format(Item.ReceivedTime, "YYYYMMDD") 'This is the line which I think is the problem. If I do Msg.ReceivedTime, I get 91 error, but if I do Item.ReceivedTime, it does not save
If TypeName(Item) = "MailItem" Then
If InStr(Item.Subject, "XXX") > 0 Then
For Each att In Item.Attachments
att.SaveAsFile filepath & "XXX\" & filedate & "_raw.csv"
Next
ElseIf InStr(Item.Subject, "YYY") > 0 Then
For Each att In Item.Attachments
att.SaveAsFile filepath & "YYY\" & filedate & "_raw.xlsx"
Next
ElseIf InStr(Item.Subject, "ZZZ") > 0 Then
For Each att In Item.Attachments
att.SaveAsFile filepath & "ZZZ.csv"
Next
End If
End If
ExitNewItem:
Exit Sub
ErrorHandler:
MsgBox Err.Number & " - " & Err.Description
Resume ExitNewItem
End Sub
My hypothesis is that the ReceivedTime is the issue. If I can use Msg.ReceivedTime, how do I set the variable? Or, if Item.ReceivedTime is correct, why does it not save?
Try the following
Dim att As Outlook.attachment
Dim msg As Outlook.MailItem
Dim filepath As String, filedate As String
filepath = "C:\Documents\"
If TypeName(Item) = "MailItem" Then
Set msg = Item
Debug.Print msg.ReceivedTime ' print on Immediate Window
filedate = Format(msg.ReceivedTime, "YYYYMMDD")
If InStr(msg.Subject, "XXX") > 0 Then
For Each att In msg.Attachments
att.SaveAsFile filepath & "XXX\" & filedate & "_raw.csv"
Next
ElseIf InStr(msg.Subject, "YYY") > 0 Then
For Each att In msg.Attachments
att.SaveAsFile filepath & "YYY\" & filedate & "_raw.xlsx"
Next
ElseIf InStr(msg.Subject, "ZZZ") > 0 Then
For Each att In msg.Attachments
att.SaveAsFile filepath & "ZZZ.csv"
Next
End If
End If
also you don't need outlookApp when the code is running within Outlook Application, simply use Application.
Example
Private Sub Application_Startup()
Dim objectNS As Outlook.NameSpace
Set objectNS = Application.GetNamespace("MAPI")
Set folderItems = objectNS.GetDefaultFolder(olFolderInbox) _
.Folders("Operations") _
.Folders("Test").Items
End Sub

Identfy incoming mail by subject

I auto export email details from Outlook to Excel every time a new mail is received. Emails are exported correctly into Excel.
I want to refine the code such that only mails with a specific subject is exported into Excel.
Code used is as follows:
Public WithEvents objMails As Outlook.Items
Private Sub Application_Startup()
Set objMails = Outlook.Application.Session.GetDefaultFolder(olFolderInbox).Items
End Sub
Private Sub objMails_ItemAdd(ByVal Item As Object)
Dim objMail As Outlook.MailItem
Dim strExcelFile As String
Dim objExcelApp As Excel.Application
Dim objExcelWorkBook As Excel.Workbook
Dim objExcelWorkSheet As Excel.Worksheet
Dim nNextEmptyRow As Integer
Dim strColumnB As String
Dim strColumnC As String
Dim strColumnD As String
Dim strColumnE As String
Dim strColumnF As String
If Item.Class = olMail Then
Set objMail = Item
End If
'Specify the Excel file which you want to auto export the email list
'You can change it as per your case
strExcelFile = "C:\Users\pddamoda\Desktop\abc.xlsx"
'Get Access to the Excel file
On Error Resume Next
Set objExcelApp = GetObject(, "Excel.Application")
If Error <> 0 Then
Set objExcelApp = CreateObject("Excel.Application")
End If
Set objExcelWorkBook = objExcelApp.Workbooks.Open(strExcelFile)
Set objExcelWorkSheet = objExcelWorkBook.Sheets("Sheet1")
'Get the next empty row in the Excel worksheet
nNextEmptyRow = objExcelWorkSheet.Range("B" & objExcelWorkSheet.Rows.Count).End(xlUp).Row + 1
'Specify the corresponding values in the different columns
strColumnB = objMail.SenderName
strColumnC = objMail.SenderEmailAddress
strColumnD = objMail.Subject
strColumnE = objMail.ReceivedTime
strColumnF = objMail.Body
'Add the vaules into the columns
objExcelWorkSheet.Range("A" & nNextEmptyRow) = nNextEmptyRow - 1
objExcelWorkSheet.Range("B" & nNextEmptyRow) = strColumnB
objExcelWorkSheet.Range("C" & nNextEmptyRow) = strColumnC
objExcelWorkSheet.Range("D" & nNextEmptyRow) = strColumnD
objExcelWorkSheet.Range("E" & nNextEmptyRow) = strColumnE
objExcelWorkSheet.Range("F" & nNextEmptyRow) = strColumnF
'Fit the columns from A to E
objExcelWorkSheet.Columns("A:F").AutoFit
'Save the changes and close the Excel file
objExcelWorkBook.Close SaveChanges:=True
End Sub
Below is an example of using Item.Restrict, Restrict is better when you have large search range. You can read this post for more information: Find an email starting with specific subject using VBA
sub exampleFilter()
Dim myOlApp As New Outlook.Application
Dim objNamespace As Outlook.Namespace
Dim objFolder As Outlook.MAPIFolder
Dim filteredItems As Outlook.Items
Dim itm As Object
Dim eFilter As String
Set myOlApp = GetObject(, "Outlook.Application")
Set objNamespace = myOlApp.GetNamespace("MAPI")
Set objFolder = objNamespace.GetDefaultFolder(olFolderInbox)
Dim emailSubject As String
emailSubject = "The Subject You like to Filter"
eFilter = "#SQL=" & Chr(34) & "urn:schemas:httpmail:subject" & _
Chr(34) & " = '" + emailSubject + "'"
Set filteredItems = objFolder.Items.Restrict(eFilter)
If filteredItems.Count = 0 Then
debug.print "No Email with that subject found"
Else
For Each itm In filteredItems
Debug.Print itm.Subject
Next
End If
If filteredItems.Count <> 0 Then
Debug.Print "Found " & filteredItems.Count & " items."
End If
End Sub

How to Search Items with Attachment and keyword in Subject using Filter

I am working on a code which attachment will be download to folder location in context to subject by using a subject filter.
After a long search on the internet, my code is working but the problem here is that I want to put the keyword in the subject filter so that it will download the attachment as the subject keep changing every day
e.g. Sub: training_24357 on one day and training_24359 on the next day.
Also, I want to run my code after every 5 minutes automatically, any help will be much appreciated,
below is my code.
Sub Attachment()
Dim OutOpened As Boolean
Dim App As Outlook.Application
Dim Ns As Outlook.NameSpace
Dim Folder As Outlook.MAPIFolder
Dim Attach As Outlook.Attachment
Dim Item As Object
Dim MailItem As Outlook.MailItem
Dim subject As String
Dim saveFolder As String
Dim dateFormat As String
saveFolder = "D:\Outlook\POS Visit Report"
If Right(saveFolder, 1) <> "\" Then saveFolder = saveFolder & "\"
subject = """*POS Visit*"""
OutOpened = False
On Error Resume Next
Set App = GetObject(, "Outlook.Application")
If Err.Number <> 0 Then
Set App = New Outlook.Application
OutOpened = True
End If
On Error GoTo 0
If App Is Nothing Then
MsgBox "Cannot Start Outlook Mail", vbExclamation
Exit Sub
End If
Set Ns = App.GetNamespace("MAPI")
Set Folder = Ns.GetDefaultFolder(olFolderInbox)
If Not olFolder Is Nothing Then
For Each Item In olFolder.Items
If Item.Class = Outlook.ObjectClass.olMail Then
Set MailItem = Item
If MailItem.subject = subject Then
Debug.Print MailItem.subject
For Each Attach In MailItem.Attachments
dateFormat = Format(Now(), "yyyy-mm-dd H-mm")
Attach.SaveAsFile saveFolder & "(" & dateFormat & ")" & " " & Attach
Next
End If
End If
Next
End If
If OutOpened Then App.Quit
Set App = Nothing
End Sub
To Search for Items with Attachment and by Subject line you can use Items.Restrict Method to filter Items collection containing all the match from the filter
Filter Example: [Attachment & Subject Like '%training%']
Filter = "#SQL=" & Chr(34) & "urn:schemas:httpmail:subject" & _
Chr(34) & " Like '%training%' AND " & _
Chr(34) & "urn:schemas:httpmail:hasattachment" & _
Chr(34) & "=1"
VBA Example https://stackoverflow.com/a/42547062/4539709 Or https://stackoverflow.com/a/42777485/4539709
Now if your running the code from Outlook then you do not need to GetObject, or Set App = New Outlook.Application Just simply Set Ns = Application.GetNamespace("MAPI")
To run your code when Items are added to you Inbox - Try working with Application.Startup Event (Outlook) And Items_ItemAdd Event (Outlook)
Items.ItemAdd Event Occurs when one or more Items are added to the specified collection. This event does not run when a large number of items are added to the folder at once.
Code Example:
Private WithEvents Items As Outlook.Items
Private Sub Application_Startup()
Dim olNs As Outlook.NameSpace
Dim Inbox As Outlook.MAPIFolder
Set olNs = Application.GetNamespace("MAPI")
Set Inbox = olNs.GetDefaultFolder(olFolderInbox)
Set Items = Inbox.Items
End Sub
Private Sub Items_ItemAdd(ByVal Item As Object)
If TypeOf Item Is Outlook.MailItem Then
'// call sub here
End If
End Sub

Opening and saving attachments

I have some code that searches the rfin#example.com inbox for messages with a certain subject and then debug prints the subject to the console, I'd like to add code that saves the attachments of those emails flagged by the search. The MSDN documentation was vague on this issue.
The area I'm looking for help with is commented out with '### about 12 lines from the bottom
Sub Search_Inbox()
'This subroutine searchest the RFin Inbox for the prior month's Acting / Additional forms
'Then it saves the .xlsx attachments
Dim objNamespace As Outlook.NameSpace
Dim olShareName As Outlook.Recipient
Dim myDestFolder As Outlook.Folder
Dim objFolder As Outlook.MAPIFolder
Dim DestFolder As Outlook.MAPIFolder
Dim filteredItems As Outlook.Items
Dim itm As Object
Dim Found As Boolean
Dim strFilter As String
Dim mon As String
mon = Format(Date - 30, "mmmm")
Set objNamespace = Application.GetNamespace("MAPI")
Set olShareName = objNamespace.CreateRecipient("rfin#example.com") 'contains secondary address
Set objFolder = objNamespace.GetSharedDefaultFolder(olShareName, olFolderInbox)
Set DestFolder = objNamespace.GetSharedDefaultFolder(olShareName, olFolderToDo)
strFilter = "#SQL=" & Chr(34) & "urn:schemas:httpmail:subject" & Chr(34) & " like '%" & mon & " Acting / Additional Bonus %'"
Set filteredItems = objFolder.Items.Restrict(strFilter)
If filteredItems.Count = 0 Then
Debug.Print "No emails found"
Found = False
Else
Found = True
' this loop displays the list of emails by subject in the debug console and saves the attachments to the specified folder
dim z as integer
z=0
For Each itm In filteredItems
z=z+1
Debug.Print itm.Subject
'### Insert code here to Open the attachments with .xlsx extensions, if any, in each of the emails found, save them as "[Mon] Acting / Additional Bonus (1 to n).xlsx"
Next
End If
'If the subject isn't found:
If Not Found Then
'NoResults.Show
Else
Debug.Print "Found " & filteredItems.Count & " items."
End If
End Sub
Try something like the following:
for each attach in itm.Attachments
if (attach.Type = olByValue) or (attach.Type = olEmbeddeditem) Then
attach.SaveAsFile "c:\temp\" & itm.FileName
End If
next

ms 2010 vb to move email to a different mailbox and subfolder

I am looking to move emails from a folder to the deleted folder of the below mailbox. I get a "compile error: variable not defined" message, where have I gone wrong?
Sub MoveToFolder(folderName)
mailboxNameString = "Mailbox - David Beach"
Dim olApp As New Outlook.Application
Dim olNameSpace As Outlook.NameSpace
Dim olCurrExplorer As Outlook.Explorer
Dim olCurrSelection As Outlook.Selection
Dim olDestFolder As Outlook.MAPIFolder
Dim olCurrMailItem As MailItem
Dim m As Integer
Set olNameSpace = olApp.GetNamespace("MAPI")
Set olCurrExplorer = olApp.ActiveExplorer
Set olCurrSelection = olCurrExplorer.Selection
Set olDestFolder = olNameSpace.Folders(mailboxNameString).Folders(folderName)
For m = 1 To olCurrSelection.Count
Set olCurrMailItem = olCurrSelection.Item(m)
Debug.Print "[" & Date & " " & Time & "] moving #" & m & _
": folder = " & folderName & _
"; subject = " & olCurrMailItem.Subject & "..."
olCurrMailItem.Move olDestFolder
Next m
End Sub
Sub Delete()
MoveToFolder ("Deleted Items")
End Sub
This line is for Outlook 2003. mailboxNameString = "Mailbox - David Beach"
Take a look at your 2010 mailbox and use that name.