I'm trying to search Outlook by email received date and time, for specific subject email and then save its attachment in designated folder.
It gets stuck where I search for email with specific subject.
Set foundEmails = searchFolder.Items.Restrict("[Subject] = 'KSA RDC - ECOM Inventory Report'")
Sub SearchAndDownloadAttachments()
' Declare variables for the Outlook application and folder
Dim outlookApp As Outlook.Application
Dim outlookNamespace As Namespace
Dim inboxFolder As MAPIFolder
Dim searchFolder As MAPIFolder
Dim foundEmails As Search
Dim email As Outlook.MailItem
Dim attach As Outlook.Attachment
' Set the Outlook application and namespace
Set outlookApp = New Outlook.Application
Set outlookNamespace = outlookApp.GetNamespace("MAPI")
' Set the inbox folder and search folder
Set inboxFolder = outlookNamespace.GetDefaultFolder(olFolderInbox)
Set searchFolder = inboxFolder.Folders("IT Reports")
' Search for emails with the specified subject
Set foundEmails = searchFolder.Items.Restrict("[Subject] = 'KSA RDC - ECOM Inventory Report'")
' Loop through the found emails
For Each email In foundEmails
' Declare variables for the email name and received time
Dim emailName As String
Dim receivedTime As Date
Dim attachmentName As String
' Set the email name and received time
emailName = email.SenderName
receivedTime = email.receivedTime
' Loop through the attachments of the email
For Each attach In email.Attachments
attachmentName = attach.Filename
' Copy the attachment to the specified folder
attach.SaveAsFile "C:\Attachments\" & attachmentName & "-" & emailName & " - " & Format(receivedTime, "yyyy-mm-dd hh-mm-ss")
Next
Next email
End Sub
Please, test the next adapted code. Take care to change the subject string, to be exactly as the one you try returning:
Sub SearchAndDownloadAttachments()
' Declare variables for the Outlook application and folder
Dim outlookApp As Outlook.Application, outlookNamespace As NameSpace
Dim inboxFolder As MAPIFolder, searchFolder As MAPIFolder
Dim foundEmails As Items, email As Outlook.MailItem
Dim attach As Outlook.Attachment
' Set the Outlook application and namespace
Set outlookApp = New Outlook.Application
Set outlookNamespace = outlookApp.GetNamespace("MAPI")
' Set the inbox folder and search folder
Set inboxFolder = outlookNamespace.GetDefaultFolder(olFolderInbox)
Set searchFolder = inboxFolder.Folders("IT Reports")
' Search for emails with the specified subject
Set foundEmails = searchFolder.Items.Restrict("[Subject] = 'KSA RDC - ECOM Inventory Report'") 'change here the exact spelled subject string!
' Loop through the found emails
For Each email In foundEmails
' Declare variables for the email name and received time
Dim emailName As String, receivedTime As Date, attachmentName As String
Dim ext As String, nameRoot As String 'new declarations
' Set the email name and received time
emailName = email.SenderName
receivedTime = email.receivedTime
' Loop through the attachments of the email
For Each attach In email.Attachments
attachmentName = attach.FileName
ext = Right(attachmentName, Len(attachmentName) - InStrRev(attachmentName, ".") + 1) 'extract extension
nameRoot = left(attachmentName, Len(attachmentName) - Len(ext)) 'the remained name (without extension)
' Copy the attachment to the specified folder
attach.SaveAsFile "C:\Attachments\" & nameRoot & "-" & emailName & " - " & _
Format(receivedTime, "yyyy-mm-dd hh-mm-ss") & ext
Next
Next email
End Sub
Your last error may be related to the fact that Outlook is not able to save a file without extension and Excel remains hanged on this Outlook attempt...
Please, send some feedback after testing the code.
Related
Message Body format:
> Hi All,
>
>
> Redwood.Harel.Harley.Miscare.Find failed. Below is the detailed report
>
> ************************************************************************************** Server Name : freedyishere1234
>
>
> Service Name : SantaIsRed
>
>
> Transaction Id : 32k23k23k-234jbk23b4k-32j4k23b-23231q
>
>
> Universal Id : 8979870
>
>
> Employee Id : 123123321
>
>
> Service Status : Failed
>
>
> Error Details : The family’s excitement over going to Disneyland was
> crazier than she anticipated. EmployeeId=123123321
>
>
> **************************************************************************************
>
> This is a system generated message. Do not reply to this message.
>
> Thank you, Cranberry Team
I want to write a VBA which runs everyday(or manually as well) at specific time and date (past, present,future). My script should extract EmployeeId and Error Details from the body and save it into an excel file which has to be maintained everyday.
Column A = EmployeeId
Column B = Error
of excel.
Everyday data should be seperated from last date by just 1 or 2 empty rows in excel.
My code:
Sub ExtractEmailData()
Dim olApp As Outlook.Application
Dim olMail As Outlook.MailItem
Dim olNS As Outlook.NameSpace
Dim olFolder As Outlook.MAPIFolder
Dim strFile As String
Dim objFSO As Object
Dim objTS As Object
Dim strText As String
Dim EmployeeID As String
Dim Error As String
Dim OlInbox As Outlook.MAPIFolder
'Set Outlook application object
Set olApp = New Outlook.Application
'Set Outlook namespace
Set olNS = olApp.GetNamespace("MAPI")
'olFolderI is Inbox folder
Set olFolderI = olNS.GetDefaultFolder(olFolderInbox)
'Get the parent folder of the Inbox folder
Dim olParentFolder As Outlook.MAPIFolder
Set olParentFolder = olFolderI.Parent
' Loop through all the subfolders of the parent folder
For Each subfolder In olParentFolder.Folders
'set olFolder as TARGET123
If subfolder.Name = "TARGET123" Then
Set olFolder = subfolder
End If
Next
'Path of the Windows desktop folder
DesktopPath = CreateObject("WScript.Shell").SpecialFolders("Desktop") & "\"
'Loop through emails in TARGET123 folder
For Each olMail In olFolder.Items
'Extract EmployeeID and Error from email body
EmployeeID = ExtractData(olMail.Body, "Employee Id:\s*(\d+)")
Error = ExtractData(olMail.Body, "Error Details:\s*(.+)")
'Create string to write to file
strText = EmployeeID + "," + Error + vbNewLine
'Set file name and location
strFile = DesktopPath + Format(Now(), "dd-MMM-yyyy") + ".csv"
'Check if file already exists
If Len(Dir(strFile)) = 0 Then
'Create new file and write headers
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTS = objFSO.CreateTextFile(strFile, True)
objTS.WriteLine "EmployeeID,Error"
objTS.Close
Else
'Open file and append data
Open strFile For Append As #1
Print #1, strText
Close #1
End If
Next olMail
'Clean up
Set objFSO = Nothing
Set objTS = Nothing
Set olNS = Nothing
Set olApp = Nothing
End Sub
'Function to extract data using regular expressions
Public Function ExtractData(strText As String, strPattern As String) As String
Dim objRegEx As Object
Set objRegEx = CreateObject("VBScript.RegExp")
objRegEx.Pattern = strPattern
objRegEx.Global = True
If objRegEx.Test(strText) Then
ExtractData = objRegEx.Execute(strText)(0).SubMatches(0)
Else
ExtractData = ""
End If
Set objRegEx = Nothing
End Function
'Application.OnTime TimeValue("20:00:00"), "ExtractEmailData"
'You can also specify a specific date and time for the macro to run using the Application.OnTime method, for example:
Public Sub ScheduleMacro()
Application.OnTime Now + TimeValue("00:00:10"), "ExtractEmailData"
End Sub
ScheduleMacro
End Sub
But this code just creates a new file everyday(which is also fine) and the columns created are also fine but there is not data being extracted from emails and populated into the excel file.
It seems the following code doesn't add the retrieved in Outlook data to the Excel file:
'Open file and append data
Open strFile For Append As #1
Print #1, strText
Close #1
Try to set a break point and go through each line of code under the debugger attached.
Also keep in mind that Outlook folders may contain different kind of items - emails, appointments, documents, notes and etc. So, it makes sense to make sure that you deal with mail items before accessing its properties. For example, not all properties may be available. In the code you iterate over items assuming they are all mail items:
Dim olMail As Outlook.MailItem
'Loop through emails in TARGET123 folder
For Each olMail In olFolder.Items
Instead, I'd suggest declaring the item as object and check the MessageClass before casting to the MailItem class to make sure you deal with a true mail item.
I am hoping to filter the mails in my 'sent items' folder based on the email address of my contact person, i.e. sent to but my attempts so far failed. I am trying to use the filter method in the example below.
Sub CommandButton2_Click()
Dim olApp As Object
Dim olNs As Object
Dim olFldr As Object
Dim olItems As Object
Dim emailStr As String
Dim filter As String
Set olApp = CreateObject("Outlook.Application")
Set olNs = olApp.GetNamespace("MAPI")
Set olFldr = olNs.GetDefaultFolder(olFolderSentMail)
Debug.Print "olFldr: " & olFldr
emailStr = "sombody#gmail.com" '(email address in Excel spreadsheet)
Debug.Print "emailStr: " & emailStr
Set olItems = olFldr.Items
`for the inbox I used SenderEmailAddress. Attempts with RecipientEmailAddress etc did not work. It would help if I knew how you can see which fields are there to search through, but I don't know how to access this information, nor can I find it on google.
filter = "[SenderEmailAddress] = '" & emailStr & "'"
Set olItems = olFldr.Items.Restrict(filter)
End sub
I figured out that the recipient Address is found here:
olSentFldr.Items.Item(1).Recipients.Item(1).Address
but this still won't work:
Debug.Print olSentFldr.Items.Item(1).Recipients.Item(1).Address filter
= (" Address = """ & emailStr & """")
Set olSentFldr2 = olSentFldr.Items.Restrict(filter)
Outlook Object Model won't let you create a subrestriction on message recipients or attachments.
You can use To/CC/BCC properties in a query, but they correspond to the PR_DISPLAY_TO/ PR_DISPLAY_CC / PR_DISPLAY_BCC MAPI properties and contain a ";" separated list of recipients and may or may not contain email addresses. Generally, they only contain display names.
Extended MAPI allows to create a subrestriction PR_MESSAGE_RECIPIENTS or PR_MESSAGE_ATTACHMENTS (create RES_SUBRESTRICTION SRestriction structure on PR_MESSAGE_RECIPIENTS and RES_OR child restriction on PR_DISPLAY_NAME, PR_EMAIL_ADDRESS, PR_SMTP_ADDRESS, etc. MAPI properties), but Extended MAPI requires C++ or Delphi.
If using Redemption (I am its author) is an option, it supports RDOFolder.Items.Find/Restrict queries on message recipients in the form of "Recipients = 'user#domain.demo'"
Good morning friends,
Please, I need your help, I have 2 problems:
1.- I wanted to be able to extract pdf files but an email from a specific contact (sender)
2.- I have several inboxes, how could I set another inbox, but not the one that comes by default - here I tried the following "Set Inbox = olNs.GetDefaultFolder (onothermail#gmail.com)" but it did not work for me
Thank you very much in advance
Option Explicit
Public Sub Example()
'// Declare your Variables
Dim olNs As Outlook.NameSpace
Dim Inbox As Outlook.MAPIFolder
Dim Items As Outlook.Items
Dim Item As Outlook.MailItem
Dim Atmt As Attachment
Dim Filter As String
Dim FilePath As String
Dim AtmtName As String
Dim i As Long
Dim objOwner As Outlook.Recipient
'// Set Inbox Reference
Set olNs = Application.GetNamespace("MAPI")
Set objOwner = olNs.CreateRecipient("secondMail#gmail.com")
Set Inbox = olNs.GetSharedDefaultFolder(objOwner)
FilePath = "C:\Users\Unity\Desktop\adjuntos\"
Filter = "[Unread] = True"
Set Items = Inbox.Items.Restrict(Filter)
'// Loop through backwards
For i = Items.Count To 1 Step -1
Set Item = Items(i)
DoEvents
If Item.Class = olMail Then
If Item.SenderEmailAddress = "senderx#gmail.com" Then
For Each Atmt In Item.Attachments
AtmtName = FilePath & Atmt.FileName
If ((InStr(Atmt.DisplayName, ".jpg") Or InStr(Atmt.DisplayName, ".zip") Or InStr(Atmt.DisplayName, ".PDF") Or InStr(Atmt.DisplayName, ".pdf"))) Then
Atmt.SaveAsFile FilePath & "\" & Atmt.DisplayName
End If
Item.UnRead = False
Next
End If
End If
Next
Set Inbox = Nothing
Set Items = Nothing
Set Item = Nothing
Set Atmt = Nothing
Set olNs = Nothing
End Sub
It seems additionally you need to check the sender's email address of the item. The MailItem.SenderEmailAddress property returns a string that represents the email address of the sender of the Outlook item.
Sub SetFlagIcon()
Dim mpfInbox As Outlook.Folder
Dim obj As Outlook.MailItem
Dim i As Integer
Set mpfInbox = Application.GetNamespace("MAPI").GetDefaultFolder(olFolderInbox).Folders("Test")
' Loop all items in the Inbox\Test Folder
For i = 1 To mpfInbox.Items.Count
If mpfInbox.Items(i).Class = olMail Then
Set obj = mpfInbox.Items.Item(i)
If obj.SenderEmailAddress = "someone#example.com" Then
'Set the yellow flag icon
obj.FlagIcon = olYellowFlagIcon
obj.Save
End If
End If
Next
End Sub
However, iterating over all items in the folder is not really a good idea. 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
Also you may use the AdvancedSearch method of the Application class helpful. See Advanced search in Outlook programmatically: C#, VB.NET for more information.
Use the Store.GetDefaultFolder method instead. It returns a Folder object that represents the default folder in the store and that is of the type specified by the FolderType argument. This method is similar to the GetDefaultFolder method of the NameSpace object. The difference is that this method gets the default folder on the delivery store that is associated with the account, whereas NameSpace.GetDefaultFolder returns the default folder on the default store for the current profile.
I have exported all subject of the emails from the main folder to excel spreadsheet in the first module of my project.
For the second module, or code. I would like to move the emails i extracted from the main folder to a sub-folder based on searching the email subject. I detailed the subfolder name, on a separate column of the spreadsheet.
Column 3 - The subject email
Column 8 - The subfolder name
Each email subject in the main folder is unique, So i used the "Find Method" then move the email to the subfolder. Since the list is dynamic every time i make an extract, i decided to use arrays, so that it can iterate when the list of email changes.
Example, the code has to place email in the main folder with subject "A" to folder "1".
Email subject Folder name
(Column 3) (Column 8)
A 1
B 1
C 2
D 2
E 1
Sub MovingEmails_Invoices()
'Declare your Variables
Dim i As Object
Dim items As Outlook.items
Dim subfolder As Outlook.Folder 'this will be the folder you want to move the Mail to
'Set Outlook Inbox Reference
Set OP = New Outlook.Application
Set NS = OP.GetNamespace("MAPI")
'To loop through subfolder and its folders
Set rootfol = NS.Folders("SYNTHES-JNJCZ-GBS.DE.AT.CH#ITS.JNJ.com")
Set Folder = rootfol.Folders("Austria")
'The list for invoice numbers and folders is dynamic
'Each subject being searched is different
Dim Listmails() As Variant
Dim Rowcount As Variant
Dim Mailsubject As Variant
Dim FolderName As Variant
Dim MS As Variant
'Establish the array based on the mailbox extract
Sheets("files").Activate
Listmails = Range("A2").CurrentRegion
'Ititerate through the array which is dynamic (One-dimensional)
For Rowcount = LBound(Listmails) To UBound(Listmails)
'3rd row for email subject
Mailsubject = Application.WorksheetFunction.Index(Listmails, Rowcount, 3)
MS = "[subject] = '" & Mailsubject & "'"
'Find the email based on the array for email subject
Set i = items
Set i = Folder.items.Find(MS)
If i.Class = olMail Then
'8th row for folder name
FolderName = Application.WorksheetFunction.Index(Listmails, Rowcount, 8)
Set subfolder = rootfol.Folders(FolderName)
'If email is found then mark it as read
item.UnRead = False
'Move it to the subfolder based on the array for folder name
i.Move subfolder
End If
Next Rowcount
End Sub
I had an error to conduct the below code, but i am not sure why
If i.Class = olMail Then
I am adding an improved code for the iteration part alone. i have error for
Set items = items.Restrict(MS)
'Ititerate through the array which is dynamic (One-dimensional)
For Rowcount = LBound(Listmails) To UBound(Listmails)
'3rd row for email subject 'used DASL Filter
Mailsubject = Application.WorksheetFunction.Index(Listmails, Rowcount, 3)
MS = "urn:schemas:mailheader:subject LIKE \'%" & Mailsubject & "%\'"
'Find the email based on the array for email subject
Set myitems = Folder.items
Set myrestrictitem = myitems.Restrict(MS)
For Each i In myrestrictitem
If TypeOf i Is Mailitem Then
'8th row for folder name
FolderName = Application.WorksheetFunction.Index(Listmails, Rowcount, 8)
Set subfolder = rootfol.Folders(FolderName)
'If email found then mark it as read
i.UnRead = False
'Move it to the subfolder based on the array for folder name
i.Move subfolder
Else
End If
Next
Next Rowcount
End Sub
I'm just looking at part of your code, but there's at least two big mistakes I spotted:
Why are you setting i twice? Also what is items?
Set i = items
Set i = Folder.items.Find(MS)
1: Do you perhaps want to check the TypeOf i?
If i.Class = olMail Then
2: What is item?
item.UnRead = False
Remove the line
Set i = items
Replace the line
If i.Class = olMail then
with
If TypeOf i Is MailItem Then
And replace item with i in the line item.UnRead = False
I'd suggest checking the subject line as a substring, for example:
dim filter as string = "urn:schemas:mailheader:subject LIKE \'%"+ wordInSubject +"%\'"
Also, you must use the FindNext in addition to the Find one or just the Restrict method:
Sub MovingEmails_Invoices()
'Declare your Variables
Dim i As Object
Dim items As Outlook.items
Dim subfolder As Outlook.Folder 'this will be the folder you want to move the Mail to
'Set Outlook Inbox Reference
Set OP = New Outlook.Application
Set NS = OP.GetNamespace("MAPI")
'To loop through subfolder and its folders
Set rootfol = NS.Folders("SYNTHES-JNJCZ-GBS.DE.AT.CH#ITS.JNJ.com")
Set Folder = rootfol.Folders("Austria")
'The list for invoice numbers and folders is dynamic
'Each subject being searched is different
Dim Listmails() As Variant
Dim Rowcount As Variant
Dim Mailsubject As Variant
Dim FolderName As Variant
Dim MS As Variant
'Establish the array based on the mailbox extract
Sheets("files").Activate
Listmails = Range("A2").CurrentRegion
'Ititerate through the array which is dynamic (One-dimensional)
For Rowcount = LBound(Listmails) To UBound(Listmails)
'3rd row for email subject
Mailsubject = Application.WorksheetFunction.Index(Listmails, Rowcount, 3)
MS = "urn:schemas:mailheader:subject LIKE \'%"& Mailsubject &"%\'"
'Find the email based on the array for email subject
Set items = Folder.Items
Set items = items.Restrict(MS)
i = resultItems.GetFirst()
While Not IsNothing(i)
If i.Class = olMail Then
'8th row for folder name
FolderName = Application.WorksheetFunction.Index(Listmails, Rowcount, 8)
Set subfolder = rootfol.Folders(FolderName)
'If email is found then mark it as read
i.UnRead = False
'Move it to the subfolder based on the array for folder name
i.Move subfolder
i = resultItems.GetNext()
End While
End If
Next Rowcount
End Sub
You can find the sample code and description 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
I am trying to export all emails in specific folder "Not actioned DO" to a CSV file then move these emails to another folder "Actioned DO".
I edited code I found.
Only the last email is saved on the csv file.
I need all emails to be in the same CSV file.
Sub PseudoArchive()
Dim objNamespace As Outlook.NameSpace
Dim sourceFolder As Outlook.MAPIFolder
Dim destinationFolder As Outlook.MAPIFolder
Dim Items As Outlook.Items
Dim Item As Object
Dim msg As String
Dim i As Long
Set objNamespace = GetNamespace("MAPI")
Set sourceFolder = objNamespace.Folders("msroumi#hotmail.com").Folders("Inbox").Folders("Not Actioned DO")
Set destinationFolder = objNamespace.Folders("msroumi#hotmail.com").Folders("Inbox").Folders("Actioned DO")
Set Items = sourceFolder.Items
'Move emails in sourceFolder to destinationFolder
msg = Items.Count & " Items in " & sourceFolder.Name & ", Move?"
If MsgBox(msg, vbYesNo) = vbYes Then
For i = Items.Count To 1 Step -1
Set Item = Items.Item(i)
DoEvents
Item.Move destinationFolder
Item.SaveAs "D:\Excel\Learning Excel VBA\Outlook VBA\MyEmail.txt", olTXT
Next
End If
End Sub
Firstly, you are sving the item after it's already been moved (and deleted). Call SaveAs before calling Move. Or use the returned value of the Move function to reset the item: set Item = Item.Move destinationFolder.
Most importantly however, is that you are saving all message with the same file name, continuously overwriting the old files, thus only the last file survives. Make the file name unique - you can ether use the message Subject property for that (make sure you remove all invalid chars, such as ":") or you can do something as simple as adding a counter to te hfile name:
Item.SaveAs "D:\Excel\Learning Excel VBA\Outlook VBA\MyEmail" & i & ".txt", olTXT