VBA to loop through email attachments and save based on given criteria - excel

This is a follow up from a previous question (VBA to save attachments (based on defined criteria) from an email with multiple accounts)
Scenario: I have a code that loops through all e-mails in a certain outlook account, and saves the attachments to a selected folder. Previously, my problem was selecting which folder (and account) from where to extract the attachments (this was solved with a suggestion from the previous question).
Issue 1: The code is presenting a "Type Mismatch" error at the line:
Set olMailItem = olFolder.Items(i)
Issue 2: As stated in the question title, my main objective is to loop through all the attachments and save only those that have a given criteria (excel file, with one sheet name "ASK" and one named "BID"). More than a simple If to account for these criteria, I have to either download all files to "temp folder", to the selection and put the final resulting files in the output folder, or download everything to the final folder and delete the files that do not meet the criteria.
Problem: I can't seem to find the way to do either of those operations.
Question: How would one do that? And which of those two would be more efficient?
Code:
Sub email()
Application.ScreenUpdating = False
Dim olApp As New Outlook.Application
Dim olNameSpace As Object
Dim olMailItem As Outlook.MailItem
Dim olFolder As Object
Dim olFolderName As String
Dim olAtt As Outlook.Attachments
Dim strName As String
Dim sPath As String
Dim i As Long
Dim j As Integer
Dim olSubject As String
Dim olSender As String
Dim sh As Worksheet
Dim LastRow As Integer
'delete content except from row 1
ThisWorkbook.Worksheets("FileNames").Rows(2 & ":" & ThisWorkbook.Worksheets("FileNames").Rows.count).Delete
'set foldername and subject
olFolderName = ThisWorkbook.Worksheets("Control").Range("D10")
'olSubject = ThisWorkbook.Worksheets("Control").Range("D16")
olSender = ThisWorkbook.Worksheets("Control").Range("D16")
sPath = Application.FileDialog(msoFileDialogFolderPicker).Show
sPathstr = Application.FileDialog(msoFileDialogFolderPicker).SelectedItems(1)
Set olNameSpace = olApp.GetNamespace("MAPI")
'check if folder is subfolder or not and choose olFolder accordingly
'Set olFolder = olNameSpace.GetDefaultFolder(olFolderInbox).Folders(olFolderName)
Set olFolder = olNameSpace.Folders("email#email.com").Folders("Inbox")
If (olFolder = "") Then
Set olFolder = olNameSpace.Folders("email#email.com").Folders("Inbox")
End If
'loop through mails
h = 2
For i = 1 To olFolder.Items.count
Set olMailItem = olFolder.Items(i)
'check if the search name is in the email subject
'If (InStr(1, olMailItem.Subject, olSubject, vbTextCompare) <> 0) Then
If (InStr(1, olMailItem.Sender, olSender, vbTextCompare) <> 0) Then
With olMailItem
strName = .Attachments.Item(j).DisplayName
'check if file already exists
If Not Dir(sPathstr & "\" & strName) = "" Then
.Attachments(j).SaveAsFile sPathstr & "\" & "(1)" & strName
ThisWorkbook.Worksheets("FileNames").Range("A" & h) = "(1)" & strName
Else
.Attachments(j).SaveAsFile sPathstr & "\" & strName
ThisWorkbook.Worksheets("FileNames").Range("A" & h) = strName
End If
h = h + 1
Next
End With
End If
Next
Application.ScreenUpdating = True
MsgBox "Download complete!", vbInformation + vbOKOnly, "Done"
End Sub

Issue 1 :
You probably have so meeting invites or something other than a regular mail in your folder.
Check the Class property of the Item to see if it's olMail
Issue 2 :
I'll go with error handling, here :
Save in temp folder with the appropriate name
Open the file
Try to get to the sheets
If there is an error, just close the file
If there is no error, save the file in destination folder
Full code :
Sub email_DGMS89()
Application.ScreenUpdating = False
Dim olApp As New Outlook.Application
Dim olNameSpace As Object
Dim olMailItem As Outlook.MailItem
Dim olFolder As Object
Dim olFolderName As String
Dim olAtt As Outlook.Attachments
Dim strName As String
Dim sPath As String
Dim i As Long
Dim j As Integer
Dim olSubject As String
Dim olSender As String
Dim sh As Worksheet
Dim LastRow As Integer
Dim TempFolder As String: TempFolder = VBA.Environ$("TEMP")
Dim wB As Excel.Workbook
'delete content except from row 1
ThisWorkbook.Worksheets("FileNames").Rows(2 & ":" & ThisWorkbook.Worksheets("FileNames").Rows.Count).Delete
'set foldername and subject
olFolderName = ThisWorkbook.Worksheets("Control").Range("D10")
'olSubject = ThisWorkbook.Worksheets("Control").Range("D16")
olSender = ThisWorkbook.Worksheets("Control").Range("D16")
sPath = Application.FileDialog(msoFileDialogFolderPicker).Show
sPathstr = Application.FileDialog(msoFileDialogFolderPicker).SelectedItems(1)
Set olNameSpace = olApp.GetNamespace("MAPI")
'check if folder is subfolder or not and choose olFolder accordingly
'Set olFolder = olNameSpace.GetDefaultFolder(olFolderInbox).Folders(olFolderName)
Set olFolder = olNameSpace.Folders("email#email.com").Folders("Inbox")
If (olFolder = "") Then
Set olFolder = olNameSpace.Folders("email#email.com").Folders("Inbox")
End If
'loop through mails
h = 2
For i = 1 To olFolder.items.Count
'''Const olMail = 43 (&H2B)
If olFolder.items(i).Class <> olMail Then
Else
Set olMailItem = olFolder.items(i)
'check if the search name is in the email subject
'If (InStr(1, olMailItem.Subject, olSubject, vbTextCompare) <> 0) Then
If (InStr(1, olMailItem.Sender, olSender, vbTextCompare) <> 0) Then
With olMailItem
For j = 1 To .Attachments.Count
strName = .Attachments.Item(j).DisplayName
'check if file already exists
If Not Dir(sPathstr & "\" & strName) = vbNullString Then
strName = "(1)" & strName
Else
End If
'''Save in temp
.Attachments(j).SaveAsFile TempFolder & "\" & strName
ThisWorkbook.Worksheets("FileNames").Range("A" & h) = strName
'''Open file as read only
Set wB = workbooks.Open(TempFolder & "\" & strName, True)
DoEvents
'''Start error handling
On Error Resume Next
Set sh = wB.sheets("ASK")
Set sh = wB.sheets("BID")
If Err.Number <> 0 Then
'''Error = At least one sheet is not detected
Else
'''No error = both sheets found
.Attachments(j).SaveAsFile sPathstr & "\" & strName
End If
Err.Clear
Set sh = Nothing
wB.Close
On Error GoTo 0
h = h + 1
Next j
End With
End If
End If
Next i
Application.ScreenUpdating = True
MsgBox "Download complete!", vbInformation + vbOKOnly, "Done"
End Sub

Related

Save Outlook attachment using a cell value as the file name

I'm trying to save the Outlook attachment from a particular sub folder to a local path.
I'm able to save the file as is to the local path.
The requirement is to save the xl attachment using a cell value of ThisWorkbook as the file name.
Sub ManualPunchAttachmentsExtract()
Dim OlFolder As Outlook.MAPIFolder
Dim OlMail As Object
Dim OlApp As Outlook.Application
Dim OlItems As Outlook.Items
Dim Get_namespace As Outlook.Namespace
Dim strFolder As String
Dim i As Integer
ThisWorkbook.Activate
Sheets("MP File Save").Activate
Range("H3").Activate
Set OlApp = GetObject(, "Outlook.Application")
If err.Number = 429 Then
Set OlApp = CreateObject("Outlook.Application")
End If
strFolder = InputBox("Please Enter the Folder Path alongwith ' \ ' at the end", Path)
'Set Get_namespace = OlApp.GetNamespace("MAPI")
Set OlFolder = OlApp.GetNamespace("MAPI").Folders("shaikajaz.k#flex.com").Folders("Archive").Folders("Juarez").Folders("Manual Punch")
Set OlItems = OlFolder.Items
'.Restrict("[Unread]=true")
For Each OlMail In OlItems
If OlMail.UnRead = False Then
Else
ThisWorkbook.Activate
Sheets("MP File Save").Activate
ActiveCell.Value = OlMail.Subject
ActiveCell.Offset(0, 1).Value = OlMail.ReceivedTime
If OlMail.attachments.Count > 0 Then
For i = 1 To OlMail.attachments.Count
OlMail.attachments.Item(i).SaveAsFile strFolder & "\" & OlMail.attachments.Item(i).FileName
OlMail.UnRead = False
ThisWorkbook.Activate
ActiveCell.Offset(1, 0).Select
Next i
Else
End If
End If
Next
MsgBox ("Done")
End Sub
First of all, iterating over all items in an Outlook folder is not realy a good idea. Use the Find/FindNext or Restrict methods of the Items class instead. So, instead of the following code:
For Each OlMail In OlItems
If OlMail.UnRead = False Then
Use this:
Private Sub FindAllUnreadEmails(folder As Outlook.MAPIFolder)
Dim searchCriteria As String = "[UnRead] = true"
Dim counter As Integer = 0
Dim mail As Outlook._MailItem = Nothing
Dim folderItems As Outlook.Items = Nothing
Dim resultItem As Object = Nothing
If (folder.UnReadItemCount > 0) Then
folderItems = folder.Items
resultItem = folderItems.Find(searchCriteria)
While Not IsNothing(resultItem)
If (TypeOf (resultItem) Is Outlook._MailItem) Then
counter += 1
mail = resultItem
Debug.Print("#" + counter.ToString() + _
" - Subject: " + mail.Subject)
End If
resultItem = folderItems.FindNext()
End While
Else
Debug.Print("There is no match in the " + _
folder.Name + " folder.")
End If
End Sub
Note, attached files can have the same file name. So, to uniquelly identify files I'd suggest introducing any IDs in the file name when attachments are saved to the disk.
Finally, to save the attached file with a workbook's content name you need to pass a cell value to the SaveAsFile method:
OlMail.attachments.Item(i).SaveAsFile strFolder & "\" & yourWorksheet.Range("B2").Value

How to check if data is already in the worksheet when exporting email data to workbook?

I export email data from a folder that has subfolders, from a shared mailbox.
I am trying to loop through the existing values in column E, comparing the string value of the email.EntryID field to the string value of the cell, to skip the emails (email fields) that were already exported.
Option Explicit
Sub inbox_working()
Dim xlApp As Excel.Application
Dim xlWB As Excel.Workbook
Dim Sht As Excel.Worksheet
Dim olApp As Outlook.Application
Set olApp = New Outlook.Application
Dim olNs As Outlook.Namespace
Set olNs = olApp.GetNamespace("MAPI")
Dim olRecip As Outlook.Recipient
Set olRecip = olNs.CreateRecipient("exampleEmail#email.com") ' Update email
Dim Inbox As Outlook.MAPIFolder
Set Inbox = olNs.GetSharedDefaultFolder(olRecip, olFolderInbox)
Set xlApp = CreateObject("Excel.Application")
xlApp.Visible = True
Set xlWB = xlApp.Workbooks.Open("C:\Desktop\mails.xlsm")
Set Sht = xlWB.Sheets("inbox_email_data")
With Sht
.Range("A3").Value = "Sender"
.Range("B3").Value = "Received_Date_Time"
.Range("C3").Value = "Converation Topic"
.Range("D3").Value = "Category"
.Range("E3").Value = "message_ID"
.Range("F3").Value = "conversation_ID"
.Range("G3").Value = "Folder Name"
End With
' // Process Current Folder
LoopFolders Inbox, Sht
End Sub
Private Sub LoopFolders( _
ByVal CurrentFolder As Outlook.MAPIFolder, _
ByVal Sht As Worksheet _ )
Dim Items As Outlook.Items
Set Items = CurrentFolder.Items
Dim i As Long
Dim last_row As Long
Dim Item As Object ' Outlook.MailItem
Dim cell As Range
With Sht
last_row = Sht.Range("A" & .Rows.Count).End(xlUp).Row + 1
For i = Items.Count To 1 Step -1 ' run loop
Set Item = Items(i)
'DoEvents
If TypeOf Item Is Outlook.MailItem Then
For Each cell In .Range("ID_inbox").Cells '----> the range here =$E$4:$Erowatendofworksheet
If CStr(Item.entryID) = CStr(cell.Value) Then
' do nothing
Else
.Range("A" & last_row).Value = Item.SenderName '----> at this line it breaks with 1004 error
.Range("B" & last_row).Value = Item.ReceivedTime
.Range("C" & last_row).Value = Item.ConversationTopic
.Range("D" & last_row).Value = Item.categories
.Range("E" & last_row).Value = Item.entryID
.Range("F" & last_row).Value = Item.ConversationID
.Range("G" & last_row).Value = CurrentFolder.Name
End If
Next
Else
' do nothing
End If
Next
last_row = last_row + 1
' // Recurse through subfolders
Dim folder As Outlook.MAPIFolder
If CurrentFolder.Folders.Count > 0 Then
For Each folder In CurrentFolder.Folders
LoopFolders folder, Sht
Next
End If
End With
' // Cleanup
Set folder = Nothing
Set Item = Nothing
Set Items = Nothing
End Sub
The code writes the data (fields) of the first email and then gives the error at that line.
I gather, it fails to 'do nothing if the string values match.
The cells in the sheet are unlocked (Ctrl+A->Right click->Permissions->Locked field is unticked).
Later edit:
Using the below, exports every time, all email items from all folders and subfolders of the Inbox folder.
Using event the lightest filering (fx. Item.ReceivedTime > a specific date) or other (as the one mentioned in the answer), renders the Outlook frozen.
Option Explicit
Sub all_email()
Dim xlApp As Excel.Application
Dim xlWB As Excel.Workbook
Dim Sht As Excel.Worksheet
Dim olApp As Outlook.Application
Set olApp = New Outlook.Application
Dim olNs As Outlook.Namespace
Set olNs = olApp.GetNamespace("MAPI")
Dim olRecip As Outlook.Recipient
Set olRecip = olNs.CreateRecipient("email#email.com") ' Update email
Dim Inbox As Outlook.MAPIFolder
Set Inbox = olNs.GetSharedDefaultFolder(olRecip, olFolderInbox)
Set xlApp = CreateObject("Excel.Application")
xlApp.Visible = True
Set xlWB = xlApp.Workbooks.Open("C:\Desktop\mails.xlsm")
Set Sht = Sheets("email_data")
With Sht
.Range("A3").Value = "Sender"
.Range("B3").Value = "Date_Time"
.Range("C3").Value = "Conversation_Topic"
.Range("D3").Value = "Category"
.Range("E3").Value = "Entry_ID"
.Range("F3").Value = "Conversation_ID"
.Range("G3").Value = "Mailbox"
End With
' // Process Current Folder
LoopFolders Inbox, Sht
End Sub
Sub LoopFolders( _
ByVal CurrentFolder As Outlook.MAPIFolder, _
ByVal Sht As Worksheet _
)
Dim Items As Outlook.Items
Set Items = CurrentFolder.Items
Dim i As Long
Dim last_row As Long
Dim Item As Object ' Outlook.MailItem
With Sht
last_row = Sht.Range("A" & .Rows.Count).End(xlUp).Row + 1
For i = Items.Count To 1 Step -1 ' run loop
Set Item = Items(i)
DoEvents
If TypeOf Item Is Outlook.MailItem Then
Debug.Print Item
.Range("A" & last_row).Value = Item.SenderName
.Range("B" & last_row).Value = Item.ReceivedTime
.Range("C" & last_row).Value = Item.ConversationTopic
.Range("D" & last_row).Value = Item.categories
.Range("E" & last_row).Value = Item.entryID
.Range("F" & last_row).Value = Item.ConversationID
.Range("G" & last_row).Value = CurrentFolder.Name
Else
End If
last_row = last_row + 1
Next
' // Recurse through subfolders
Dim folder As Outlook.MAPIFolder
If CurrentFolder.Folders.Count > 0 Then
For Each folder In CurrentFolder.Folders
LoopFolders folder, Sht
Next
End If
End With
' // Cleanup
Set folder = Nothing
Set Item = Nothing
Set Items = Nothing
End Sub
Later edit 2:
After using #niton's comments and partial solution, as it stands now, only the items from subfolders of the Inbox folder are extracted. When the script encounters a subfolder of a subfolder (i.e. Inbox->Subfolder->Subfolder) it stops.
How would I iterate through subfolders of each of the subfolder in the Inbox?
I tried:
// Recurse through subfolders
Dim folder As Outlook.MAPIFolder
Dim subfolder As Outlook.folder
If CurrentFolder.Folders.Count > 0 Then
For Each folder In CurrentFolder.Folders
LoopFolders folder, Sht
If folder.Folders.Count > 0 Then
For Each subfolder In folder.Folders
LoopFolders subfolder, Sht
Next
End If
Next
End If
But with no awail.
Also, how would I be able to extract the mail items data from the Sent folder?
Thank you.
Given the chosen method there has to be a lot more repetition. This could lead to a long run time.
If .Range("ID_inbox").Cells is the entire worksheet then limit the number of rows
Dim bFound As Boolean
Dim starting_last_row As Long
With Sht
last_row = Sht.Range("A" & .Rows.Count).End(xlUp).Row + 1
starting_last_row = Sht.Range("A" & .Rows.Count).End(xlUp).Row
For i = Items.Count To 1 Step -1 ' run loop
Set Item = Items(i)
bFound = False
'DoEvents
If TypeOf Item Is Outlook.MailItem Then
'For Each cell In .Range("ID_inbox").Cells '----> the range here =$E$4:$Erowatendofworksheet
For Each cell In .Range("E1:E" & starting_last_row)
If CStr(Item.entryID) = CStr(cell.Value) Then
bFound = True
Exit For
End If
Next
If bFound = False Then
.Range("A" & last_row).Value = Item.SenderName
.Range("B" & last_row).Value = Item.ReceivedTime
.Range("C" & last_row).Value = Item.ConversationTopic
.Range("D" & last_row).Value = Item.categories
.Range("E" & last_row).Value = Item.entryID
.Range("F" & last_row).Value = Item.ConversationID
.Range("G" & last_row).Value = CurrentFolder.Name
last_row = last_row + 1
End If
End If
Next
' // Recurse through subfolders
When code is in Excel some email properties may not be accessible if so move code to Outlook.

Update file names when the file names contain specific string referenced from an Excel table

I have created a fully functional outlook macro, that downloads Outlook attachments to OneDrive specified folder.
So the macro would update the file name with the email domain and month/year
e.g.
from original attachment name "Invoice_GBR_Z-GRX_2019_07.pdf"
it becomes "comfone.com_08-2019___Invoice_GBR_Z-GRX_2019_07.pdf" after executing the macro.
However, I would like the macro to also have the ability to compare against a static Excel table called Table.xls on my desktop (2 columns where column A contain the email domain name, and column B containing its respective company code), wherein if the Excel cell contains "comfone.com", then its corresponding company code say 0001 would then be appended to the file name
So the file name gets updated to
"0001_comfone.com_08-2019___Invoice_GBR_Z-GRX_2019_07.pdf"
I'm struggling quite a fair bit not knowing how to reference to an Excel table from my Outlook vba.
Public Sub SaveAttachments()
Dim objOL As Outlook.Application
Dim objMsg As Outlook.MailItem 'Object
Dim objAttachments As Outlook.Attachments
Dim objSelection As Outlook.Selection
Dim i As Long
Dim lngCount As Long
Dim strFile As String
Dim strFolderpath As String
Dim strDeletedFiles As String
Dim saveName As String
Dim userName As String
Dim sndrEmailAdd As String
Dim sndrEmailRight As String
Dim sndrEmailPreDot As String
' Get the path to your OneDrive folder.
userName = CreateObject("WScript.Network").userName
Debug.Print userName
'strFolderpath = "C:\Users\" & VBA.Environ$("USERNAME") & "\OneDrive - SAP
SE"
strFolderpath = "C:\Users\" & userName & "\OneDrive - SAP SE"
On Error Resume Next
' Instantiate an Outlook Application object.
Set objOL = CreateObject("Outlook.Application")
' Get the collection of selected objects.
Set objSelection = objOL.ActiveExplorer.Selection
' Set the Test folder, change "Test" to any folder name in your OneDrive
strFolderpath = strFolderpath & "\Downloaded Invoices\"
' Check each selected item for attachments. If attachments exist,
' save them to the strFolderPath folder and strip them from the item.
For Each objMsg In objSelection
' This code only strips attachments from mail items.
' If objMsg.class=olMail Then
' Get the Attachments collection of the item.
Set objAttachments = objMsg.Attachments
lngCount = objAttachments.Count
strDeletedFiles = ""
If lngCount > 0 Then
' We need to use a count down loop for removing items
' from a collection. Otherwise, the loop counter gets
' confused and only every other item is removed.
For i = lngCount To 1 Step -1
'Extract text, after # and before dot, from the email address.
sndrEmailAdd = objMsg.SenderEmailAddress
Debug.Print sndrEmailAdd
'Debug.Print " position of # sign: " & InStr(sndrEmailAdd, "#")
'Debug.Print " number of characters right of # sign: " &
Len(sndrEmailAdd) - InStr(sndrEmailAdd, "#")
'sndrEmailRight = Right(sndrEmailAdd, Len(sndrEmailAdd) -
InStr(sndrEmailAdd, "#"))
sndrEmailRight = Right(sndrEmailAdd, Len(sndrEmailAdd) -
InStr(sndrEmailAdd, "#"))
Debug.Print " text after # sign: " & sndrEmailRight
Debug.Print " position of the (first) . period in the remaining text:
" & InStr(sndrEmailRight, ".")
'sndrEmailPreDot = Left(sndrEmailRight, InStr(sndrEmailRight, ".") -
1)
' Save attachment before deleting from item.
' Get the file name.
strFile = sndrEmailRight & "_" & Format(DateAdd("m", -1,
objMsg.ReceivedTime), "mm-yyyy") & "___" &
objAttachments.item(i).FileName
' Combine with the path to the Temp folder.
saveName = strFolderpath & strFile
' Save the attachment as a file.
objAttachments.item(i).SaveAsFile saveName
' Delete the attachment.
'objAttachments.item(i).Delete
Next i
objMsg.Save
End If
Next
ExitSub:
Set objAttachments = Nothing
Set objMsg = Nothing
Set objSelection = Nothing
Set objOL = Nothing
End Sub
See example on how to call Excel from Outlook
https://stackoverflow.com/a/41801050/4539709
I have updated your code, make sure to Reference to Microsoft Excel xx.x Object Library and update your one-drive folder path
Your code example
Option Explicit
Public Sub SaveAttachments()
Dim Atmts As Outlook.Attachments
Dim i As Long
Dim lngCount As Long
Dim strFile As String
Dim strDeletedFiles As String
Dim saveName As String
Dim userName As String
Dim sndrEmailAdd As String
Dim sndrEmailRight As String
Dim sndrEmailPreDot As String
Dim strFolderpath As String
strFolderpath = "C:\Temp\"
' Get the collection of selected objects.
Dim objSelection As Outlook.Selection
Set objSelection = Application.ActiveExplorer.Selection
Dim xlApp As Excel.Application
Set xlApp = New Excel.Application
Dim Book As Workbook
Set Book = xlApp.Workbooks.Open("C:\Temp\Book1.xlsx")
Dim xlStarted As Boolean
xlStarted = True
Dim Sht As Excel.Worksheet
Set Sht = Book.Sheets("Sheet1")
Dim Rng As Range
' Check each selected item for attachments. If attachments exist,
' save them to the strFolderPath folder and strip them from the item.
Dim objMsg As Outlook.MailItem 'Object
For Each objMsg In objSelection
' This code only strips attachments from mail items.
' If objMsg.class=olMail Then
' Get the Attachments collection of the item.
Set Atmts = objMsg.Attachments
lngCount = Atmts.Count
Debug.Print lngCount
strDeletedFiles = ""
If lngCount > 0 Then
' We need to use a count down loop for removing items
' from a collection. Otherwise, the loop counter gets
' confused and only every other item is removed.
For i = lngCount To 1 Step -1
'Extract text, after # and before dot, from the email address.
sndrEmailAdd = objMsg.SenderEmailAddress
Debug.Print sndrEmailAdd
sndrEmailRight = Right(sndrEmailAdd, Len( _
sndrEmailAdd) - InStr( _
sndrEmailAdd, "#"))
Debug.Print sndrEmailRight
sndrEmailPreDot = Left(sndrEmailRight, _
InStr(sndrEmailRight, ".") - 1)
Debug.Print sndrEmailPreDot
For Each Rng In Sht.Range("A1", Sht.Range("A100").End(xlUp))
If (Rng.Value) = sndrEmailRight Then
sndrEmailPreDot = Rng.Offset(0, 1).Value & "_" & sndrEmailPreDot
Debug.Print sndrEmailPreDot
End If
Next
' Save attachment before deleting from item.
' Get the file name.
strFile = sndrEmailPreDot & "_" & _
Format(DateAdd("m", -1, objMsg.ReceivedTime _
), "mm-yyyy") & "___" & Atmts.Item(i).FileName
Debug.Print strFile
' Combine with the path to the Temp folder.
saveName = strFolderpath & strFile
Debug.Print saveName
' Save the attachment as a file.
Atmts.Item(i).SaveAsFile saveName
' Delete the attachment.
'Atmts.item(i).Delete
Next i
objMsg.Save
End If
Next
' Close & SaveChanges
Book.Close SaveChanges:=True
If xlStarted Then
xlApp.Quit
End If
Set xlApp = Nothing
Set Book = Nothing
Set Sht = Nothing
Set Rng = Nothing
Set Atmts = Nothing
Set objMsg = Nothing
Set objSelection = Nothing
End Sub

export email from outlook

Could you advise please how to export emails from excel files?
I have an excel files with column called emails - this is a list of emails.
How can VBA script check every email from excel file in outlook and export emails with subject, data, sender from these excel file to new excel file or new sheet in current excel.
I have this script:
Const MACRO_NAME = "Export Messages to Excel (Rev 4)"
Sub ExportMessagesToExcelbyDate()
Dim olkLst As Object, _
olkMsg As Object, _
excApp As Object, _
excWkb As Object, _
excWks As Object, _
intRow As Integer, _
intVersion As Integer, _
strFilename As String, _
strDateRange As String, _
arrTemp As Variant, _
datStart As Date, _
datEnd As Date
strFilename = InputBox("Enter a filename to save the exported messages to.", , MICRO_NAME)
If strFilename <> "" Then
strDateRange = InputBox("Enter the date range of the messages to export in the form ""mm/dd/yyyy to mm/dd/yyyy""", MACRO_NAME, Date & " to " & Date)
arrTemp = Split(strDateRange, "to")
datStart = IIf(IsDate(arrTemp(0)), arrTemp(0), Date) & " 12:00am"
datEnd = IIf(IsDate(arrTemp(1)), arrTemp(1), Date) & " 11:59pm"
intVersion = GetOutlookVersion()
Set excApp = CreateObject("Excel.Application")
Set excWkb = excApp.Workbooks.Add()
Set excWks = excWkb.ActiveSheet
'Write Excel Column Headers
With excWks
.Cells(1, 1) = "Subject"
.Cells(1, 2) = "Received"
.Cells(1, 3) = "Sender"
End With
intRow = 2
'Write messages to spreadsheet
Set olkLst = Application.ActiveExplorer.CurrentFolder.Items.Restrict("[ReceivedTime] >= '" & Format(datStart, "ddddd h:nn AMPM") & "'" & " AND [ReceivedTime] <= '" & Format(datEnd, "ddddd h:nn AMPM") & "'")
For Each olkMsg In olkLst
'Only export messages, not receipts or appointment requests, etc.
If olkMsg.Class = olMail Then
'Add a row for each field in the message you want to export
excWks.Cells(intRow, 1) = olkMsg.Subject
excWks.Cells(intRow, 2) = olkMsg.ReceivedTime
excWks.Cells(intRow, 3) = GetSMTPAddress(olkMsg, intVersion)
intRow = intRow + 1
End If
Next
Set olkMsg = Nothing
excWkb.SaveAs strFilename
excWkb.Close
End If
Set olkLst = Nothing
Set excWks = Nothing
Set excWkb = Nothing
Set excApp = Nothing
MsgBox "Process complete. A total of " & intRow - 2 & " messages were exported.", vbInformation + vbOKOnly, MICRO_NAME
End Sub
Private Function GetSMTPAddress(Item As Outlook.MailItem, intOutlookVersion As Integer) As String
Dim olkSnd As Outlook.AddressEntry, olkEnt As Object
On Error Resume Next
Select Case intOutlookVersion
Case Is < 14
If Item.SenderEmailType = "EX" Then
GetSMTPAddress = SMTP2007(Item)
Else
GetSMTPAddress = Item.SenderEmailAddress
End If
Case Else
Set olkSnd = Item.Sender
If olkSnd.AddressEntryUserType = olExchangeUserAddressEntry Then
Set olkEnt = olkSnd.GetExchangeUser
GetSMTPAddress = olkEnt.PrimarySmtpAddress
Else
GetSMTPAddress = Item.SenderEmailAddress
End If
End Select
On Error GoTo 0
Set olkPrp = Nothing
Set olkSnd = Nothing
Set olkEnt = Nothing
End Function
Function GetOutlookVersion() As Integer
Dim arrVer As Variant
arrVer = Split(Outlook.Version, ".")
GetOutlookVersion = arrVer(0)
End Function
Function SMTP2007(olkMsg As Outlook.MailItem) As String
Dim olkPA As Outlook.PropertyAccessor
On Error Resume Next
Set olkPA = olkMsg.PropertyAccessor
SMTP2007 = olkPA.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x5D01001E")
On Error GoTo 0
Set olkPA = Nothing
End Function
But this script export only selected folder in outlook.
What is the more important it should be exported from conversation history. For example in excel file there is mailbox YourMailbox#gmail.com. Script should find all conversation history and emails with this person and export information from emails. Information such as Subject, sender, date. Also script should check all list emails from excel file, not one.
Thanks for advices.
Application.ActiveExplorer.CurrentFolder will get current select folder, If you want to get all folder, you could refer to the below code:
Option Explicit
Sub repopulate3()
Dim olApp As Outlook.Application
Dim olNs As Outlook.Namespace
Dim olparentfolder As Outlook.Folder
Dim olMail As Object
Dim eFolder As Object
Dim i As Long
Dim wb As Workbook
Dim ws As Worksheet
Dim iCounter As Long
Dim lrow As Long
Dim lastrow As Long
'Set wb = ActiveWorkbook
'Set ws = wb.Worksheets("vlookup")
On Error Resume Next
Set olApp = GetObject(, "Outlook.Application")
On Error GoTo 0
If olApp Is Nothing Then
Set olApp = CreateObject("Outlook.Application")
End If
Set olNs = olApp.GetNamespace("MAPI")
Set olparentfolder = olNs.GetDefaultFolder(olFolderInbox)
'wb.Sheets("vlookup").range("A2:C500").ClearContents
'i think you want column E here, not L?
'lastrow = ThisWorkbook.Worksheets("vlookup").Cells(Rows.count, "E").End(xlUp).Row
ProcessFolder olparentfolder
ExitRoutine:
Set olparentfolder = Nothing
Set olNs = Nothing
Set olApp = Nothing
End Sub
Private Sub ProcessFolder(ByVal oParent As Outlook.Folder)
Dim olFolder As Outlook.Folder
Dim olMail As Object
Dim i As Long
Dim wb As Workbook
Dim ws As Worksheet
Dim iCounter As Long
Dim lrow As Long
Dim lastrow As Long
'Set wb = ActiveWorkbook
'Set ws = wb.Worksheets("vlookup")
'lastrow = ThisWorkbook.Worksheets("vlookup").Cells(Rows.count, "E").End(xlUp).Row
For i = oParent.Items.Count To 1 Step -1
Debug.Print oParent
If TypeOf oParent.Items(i) Is MailItem Then
Set olMail = oParent.Items(i)
Debug.Print " " & olMail.Subject
Debug.Print " " & olMail.ReceivedTime
Debug.Print " " & olMail.SenderEmailAddress
Debug.Print
'For iCounter = 2 To lastrow
'If InStr(olMail.SenderEmailAddress, ws.Cells(iCounter, 5).Value) > 0 Then 'qualify the cell
'With ws
' lrow = .range("A" & .Rows.count).End(xlUp).Row
' .range("C" & lrow + 1).Value = olMail.body
' .range("B" & lrow + 1).Value = olMail.ReceivedTime
' .range("A" & lrow + 1).Value = olMail.SenderEmailAddress
'End With
'End If
'Next iCounter
End If
Next i
If (oParent.Folders.Count > 0) Then
For Each olFolder In oParent.Folders
ProcessFolder olFolder
Next
End If
End Sub
For more information, Please refer to the below link:
VBA code to loop through every folder and subfolder in Outlook

Export contents of shared Outlook folder into Excel

I want to export mails from a shared mailbox into Excel.
Here is a code which is exporting mails from my default mailbox.
Sub ExportEmailsfromSpecificSender()
Dim objOutlook As Object
Dim objnSpace As Object
Dim objFolder As MAPIFolder
Dim objSubFolder As MAPIFolder
Dim objSubSubFolder As MAPIFolder
Dim EmailCount As Integer
' Dim dateStr As String
Dim myItems As Outlook.Items
Dim myFilterItems As Outlook.Items
' Dim dict As Object
' Dim msg As String
Dim excApp As Object
Dim excWkb As Object
Dim excWks As Object
' Dim intVersion As Integer
' Dim intMessages As Integer
Dim lngRow As Long
Dim strFilename As String
Dim objCategory As Category
Dim strFilter As String
Dim objEmails, objSpecificEmails As Outlook.Items
Dim objItem As Object
Dim strSpecificSender As String
Dim nRow As Integer
Dim strFilePath As String
Set objOutlook = CreateObject("Outlook.Application")
Set objnSpace = objOutlook.GetNamespace("MAPI")
Set excApp = CreateObject("Excel.Application")
Set excWkb = excApp.Workbooks.Add
On Error Resume Next
'Get the emails from a specific sender
'Set Items = GetFolderPath("PD Services\RetainPermanently\07 July 2018\").Items
Set objEmails = Application.Session.GetDefaultFolder(olFolderInbox).Items
strSpecificSender = InputBox("Input the name of the specific sender:", "Specify Sender")
strFilter = "[From] = '" & strSpecificSender & "'"
Set objSpecificEmails = objEmails.Restrict(strFilter)
Set objExcelApplication = CreateObject("Excel.Application")
Set objExcelWorkbook = objExcelApplication.Workbooks.Add
'Export the specific emails to worksheet
Set objExcelWorksheet = objExcelWorkbook.Worksheets(1)
With objExcelWorksheet
.Cells(1, 1) = "Subject"
.Cells(1, 2) = "Received"
.Cells(1, 3) = "Body"
End With
nRow = 2
For Each objItem In objSpecificEmails
With objExcelWorksheet
.Name = "From " & strSpecificSender
.Cells(nRow, 1) = objItem.Subject
.Cells(nRow, 2) = objItem.ReceivedTime
.Cells(nRow, 3) = objItem.Body
End With
nRow = nRow + 1
Next
objExcelWorksheet.Columns("A:E").AutoFit
'Save the Excel workbook
strFilePath = "H:\WINDOWS\system\Mitushi Documents " & strSpecificSender & ".xlsx"
objExcelWorkbook.Close True, strFilePath
'Notify you of the export complete
MsgBox ("Export Complete!")
End Sub
I am receiving a blank Excel file with only the column headers.
What should I modify here to get the emails from a shared mailbox called "PD Services" and a folder named "RetainPermanently"?
I'm not sure what a 'shared folder' is, but try the script below and see if you get the results you want.
Option Explicit On
Const fPath As String = "C:\Users\your_path_here\" 'The path to save the messages
Sub Download_Outlook_Mail_To_Excel()
Dim olApp As Object
Dim olFolder As Object
Dim olNS As Object
Dim xlBook As Workbook
Dim xlSheet As Worksheet
Dim NextRow As Long
Dim i As Long
Dim olItem As Object
Set xlBook = Workbooks.Add
Set xlSheet = xlBook.Sheets(1)
On Error Resume Next
Set olApp = GetObject(, "Outlook.Application")
If Err() <> 0 Then
Set olApp = CreateObject("Outlook.Application")
End If
On Error GoTo 0
With xlSheet
.Cells(1, 1) = "Sender"
.Cells(1, 2) = "Subject"
.Cells(1, 3) = "Date"
'.Cells(1, 4) = "Size"
.Cells(1, 5) = "EmailID"
.Cells(1, 6) = "Body"
CreateFolders fPath
Set olNS = olApp.GetNamespace("MAPI")
Set olFolder = olNS.PickFolder
For Each olItem In olFolder.Items
NextRow = .Cells(.Rows.Count, "A").End(xlUp).Row + 1
If olItem.Class = 43 Then
.Cells(NextRow, 1) = olItem.Sender
.Cells(NextRow, 2) = olItem.Subject
.Cells(NextRow, 3) = olItem.SentOn
'.Cells(NextRow, 4) =
.Cells(NextRow, 5) = SaveMessage(olItem)
'.Cells(NextRow, 6) = olItem.Body 'Are you sure?
End If
Next olItem
End With
MsgBox "Outlook Mails Extracted to Excel"
lbl_Exit:
Set olApp = Nothing
Set olFolder = Nothing
Set olItem = Nothing
Set xlBook = Nothing
Set xlSheet = Nothing
Exit Sub
End Sub
Function SaveMessage(olItem As Object) As String
Dim Fname As String
Fname = Format(olItem.ReceivedTime, "yyyymmdd") & Chr(32) &
Format(olItem.ReceivedTime, "HH.MM") & Chr(32) & olItem.sendername & " - " & olItem.Subject
Fname = Replace(Fname, Chr(58) & Chr(41), "")
Fname = Replace(Fname, Chr(58) & Chr(40), "")
Fname = Replace(Fname, Chr(34), "-")
Fname = Replace(Fname, Chr(42), "-")
Fname = Replace(Fname, Chr(47), "-")
Fname = Replace(Fname, Chr(58), "-")
Fname = Replace(Fname, Chr(60), "-")
Fname = Replace(Fname, Chr(62), "-")
Fname = Replace(Fname, Chr(63), "-")
Fname = Replace(Fname, Chr(124), "-")
SaveMessage = SaveUnique(olItem, fPath, Fname)
lbl_Exit:
Exit Function
End Function
Private Function SaveUnique(oItem As Object,
strPath As String,
strFileName As String) As String
Dim lngF As Long
Dim lngName As Long
lngF = 1
lngName = Len(strFileName)
Do While FileExists(strPath & strFileName & ".msg") = True
strFileName = Left(strFileName, lngName) & "(" & lngF & ")"
lngF = lngF + 1
Loop
oItem.SaveAs strPath & strFileName & ".msg"
SaveUnique = strPath & strFileName & ".msg"
lbl_Exit:
Exit Function
End Function
Private Sub CreateFolders(strPath As String)
Dim strTempPath As String
Dim iPath As Long
Dim vPath As Variant
vPath = Split(strPath, "\")
strPath = vPath(0) & "\"
For iPath = 1 To UBound(vPath)
strPath = strPath & vPath(iPath) & "\"
If Not FolderExists(strPath) Then MkDir strPath
Next iPath
End Sub
Private Function FolderExists(ByVal PathName As String) As Boolean
Dim nAttr As Long
On Error GoTo NoFolder
nAttr = GetAttr(PathName)
If (nAttr And vbDirectory) = vbDirectory Then
FolderExists = True
End If
NoFolder:
End Function
Private Function FileExists(filespec) As Boolean
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
If fso.FileExists(filespec) Then
FileExists = True
Else
FileExists = False
End If
lbl_Exit:
Exit Function
End Function

Resources