Visit my Youtube Channel
Extract Attachments from Saved Outlook Emails using Excel VBA
Home
This tutorial will cover how to extract attachments from saved Outlook emails messages using Excel VBA. A saved Outlook message is where you copy an email message from Outlook and save it in your computer folder as a .msg message. If you have the right rules setup in Outlook, you can copy and paste multiple Outlook messages quite easily onto your computer drive.
Extracting attachments from saved Outlook messages using Excel VBA is a safer way to download attachments. As opposed to directly connecting to the Outlook mailbox and extracting messages from there. There is no risk here, of accidently deleting off the the emails. If something goes wrong, the saved messages will be unaffected. This gives us the perfect platform to experiment. I have built stable and complex code to extract 100s of messages with all sorts of attachments, using this technique.
The video contains 3 demos; built on top of each other. Full code for each demo is given below. For this code to work, you’ll first need to connect to the Outlook library. Go to Tools -> References and select the Outlook Object library.
If you like this video and blog, please check out my other Outlook and Excel VBA related content on how to send Outlook Emails: Tutorial 1, Tutorial 2, Tutorial 3.
Demo 1- Extract Outlook Attachments with Excel VBA
This is the vanilla version where we see how to extract attachments as-is from multiple Outlook messages saved on our computer drive. We don’t yet amend the file name to account for duplicate file names (Demo 2) or include any error handling (Demo 3).
The following setup is required for this code to work. The macro file with this code needs to be saved on the computer. There will need to be two folders named “In” and “Out” created in the same location as the macro file. Your saved Outlook messages will need to be saved in the “In” folder, and the attachments will be extracted in the “Out” folder.
Option Explicit
Const csOutlookIn As String = "In"
Const csOutlookOut As String = "Out"
Sub Extract_Emails_Demo1()
Application.ScreenUpdating = False
Dim sCurrentFolder As String
sCurrentFolder = ActiveWorkbook.Path & "\"
Dim FSO As Scripting.FileSystemObject
Set FSO = New Scripting.FileSystemObject
Dim fldrOutlookIn As Scripting.Folder
Set fldrOutlookIn = FSO.GetFolder(sCurrentFolder & csOutlookIn)
Dim oApp As Outlook.Application
Set oApp = New Outlook.Application
Dim oMail As Outlook.MailItem
Dim oAttach As Outlook.Attachment
Dim fileItem As Scripting.File
Dim sAttachName As String
For Each fileItem In fldrOutlookIn.Files
Set oMail = oApp.CreateItemFromTemplate(fileItem.Path)
For Each oAttach In oMail.Attachments
sAttachName = oAttach.Filename
sAttachName = sCurrentFolder & csOutlookOut & "\" & sAttachName
oAttach.SaveAsFile sAttachName
Next oAttach
Set oMail = Nothing
Next fileItem
MsgBox "Done!"
Application.ScreenUpdating = True
End Sub
Demo 2 – Avoid Duplicates While Extracting Attachments
The code in Demo 1 will work in most cases. However, we will run into an issue if the two or more attachments have the same file name. To avoid this, we can amend the code slightly by adding a unique prefix at the start of the file name as we save the attachment.
The prefix that I use is “file” and is declared as a Constant right at the start. This along with the counter variable will assign the prefixes “file1”, “file2”, “file3” etc. to the files as they get extracted. You can choose to rename this prefix to anything else, by changing the constant.
Option Explicit
Const csOutlookIn As String = "In"
Const csOutlookOut As String = "Out"
Const csFilePrefix As String = "file"
Sub Extract_Emails_Demo2()
Application.ScreenUpdating = False
Dim sCurrentFolder As String
sCurrentFolder = ActiveWorkbook.Path & "\"
Dim FSO As Scripting.FileSystemObject
Set FSO = New Scripting.FileSystemObject
Dim fldrOutlookIn As Scripting.Folder
Set fldrOutlookIn = FSO.GetFolder(sCurrentFolder & csOutlookIn)
Dim oApp As Outlook.Application
Set oApp = New Outlook.Application
Dim oMail As Outlook.MailItem
Dim oAttach As Outlook.Attachment
Dim fileItem As Scripting.File
Dim sAttachName As String
Dim lcounter As Long
lcounter = 0
Dim scounter As String
For Each fileItem In fldrOutlookIn.Files
Set oMail = oApp.CreateItemFromTemplate(fileItem.Path)
For Each oAttach In oMail.Attachments
lcounter = lcounter + 1
scounter = Format(lcounter, "000")
sAttachName = oAttach.Filename
sAttachName = sCurrentFolder & csOutlookOut & "\" & csFilePrefix & scounter & "_" & sAttachName
oAttach.SaveAsFile sAttachName
Next oAttach
Set oMail = Nothing
Next fileItem
MsgBox "Done!"
Application.ScreenUpdating = True
End Sub
Demo 3 – Error Handling
We can go a step further and add some error handling to account for user related issues such as not removing the extracted attachments from the “Out” folder, before running the macro for the next run. We will also, create a detailed log of what got extracted and what was skipped over.
Option Explicit
Const csOutlookIn As String = "In"
Const csOutlookOut As String = "Out"
Const csFilePrefix As String = "file"
Sub Extract_Emails_Demo3()
Application.ScreenUpdating = False
Dim sCurrentFolder As String
sCurrentFolder = ActiveWorkbook.Path & "\"
Dim FSO As Scripting.FileSystemObject
Set FSO = New Scripting.FileSystemObject
If Not FSO.FolderExists(sCurrentFolder & csOutlookIn) Then
MsgBox "Folder """ & csOutlookIn & """ doesn't exist in Current Directory." & vbNewLine & _
"For this macro to work, please: " & vbNewLine & _
"1. Create a folder called """ & csOutlookIn & """ in this directory " & vbNewLine & _
"2. Place your outlook messages there." & vbNewLine & _
"Thanks!", vbCritical, "Error Occured"
Application.ScreenUpdating = True
Exit Sub
End If
If Not FSO.FolderExists(sCurrentFolder & csOutlookOut) Then
FSO.CreateFolder (sCurrentFolder & csOutlookOut)
End If
wsMain.Range("G:I").ClearContents
wsMain.Range("G1").Value = "Outlook Message Name"
wsMain.Range("H1").Value = "Outlook Attachment Name"
wsMain.Range("I1").Value = "Outlook Status"
Dim fldrOutlookIn As Scripting.Folder, fldrOutlookOut As Scripting.Folder
Set fldrOutlookIn = FSO.GetFolder(sCurrentFolder & csOutlookIn)
Set fldrOutlookOut = FSO.GetFolder(sCurrentFolder & csOutlookOut)
If fldrOutlookIn.Files.Count = 0 Then
MsgBox "There can be no files in the """ & csOutlookOut & """ folder." & vbNewLine & _
"Please empty the folder and re-run the macro. Thanks!", vbCritical, "Error Occured"
Application.ScreenUpdating = True
Exit Sub
End If
If fldrOutlookOut.Files.Count <> 0 Then
MsgBox "There can be no files in the """ & csOutlookOut & """ folder." & vbNewLine & _
"Please empty the folder and re-run the macro. Thanks!", vbCritical, "Error Occured"
Application.ScreenUpdating = True
Exit Sub
End If
Dim oApp As Outlook.Application
Set oApp = New Outlook.Application
Dim oMail As Outlook.MailItem
Dim oAttach As Outlook.Attachment
Dim fileItem As Scripting.File
Dim sAttachName As String
Dim lrow As Long
Dim lcounter As Long
lcounter = 0
Dim scounter As String
For Each fileItem In fldrOutlookIn.Files
If Right(fileItem.Name, 3) <> "msg" Then
GoTo LineNotOutlookMsg
End If
Set oMail = oApp.CreateItemFromTemplate(fileItem.Path)
For Each oAttach In oMail.Attachments
lcounter = lcounter + 1
scounter = Format(lcounter, "000")
sAttachName = oAttach.Filename
sAttachName = sCurrentFolder & csOutlookOut & "\" & csFilePrefix & scounter & "_" & sAttachName
oAttach.SaveAsFile sAttachName
lrow = wsMain.Range("g1").CurrentRegion.Rows.Count
wsMain.Range("G" & lrow).Offset(1).Value = fileItem.Name
wsMain.Range("H" & lrow).Offset(1).Value = oAttach.Filename
wsMain.Range("I" & lrow).Offset(1).Value = "Completed"
Next oAttach
If oMail.Attachments.Count = 0 Then
lrow = wsMain.Range("g1").CurrentRegion.Rows.Count
wsMain.Range("G" & lrow).Offset(1).Value = fileItem.Name
wsMain.Range("H" & lrow).Offset(1).Value = ""
wsMain.Range("I" & lrow).Offset(1).Value = "No attachments found"
End If
Set oMail = Nothing
GoTo LineNextFile
LineNotOutlookMsg:
lrow = wsMain.Range("g1").CurrentRegion.Rows.Count
wsMain.Range("G" & lrow).Offset(1).Value = fileItem.Name
wsMain.Range("H" & lrow).Offset(1).Value = ""
wsMain.Range("I" & lrow).Offset(1).Value = "Not an outlook message"
LineNextFile:
Next fileItem
wsMain.Columns("G:I").AutoFit
MsgBox "Done!"
Application.ScreenUpdating = True
End Sub
Extract Attachments from Outlook Tasks
We will continue with the same code in Demo 2. An Outlook Task is an Object under the Outlook Application, just like an Outlook Email. We can use the exact same code with some tweaks.
All we have to do is replace Outlook.MailItem with Outlook.TaskItem.
I have made a few more modifications. Screenshots saved in a Task seem to be getting saved as a Picture Device Independent Bitmap), which error out when trying to extract them. To circumvent this, I have placed some error handling in the code. A Resume Next statement before we begin extracting (to skip over any errors) and a Go To 0 after we have done extracting (to give error control back to Excel).
One more modification is the ability to specify what file you want to extract. Once we grab the file name, we can check what the extension is. And we can put in an IF statement to only extract files, for the extensions that we need. Below example shows a case where we want to only extract pdf files and ignore the rest. If you want to extract two or more specific file types, add the condition to the IF statement separated by an OR.
If Right(sAttachName, 4) = ".pdf" Then
sAttachName = sCurrentFolder & csOutlookOut & "\" & sAttachName
oAttach.SaveAsFile sAttachName
End If
For now, though, I have commented out the IF statement for the extension. If you want to use it, just remove the apostrophe.
Option Explicit
Const csOutlookIn As String = "In"
Const csOutlookOut As String = "Out"
Const csFilePrefix As String = "file"
Sub Extract_Emails_Demo2()
Application.ScreenUpdating = False
Dim sCurrentFolder As String
sCurrentFolder = ActiveWorkbook.Path & "\"
Dim FSO As Scripting.FileSystemObject
Set FSO = New Scripting.FileSystemObject
Dim fldrOutlookIn As Scripting.Folder
Set fldrOutlookIn = FSO.GetFolder(sCurrentFolder & csOutlookIn)
Dim oApp As Outlook.Application
Set oApp = New Outlook.Application
Dim oTask As Outlook.TaskItem
Dim oAttach As Outlook.Attachment
Dim fileItem As Scripting.File
Dim sAttachName As String
Dim lcounter As Long
lcounter = 0
Dim scounter As String
For Each fileItem In fldrOutlookIn.Files
Set oTask = oApp.CreateItemFromTemplate(fileItem.Path)
On Error Resume Next
For Each oAttach In oTask.Attachments
sAttachName = oAttach.Filename
'If Right(sAttachName, 4) = ".pdf" Then
lcounter = lcounter + 1
scounter = Format(lcounter, "000")
sAttachName = sCurrentFolder & csOutlookOut & "\" & csFilePrefix & scounter & "_" & sAttachName
oAttach.SaveAsFile sAttachName
'End If
Next oAttach
On Error GoTo 0
Set oTask = Nothing
Next fileItem
MsgBox "Done!"
Application.ScreenUpdating = True
End Sub
Extract Emails and Tasks
The following code will extract from files with extension .msg i.e. Emails and Tasks.
Option Explicit
Const csOutlookIn As String = "In"
Const csOutlookOut As String = "Out"
Const csFilePrefix As String = "file"
Sub Extract_Emails_And_Tasks()
Application.ScreenUpdating = False
Dim sCurrentFolder As String
sCurrentFolder = ActiveWorkbook.Path & "\"
Dim FSO As Scripting.FileSystemObject
Set FSO = New Scripting.FileSystemObject
Dim fldrOutlookIn As Scripting.Folder
Set fldrOutlookIn = FSO.GetFolder(sCurrentFolder & csOutlookIn)
Dim oApp As Outlook.Application
Set oApp = New Outlook.Application
Dim oTask As Outlook.TaskItem
Dim oMail As Outlook.MailItem
Dim oAttach As Outlook.Attachment
Dim fileItem As Scripting.File
Dim sAttachName As String
Dim lcounter As Long
lcounter = 0
Dim scounter As String
For Each fileItem In fldrOutlookIn.Files
If Right(fileItem.Name, 4) <> ".msg" Then GoTo NextFile
On Error Resume Next
Set oTask = oApp.CreateItemFromTemplate(fileItem.Path)
Set oMail = oApp.CreateItemFromTemplate(fileItem.Path)
For Each oAttach In oTask.Attachments
sAttachName = oAttach.Filename
lcounter = lcounter + 1
scounter = Format(lcounter, "000")
sAttachName = sCurrentFolder & csOutlookOut & "\" & csFilePrefix & scounter & "_" & sAttachName
oAttach.SaveAsFile sAttachName
Next oAttach
On Error GoTo 0
If Not oTask Is Nothing Then
Set oTask = Nothing
End If
If Not oMail Is Nothing Then
Set oMail = Nothing
End If
NextFile:
Next fileItem
MsgBox "Done!"
Application.ScreenUpdating = True
End Sub