This code is meant to save attachments from selected items in Outlook 2010 to a folder in My Documents. I ran into a problem using the previous iteration that
Dim itm As Outlook.MailItem
My best guess as to why it failed to save attachments is there were some calendar invites mixed in, some of which had attachments. I modified the code to try and address this and have been getting Next Without For errors.
Public Sub saveAttachtoDisk()
Dim objOL As Outlook.Application
Dim objItems As Outlook.Items
Dim objFolder As Outlook.MAPIFolder
Dim obj As Object
Dim currentExplorer As Explorer
Dim Selection As Selection
Dim objAtt As Outlook.Attachment
Dim saveFolder As String
Dim fso As Object
Dim oldName
Dim file As String
Dim DateFormat As String
Dim newName As String
Dim enviro As String
enviro = CStr(Environ("USERPROFILE"))
saveFolder = enviro & "\Documents\Attachments\"
Set objOL = Outlook.Application
Set objFolder = objOL.ActiveExplorer.CurrentFolder
Set objItems = objFolder.Items
Set fso = CreateObject("Scripting.FileSystemObject")
For Each obj In objItems
With obj
For Each objAtt In itm.Attachments
file = saveFolder & objAtt.DisplayName
objAtt.SaveAsFile file
'Get the file name
Set oldName = fso.GetFile(file)
x = 1
Saved = False
DateFormat = Format(oldName.DateLastModified, "yyyy-mm-dd ")
newName = DateFormat & objAtt.DisplayName
'See if file name exists
If FileExist(saveFolder & newName) = False Then
oldName.Name = newName
GoTo NextAttach
End If
'Need a new filename
Count = InStrRev(newName, ".")
FnName = Left(newName, Count - 1)
fileext = Right(newName, Len(newName) - Count + 1)
Do While Saved = False
If FileExist(saveFolder & FnName & x & fileext) = False Then
oldName.Name = FnName & x & fileext
Saved = True
Else
x = x + 1
End If
Loop
NextAttach:
Set objAtt = Nothing
Next
Next
Set fso = Nothing
MsgBox "Done saving attachments"
End With
End Sub
Function FileExist(FilePath As String) As Boolean
Dim TestStr As String
Debug.Print FilePath
On Error Resume Next
TestStr = Dir(FilePath)
On Error GoTo 0
'Determine if File exists
If TestStr = "" Then
FileExist = False
Else
FileExist = True
End If
End Function
The logic is:
For Each obj In objItems
With obj
For Each objAtt In itm.Attachments
This must be "closed" in the reverse manner:
Next objAtt
End With
Next obj
Check this sequence in your code and adjust accordingly.
Note: although VB doesn't require (anymore) that a Next mentions its loop variable, it is good practice and helps you to better understand your For loops.
Related
I am trying to create a macro which will save out all emails of a selected folder within outlook2010 to my desktop, the code below exports the emails to a specified location but any emails that have the same subject/timestamp are overwritten.
Can I get some advice on how to resolve this issue please.
Option Explicit
Dim StrSavePath As String
Sub SaveAllEmails_ProcessAllSubFolders()
Dim i As Long
Dim j As Long
Dim n As Long
Dim StrSubject As String
Dim StrName As String
Dim StrFile As String
Dim StrReceived As String
Dim StrFolder As String
Dim StrSaveFolder As String
Dim StrFolderPath As String
Dim iNameSpace As NameSpace
Dim myOlApp As Outlook.Application
Dim SubFolder As MAPIFolder
Dim mItem As MailItem
Dim FSO As Object
Dim ChosenFolder As Object
Dim Folders As New Collection
Dim EntryID As New Collection
Dim StoreID As New Collection
Set FSO = CreateObject("Scripting.FileSystemObject")
Set myOlApp = Outlook.Application
Set iNameSpace = myOlApp.GetNamespace("MAPI")
Set ChosenFolder = iNameSpace.PickFolder
If ChosenFolder Is Nothing Then
GoTo ExitSub:
End If
BrowseForFolder StrSavePath
Call GetFolder(Folders, EntryID, StoreID, ChosenFolder)
For i = 1 To Folders.Count
StrFolder = StripIllegalChar(Folders(i))
n = InStr(3, StrFolder, "\") + 1
StrFolder = Mid(StrFolder, n, 256)
StrFolderPath = StrSavePath & "\" & StrFolder & "\"
StrSaveFolder = Left(StrFolderPath, Len(StrFolderPath) - 1) & "\"
If Not FSO.FolderExists(StrFolderPath) Then
FSO.CreateFolder (StrFolderPath)
End If
Set SubFolder = myOlApp.Session.GetFolderFromID(EntryID(i), StoreID(i))
On Error Resume Next
For j = 1 To SubFolder.Items.Count
Set mItem = SubFolder.Items(j)
StrReceived = Format(mItem.ReceivedTime, "YYYYMMDD-hhmmss")
StrSubject = mItem.Subject
StrName = StripIllegalChar(StrSubject)
StrFile = StrSaveFolder & StrReceived & "_" & StrName & ".msg"
StrFile = Left(StrFile, 256)
mItem.SaveAs StrFile, 3
Next j
On Error GoTo 0
Next i
ExitSub:
End Sub
Function StripIllegalChar(StrInput)
Dim RegX As Object
Set RegX = CreateObject("vbscript.regexp")
RegX.Pattern = "[\" & Chr(34) & "\!\#\#\$\%\^\&\*\(\)\=\+\|\[\]\{\}\`\'\;\:\<\>\?\/\,]"
RegX.IgnoreCase = True
RegX.Global = True
StripIllegalChar = RegX.Replace(StrInput, "")
ExitFunction:
Set RegX = Nothing
End Function
Sub GetFolder(Folders As Collection, EntryID As Collection, StoreID As Collection, Fld As MAPIFolder)
Dim SubFolder As MAPIFolder
Folders.Add Fld.FolderPath
EntryID.Add Fld.EntryID
StoreID.Add Fld.StoreID
For Each SubFolder In Fld.Folders
GetFolder Folders, EntryID, StoreID, SubFolder
Next SubFolder
ExitSub:
Set SubFolder = Nothing
End Sub
Function BrowseForFolder(StrSavePath As String, Optional OpenAt As String) As String
Dim objShell As Object
Dim objFolder ' As Folder
Dim enviro
enviro = CStr(Environ("USERPROFILE"))
Set objShell = CreateObject("Shell.Application")
Set objFolder = objShell.BrowseForFolder(0, "Please choose a folder", 0, enviro & "\Desktop\")
StrSavePath = objFolder.self.Path
On Error Resume Next
On Error GoTo 0
ExitFunction:
Set objShell = Nothing
End Function
You can try function
Function FileExists(file as String) as Boolean
If Not Dir(file, vbDirectory) = vbNullString Then
Return True
Else
Return False
End If
End Function
This way you can loop and add a suffix to the filename
[your code]
Dim count as Integer = 0
While (FileExists(file))
count = count + 1
file = dir & filename & count & extension
End While
It will exit the loop as soon as it finds an available name
I get a generated report by Oracle web app every week. I got a macro working to extract that attachment report from my email, but for some reason the date filter doesn't do anything and it saves all the attachments with the email subject "VERIPRD: XXVER Veritiv Aging Report Main: PETROP01" (which is the subject of the report that I want, but I get this weekly, and I only need to extract the most current one)
Also, the report comes with a .out extension which can be opened up with Excel, but if I save that file within the macros as xlsx it gets corrupted.
So what I need is for this macro to actually filter by date, and Subject line (mentioned above), save the .out file as an Excel file titled "Aging Report" and, if there's already an "Aging Report" in destination folder, to replace that previous excel file and not prompt with a message asking me if I want to replace it.
Here's the code I have so far which I put in MS outlook:
Public Sub Extract_Outlook_Email_Attachments()
Dim OutlookOpened As Boolean
Dim outApp As Outlook.Application
Dim outNs As Outlook.NameSpace
Dim outFolder As Outlook.MAPIFolder
Dim outAttachment As Outlook.attachment
Dim outItem As Object
Dim saveFolder As String
saveFolder = "C:\Users\borjax01\Desktop\aging reports"
Dim outMailItem As Outlook.MailItem
Dim inputDate As String, subjectFilter As String
If Right(saveFolder, 1) <> "\" Then saveFolder = saveFolder & "\" & "Aging
Report.out"
inputDate = InputBox("Enter date to filter the email subject", "Extract
Outlook email attachments")
If inputDate = "" Then Exit Sub
InputDateFilter = inputDate
subjectFilter = ("VERIPRD : XXVER Veritiv Aging Report Main : PETROP01")
OutlookOpened = False
On Error Resume Next
Set outApp = GetObject(, "Outlook.Application")
If Err.Number <> 0 Then
Set outApp = New Outlook.Application
OutlookOpened = True
End If
On Error GoTo 0
If outApp Is Nothing Then
MsgBox "Cannot start Outlook.", vbExclamation
Exit Sub
End If
Set outNs = outApp.GetNamespace("MAPI")
Set outFolder = outNs.PickFolder
If Not outFolder Is Nothing Then
For Each outItem In outFolder.Items
If outItem.Class = Outlook.OlObjectClass.olMail Then
Set outMailItem = outItem
If outMailItem.Subject = subjectFilter Then
Debug.Print outMailItem.Subject
For Each outAttachment In outMailItem.Attachments
outAttachment.SaveAsFile saveFolder
Set outAttachment = Nothing
Next
End If
End If
Next
End If
If OutlookOpened Then outApp.Quit
Set outApp = Nothing
End Sub
A post might get answers more quickly if broken into multiple single questions as is expected in this Q & A.
Public Sub Extract_Outlook_Email_Attachments()
Dim OutlookOpened As Boolean
Dim OutApp As outlook.Application
Dim outNs As outlook.Namespace
Dim outFolder As outlook.MAPIFolder
Dim outAttachment As outlook.Attachment
Dim outItem As Object
Dim saveFolder As String
Dim outMailItem As outlook.MailItem
Dim inputDate As String, subjectFilter As String
Dim fldrItems As Items
Dim resultItems As Items
Dim strFilter As String
saveFolder = "C:\Users\borjax01\Desktop\aging reports"
saveFolder = "H:\test2"
'If Right(saveFolder, 1) <> "\" Then saveFolder = saveFolder & "\" & "Aging Report.out"
If Right(saveFolder, 1) <> "\" Then saveFolder = saveFolder & "\"
' subjectFilter = ("VERIPRD : XXVER Veritiv Aging Report Main : PETROP01")
' No "Re:" nor "Fw:"
subjectFilter = "VERIPRD : XXVER Veritiv Aging Report Main : PETROP01"
OutlookOpened = False
On Error Resume Next
Set OutApp = getObject(, "Outlook.Application")
If Err.number <> 0 Then
Set OutApp = New outlook.Application
OutlookOpened = True
End If
On Error GoTo 0
If OutApp Is Nothing Then
MsgBox "Cannot start Outlook.", vbExclamation
Exit Sub
End If
Set outNs = OutApp.GetNamespace("MAPI")
Set outFolder = outNs.PickFolder
If Not outFolder Is Nothing Then
Set fldrItems = outFolder.Items
strFilter = "[Subject] = '" & subjectFilter & "'"
Debug.Print strFilter
Set resultItems = fldrItems.Restrict(strFilter)
'Debug.Print resultItems.count
resultItems.Sort "[ReceivedTime]", True
For Each outItem In resultItems
If outItem.Class = outlook.OlObjectClass.olMail Then
Set outMailItem = outItem
If outMailItem.subject = subjectFilter Then
Debug.Print " outMailItem.subject: " & outMailItem.subject
Debug.Print " outMailItem.ReceivedTime: " & outMailItem.ReceivedTime
For Each outAttachment In outMailItem.Attachments
Debug.Print " outAttachment.DisplayName: " & outAttachment.DisplayName
If InStr(outAttachment.DisplayNamem, ".out") Then
outAttachment.SaveAsFile saveFolder & outAttachment.DisplayName
Exit Sub '<-- exit when most recent is saved
End If
Next
End If
End If
Next
End If
If OutlookOpened Then OutApp.Quit
Set OutApp = Nothing
End Sub
I save items I receive on my hard drive and name them differently.
Trying to import the items back into Outlook gives me an error:
Compile Error User-Defined type not defined.
on
Dim Savefolder As Outlook.Folder
In my first module
Public Sub saveAttachtoDisk(itm As Outlook.MailItem)
Dim objAtt As Outlook.Attachment
Dim Savefolder As String
Savefolder = "c:\temp"
For Each objAtt In itm.Attachments
stFileName = Savefolder & "\" & objAtt.DisplayName
i = 0
JumpHere:
If Dir(stFileName) = "" Then
objAtt.SaveAsFile stFileName
Else
i = i + 1
stFileName = Savefolder & "\" & objAtt.DisplayName & " - " & i
GoTo JumpHere
End If
Set objAtt = Nothing
Next
End Sub
In my second module
Sub ImportMessagesInFolder()
Dim fso As Scripting.FileSystemObject
Dim SourceFolder As Scripting.Folder
Dim SourceFolderName As String
Dim FileItem As Scripting.file
Dim strFile, strFileType As String
Dim oMsg As Object
Dim copiedMsg As MailItem
Dim Savefolder As Outlook.Folder
Set fso = New Scripting.FileSystemObject
'Source folder
SourceFolderName = "C:\temp"
Set SourceFolder = fso.GetFolder(SourceFolderName)
'Set the Outlook folder name
Set Savefolder = Session.GetDefaultFolder(olFolderInbox).Folders("Extra")
Set Savefolder = Application.ActiveExplorer.CurrentFolder
For Each FileItem In SourceFolder.Files
Set oMsg = Session.OpenSharedItem(FileItem.Path)
On Error Resume Next
Set copiedMsg = oMsg.Copy
copiedMsg.Move Savefolder
Set copiedMsg = Nothing
oMsg.Delete
Set oMsg = Nothing
Next FileItem
Set FileItem = Nothing
Set SourceFolder = Nothing
Set fso = Nothing
End Sub
Use Outlook.MAPIFolder instead.
I have the following code to save emails from Outlook to a folder on the desktop.
I would like to name the files with the email subjects exactly the way they are in Outlook. I do not want to strip any characters.
I have played around with the macro but I can't fix it. Also would like to remove the time stamp date etc.
Option Explicit
Dim StrSavePath As String
Sub SaveAllEmails_ProcessAllSubFolders()
Dim i As Long
Dim j As Long
Dim n As Long
Dim StrSubject As String
Dim StrName As String
Dim StrFile As String
Dim StrReceived As String
Dim StrFolder As String
Dim StrSaveFolder As String
Dim StrFolderPath As String
Dim iNameSpace As NameSpace
Dim myOlApp As Outlook.Application
Dim SubFolder As MAPIFolder
Dim mItem As MailItem
Dim FSO As Object
Dim ChosenFolder As Object
Dim Folders As New Collection
Dim EntryID As New Collection
Dim StoreID As New Collection
Set FSO = CreateObject("Scripting.FileSystemObject")
Set myOlApp = Outlook.Application
Set iNameSpace = myOlApp.GetNamespace("MAPI")
Set ChosenFolder = iNameSpace.PickFolder
If ChosenFolder Is Nothing Then
'GoTo ExitSub:
End If
BrowseForFolder StrSavePath
Call GetFolder(Folders, EntryID, StoreID, ChosenFolder)
For i = 1 To Folders.Count
StrFolder = StripIllegalChar(Folders(i))
n = InStr(3, StrFolder, "\") + 1
StrFolder = Mid(StrFolder, n, 256)
StrFolderPath = StrSavePath & "\" & StrFolder & "\"
StrSaveFolder = Left(StrFolderPath, Len(StrFolderPath) - 1) & "\"
If Not FSO.FolderExists(StrFolderPath) Then
FSO.CreateFolder (StrFolderPath)
End If
Set SubFolder = myOlApp.Session.GetFolderFromID(EntryID(i), StoreID(i))
On Error Resume Next
For j = 1 To SubFolder.Items.Count
Set mItem = SubFolder.Items(j)
StrReceived = Format(mItem.ReceivedTime, "YYYYMMDD-hhmm")
StrSubject = mItem.Subject
StrName = StripIllegalChar(StrSubject)
StrFile = StrSaveFolder & StrReceived & "_" & StrName & ".msg"
StrFile = Left(StrFile, 256)
mItem.SaveAs StrFile, 3
Next j
On Error GoTo 0
Next i
ExitSub:
End Sub
Function StripIllegalChar(StrInput)
Dim RegX As Object
Set RegX = CreateObject("vbscript.regexp")
RegX.Pattern = "[\" & Chr(34) & "\!\#\#\$\%\^\&\*\(\)\=\+\|\[\]\{\}\`\'\;\:\<\>\?\/\,]"
RegX.IgnoreCase = True
RegX.Global = True
StripIllegalChar = RegX.Replace(StrInput, "")
ExitFunction:
Set RegX = Nothing
End Function
Sub GetFolder(Folders As Collection, EntryID As Collection, _
StoreID As Collection, Fld As MAPIFolder)
Dim SubFolder As MAPIFolder
Folders.Add Fld.FolderPath
EntryID.Add Fld.EntryID
StoreID.Add Fld.StoreID
For Each SubFolder In Fld.Folders
GetFolder Folders, EntryID, StoreID, SubFolder
Next SubFolder
ExitSub:
Set SubFolder = Nothing
End Sub
Function BrowseForFolder(StrSavePath As String, _
Optional OpenAt As String) As String
Dim objShell As Object
Dim objFolder ' As Folder
Dim enviro
enviro = CStr(Environ("USERPROFILE"))
Set objShell = CreateObject("Shell.Application")
Set objFolder = objShell.BrowseForFolder(0, "Please choose a folder", _
0, enviro & "C:\Temp\Folders")
StrSavePath = objFolder.self.Path
On Error Resume Next
On Error GoTo 0
ExitFunction:
Set objShell = Nothing
End Function
an alternative approach if you absolutely want to retain the original email unaltered is to create a new email message to yourself with the original email saved as an attachment. Save the new email with a corrected subject to avoid windows naming errors, it will retain a link to the unaltered original.
It's a few extra steps but you should be able to automate those if you insist on retaining the original email unaltered.
Its bad idea like Tim said, but if that is what you want to do then modify your j loop to something like this...
For j = 1 To SubFolder.Items.Count
Set mItem = SubFolder.Items(j)
StrSubject = mItem.Subject
StrSubject = StrSaveFolder & StrSubject & ".msg"
mItem.SaveAs StrSubject, 3
Next j
Good Luck...
I compiled and coded a macro for Outlook 2011. This macro for that it saves all the mails as word file.
The problem is that I couldn't close the dialog box automatically, I have so much signed message I couldn't solve this problem.
This is the message dialog:
And the code:
Option Explicit
Dim StrSavePath As String
Sub SaveAllEmails_ProcessAllSubFolders()
Dim i As Long
Dim j As Long
Dim n As Long
Dim strSubject As String
Dim StrName As String
Dim StrFile As String
Dim StrReceived As String
Dim StrFolder As String
Dim StrSaveFolder As String
Dim StrFolderPath As String
Dim iNameSpace As NameSpace
Dim myOlApp As Outlook.Application
Dim SubFolder As MAPIFolder
Dim mItem As Object
Dim docItem As Object
Dim FSO As Object
Dim ChosenFolder As Object
Dim Folders As New Collection
Dim EntryID As New Collection
Dim StoreID As New Collection
Dim checkIfDigitallySigned As Long
Set FSO = CreateObject("Scripting.FileSystemObject")
Set myOlApp = Outlook.Application
Dim OLIns As Outlook.Inspector
Set iNameSpace = myOlApp.GetNamespace("MAPI")
Set ChosenFolder = iNameSpace.PickFolder
Const olAlertsNone = 0
If ChosenFolder Is Nothing Then
GoTo ExitSub:
End If
Set docItem = Application.CreateItem(olMailItem)
docItem.BodyFormat = olFormatRichText
BrowseForFolder StrSavePath
Call GetFolder(Folders, EntryID, StoreID, ChosenFolder)
For i = 1 To Folders.Count
StrFolder = StripIllegalChar(Folders(i))
n = InStr(3, StrFolder, "\") + 1
StrFolder = Mid(StrFolder, n, 256)
StrFolderPath = StrSavePath & "\" & StrFolder & "\"
StrSaveFolder = Left(StrFolderPath, Len(StrFolderPath) - 1) & "\"
If Not FSO.FolderExists(StrFolderPath) Then
FSO.CreateFolder (StrFolderPath)
End If
Set SubFolder = myOlApp.Session.GetFolderFromID(EntryID(i), StoreID(i))
On Error Resume Next
For j = 1 To SubFolder.Items.Count
Set mItem = SubFolder.Items(j)
StrReceived = Format(mItem.ReceivedTime, "YYYYMMDD-hhmm")
strSubject = mItem.Subject
StrName = StripIllegalChar(strSubject)
StrFile = StrSaveFolder & StrReceived & "_" & StrName & ".doc"
StrFile = Left(StrFile, 256)
mItem.SaveAs StrFile, olRTF
Next j
On Error GoTo 0
Next i
ExitSub:
End Sub
Some utility functions used by the macro:
Function StripIllegalChar(StrInput)
Dim RegX As Object
Set RegX = CreateObject("vbscript.regexp")
RegX.Pattern = "[\" & Chr(34) & "\!\#\#\$\%\^\&\*\(\)\=\+\|\[\]\{\}\`\'\;\:\<\>\?\/\,]"
RegX.IgnoreCase = True
RegX.Global = True
StripIllegalChar = RegX.Replace(StrInput, "")
ExitFunction:
Set RegX = Nothing
End Function
Sub GetFolder(Folders As Collection, EntryID As Collection, StoreID As Collection, Fld As MAPIFolder)
Dim SubFolder As MAPIFolder
Folders.Add Fld.FolderPath
EntryID.Add Fld.EntryID
StoreID.Add Fld.StoreID
For Each SubFolder In Fld.Folders
GetFolder Folders, EntryID, StoreID, SubFolder
Next SubFolder
ExitSub:
Set SubFolder = Nothing
End Sub
Function BrowseForFolder(StrSavePath As String, Optional OpenAt As String) As String
Dim objShell As Object
Dim objFolder ' As Folder
Dim enviro
enviro = CStr(Environ("USERPROFILE"))
Set objShell = CreateObject("Shell.Application")
Set objFolder = objShell.BrowseForFolder(0, "Please choose a folder", 0, enviro & "\Documents\")
StrSavePath = objFolder.self.Path
On Error Resume Next
On Error GoTo 0
ExitFunction:
Set objShell = Nothing
End Function
There is no way to turn that prompt off. You can try to use Redemption (I am its author) to bypass the prompts. Note that signed/encrypted messages are processed separately since they need to be decrypted first.
set rSession = CreateObject("Redemption.RDOSession")
rSession.MAPIOBJECT = myOlApp.Session.MAPIOBJECT
set rFolder = rSession.GetRDOFolderFromOutlookObject(SubFolder)
ser rItems = rFolder.Items
For j = 1 To rItems.Count
Set mItem = rItems(j)
if TypeName(mItem) = "RDOEncryptedMessage" Then
'process encrypted/signed messages separately
mItem = mItem.GetDecryptedMessage
Enf If
StrReceived = Format(mItem.ReceivedTime, "YYYYMMDD-hhmm")
strSubject = mItem.Subject
StrName = StripIllegalChar(strSubject)
StrFile = StrSaveFolder & StrReceived & "_" & StrName & ".doc"
StrFile = Left(StrFile, 256)
mItem.SaveAs StrFile, olRTF
Next j