Loop Through Sub Dir - vba

I have the following code that requires me to manually update the "DateFolder" each time for my directories to move.
How do I update this so all the subfolders in the "source folder" are moved based on my code?
The folder structure is:
Date 1
|
Folder 1
|
Files
Date 2
|
Folder 1
|
Files
Sub MoveFolder()
'move any directories with all their contents listed in DIR_UPDATE
' from the source folder to the destination folder
Dim objFSO As Object
Dim rs As DAO.Recordset
Dim db As DAO.Database
Dim sourceFolder As String
Dim destinationFolder As String
Dim mysql As String
Dim DateFolder As String
DateFolder = "20160331"
mysql = "SELECT * from Update"
sourceFolder = "C:\Test\" & DateFolder & "\"
destinationFolder = "C:\Test\New\" & DateFolder & "\"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set db = CurrentDb
Set rs = db.OpenRecordSet(mysql)
'look for folders from UPDATE and move them from sourcefolder to destinationfolder
While Not rs.EOF
UPdateFolder = sourceFolder & rs!Update '
'must tell dir that sourceFolder is a directory
If Dir(UPdateFolder, vbDirectory) <> "" Then
objFSO.MoveFolder Source:=UPdateFolder, destination:=destinationFolder '
Debug.Print "Move Folder Command Complete From: " & UPdateFolder & _
"......To: " & destinationFolder & rs!Update
Else
End If
rs.MoveNext
Wend
Debug.Print "Move Complete " & Now()
End Sub

How do you think about this code? I checked it in my OS.
Sub MoveFolder()
'
' move any directories with all their contents listed in DIR_UPDATE from the source folder to the Destination folder
'
Dim objFSO As Object
Dim rs As DAO.Recordset
Dim db As DAO.Database
Dim sourceFolder As String
Dim destinationFolder As String
Dim mysql As String
Dim DateFolder As String
Dim objFolder, objSubFolders
Dim UPdateFolder As String
Dim sourceFolder0 As String, destinationFolder0 As String
mysql = "SELECT * from [Update]"
Set db = CurrentDb
Set rs = db.OpenRecordset(mysql)
sourceFolder0 = "C:\Test"
destinationFolder0 = "C:\Test\New"
' sourceFolder = "C:\Test\" & DateFolder & "\"
' destinationFolder = "C:\Test\New\" & DateFolder & "\"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder(sourceFolder0)
Set objSubFolders = objFolder.SubFolders
'
' loop over SubFolders to check them if they are DateFolder:
'
For Each objFolder In objSubFolders
'
' get SubFolder short name:
'
' DateFolder = "20160331"
'
DateFolder = objFolder.Name
'
' if it's a DateFolder in yyyymmdd format,
' eg 20160331, dir length = 8:
'
If (IsNumeric(DateFolder) And Len(DateFolder) = 8) Then
'
' sourceFolder = "C:\Test\" & DateFolder & "\"
' destinationFolder = "C:\Test\New\" & DateFolder & "\"
'
sourceFolder = sourceFolder0 & "\" & DateFolder & "\"
destinationFolder = destinationFolder0 & "\" & DateFolder & "\"
'
' check if the destination exists:
' create it if nonexistent.
'
If (Not objFSO.FolderExists(destinationFolder)) Then
objFSO.CreateFolder destinationFolder
End If
'
' look for folders from UPDATE and move them
' from sourcefolder to destinationFolder
'
While Not rs.EOF
UPdateFolder = sourceFolder & rs!Update
'
' must tell dir that sourceFolder is a directory:
'
If Dir(UPdateFolder, vbDirectory) <> "" Then
objFSO.MoveFolder Source:=UPdateFolder, Destination:=destinationFolder
Debug.Print "Move Folder Command Complete From: " _
& UPdateFolder & "......To: " _
& destinationFolder & rs!Update
Else
End If
rs.MoveNext
Wend
'
' rewind recordset for the next DateFolder:
'
rs.MoveFirst
'
End If
Next
rs.Close
Set rs = Nothing
Set objFolder = Nothing
Set objSubFolders = Nothing
Debug.Print "Move Complete " & Now()
End Sub

Related

How do I save attachment files to a directory and keep the file extension?

I would like to save the attachments to a directory using a new file name.
The following code renames the files but loose their extension. The files are image files.
How do I go by?
Dim strFileName As String
Dim rsParent As DAO.Recordset2
Dim rsChild As DAO.Recordset2
Dim subField As DAO.Field2
Dim strPath As String
strPath = "C:\Images"
If Len(Dir("C:\Images", vbDirectory)) = 0 Then
MkDir "C:\Images"
End If
Set rsParent = CurrentDb.OpenRecordset("tblDonations", dbOpenSnapshot)
With rsParent
If .RecordCount > 0 Then .MoveFirst
While Not .EOF
Set rsChild = rsParent("Image").Value
If rsChild.RecordCount > 0 Then rsChild.MoveFirst
While Not rsChild.EOF
Set subField = rsChild("FileData")
strFileName = strPath & "\" & .Fields("ItemNo")
If Len(Dir(strFileName)) <> 0 Then Kill strFileName
subField.SaveToFile strFileName
rsChild.MoveNext
Wend
.MoveNext
Wend
End With
subflied.Close
Set subfield = Nothing
rsChild.Close
Set rsChild = Nothing
rsParent.Close
Set rsParent = Nothing
Append file extension onto strFileName. Extract it from rsChild("FileType").
strFileName = strPath & "\" & .Fields("ItemNo") & "." & rsChild("FileType")

How can I make subfolders of subfolders?

I have a directory that has 1000's of files. The filename string goes like: ManagerName_EmployeeName_First Assessment.xlsx
but I have a specific type of grouping I need to execute so that I have folders go by ManagerName > Employee Name and then the 5 types of Assessments in the employees folder.
How would I edit this to identify the first _ in the filename (ManagerName) and then make a folder by that ManagerName and then make a subfolder by EmployeeName and then house all five files under that employee in the employee subfolder?
I know you'd need to use a Left(fileName, InStrRev(fileName, "_") > 1) type function to identify the first text string to the left of the first _ but how would I go and create a second subfolder based on the employee under that manager?
Here's a shell of the code I was thinking:
Option Explicit
Sub MoveFiles()
Dim objFSO As Object
Dim objMyFolder As Object
Dim objMyFile As Object
Dim strSourceFolder As String
Dim strDestFolder As String
Application.ScreenUpdating = False
strSourceFolder = "C:\Users\CIB\"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objMyFolder = objFSO.GetFolder(strSourceFolder)
For Each objMyFile In objMyFolder.Files
Do While objMyFile <> ""
strDestFolder = Left(objMyFile.Name, InStrRev(objMyFile, "_") - 1)
If Len(Dir(strDestFolder, vbDirectory)) = 0 Then
MkDir strDestFolder
End If
FileCopy strSourceFolder & "\" & objMyFile.Name, strDestFolder & "\" & objMyFile.Name
Kill strSourceFolder & "\" & objMyFile.Name
Loop
Next objMyFile
Set objFSO = Nothing
Set objMyFolder = Nothing
Application.ScreenUpdating = True
End Sub
I've changed your code accordingly to TimWiliams suggestions:
Option Explicit
Sub MoveFiles()
Dim objFSO As Object
Dim objMyFolder As Object
Dim objMyFile As Object
Dim strSourceFolder As String
Dim strDestFolder As String
Dim parts() As String
Dim i As Integer
Application.ScreenUpdating = False
strSourceFolder = "C:\Users\CIB\"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objMyFolder = objFSO.GetFolder(strSourceFolder)
For Each objMyFile In objMyFolder.Files
If objMyFile Is Nothing Then GoTo SkipNext
parts = Split(objMyFile.Name, "_")
strDestFolder = strSourceFolder
For i = LBound(parts) To UBound(parts) - 1
strDestFolder = strDestFolder & parts(i) & "\"
'if path does not exists, create it
If Not objFSO.FolderExists(strDestFolder) Then objFSO.CreateFolder strDestFolder
FileCopy strSourceFolder & "\" & objMyFile.Name, strDestFolder & "\" & objMyFile.Name
Kill strSourceFolder & "\" & objMyFile.Name
strDestFolder = ""
SkipNext:
Next objMyFile
Set objFSO = Nothing
Set objMyFolder = Nothing
Application.ScreenUpdating = True
End Sub

Outlook Save multiple attachments using the subject line, and incrementing that name

I've spent a couple of weeks playing with VBA, I am not by any means an expert on this.
What I'm looking for is a modification of this code.
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 Integer
Dim lngCount As Integer
Dim strFile As String
Dim strFolderpath As String
Dim strFileName As String
Dim objSubject As String
Dim strDeletedFiles As String
' Get the path to your My Documents folder
'strFolderpath = CreateObject("WScript.Shell").SpecialFolders(16)
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
' The attachment folder needs to exist
' You can change this to another folder name of your choice
' Set the Attachment folder.
strFolderpath = "C:\Users\demkep\Documents\"
' Check each selected item for attachments.
For Each objMsg In objSelection
'Set FileName to Subject
objSubject = objMsg.Subject
Set objAttachments = objMsg.Attachments
lngCount = objAttachments.Count
If lngCount > 0 Then
' 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
' Get the file name.
strFileName = objSubject & ".pdf"
' Combine with the path to the Temp folder.
strFile = strFolderpath & strFileName
Debug.Print strFile
' Save the attachment as a file.
objAttachments.Item(i).SaveAsFile strFile
Next i
End If
Next
ExitSub:
Set objAttachments = Nothing
Set objMsg = Nothing
Set objSelection = Nothing
Set objOL = Nothing
End Sub
It is the closest to what I am trying to accomplish.
However when I get an email with multiple attachments, it will simply overwrite the last file. if possible. I'd like it to save (sometimes up to 30 .pdf files) as "emailsubject, emailsubject(1), emailsubject(2), emailsubject(3)" etc...
any help would be appreciated.
You are not changing the filename within the loop. Something like
strFileName = objSubject & "(" & i & ").pdf"
should take care of that.
If you only want numbers if there is more than one attachment you can check lngCount before setting the name or use IIf
If lngCount > 1 Then
strFileName = objSubject & "(" & i & ").pdf"
Else
strFileName = objSubject & ".pdf"
End If
Or
strFileName = objSubject & IIf(lngCount>1, "(" & i & ")", "") & ".pdf"
You shouldn't use On Error Resume Next on your whole sub btw.
Here is Function that will do exactly what you need
Function UniqueName(FilePath As String) As String
Dim FSO As Object
Set FSO = CreateObject("Scripting.FilesystemObject")
Dim FileName As String
FileName = FilePath
Dim Ext As String
Ext = Chr(46) & FSO.GetExtensionName(FilePath)
Dim i As Long
i = 1
Do While FSO.FileExists(FileName)
FileName = Left(FilePath, Len(FilePath) - Len(Ext)) & " (" & i & ")" & Ext
i = i + 1
Loop
UniqueName = FileName
End Function
And change this strFile = strFolderpath & strFileName To strFile = UniqueName(strFolderpath & strFileName)

VBA: Only save the last (The most recent) email attachment in a local folder

I need to save the attachment of last email that has a specific subject (the most recent one) to a local folder, to do this I have created a folder in my Outlook and a rule to send every email with that specific subject to this folder. I have found a code that does what I needed except that it saves every single attachment in the email folder rather than saving only the most recent one. This is the code: how could i modify it so that it does what i need?
Sub Test()
'Arg 1 = Folder name of folder inside your Inbox
'Arg 2 = File extension, "" is every file
'Arg 3 = Save folder, "C:\Users\Ron\test" or ""
' If you use "" it will create a date/time stamped folder for you in your "Documents" folder
' Note: If you use this "C:\Users\Ron\test" the folder must exist.
SaveEmailAttachmentsToFolder "Dependencia Financiera", "xls", "W:\dependencia financiera\test dependencia\"
End Sub
Sub SaveEmailAttachmentsToFolder(OutlookFolderInInbox As String, _
ExtString As String, DestFolder As String)
Dim ns As NameSpace
Dim Inbox As MAPIFolder
Dim SubFolder As MAPIFolder
Dim Item As Object
Dim Atmt As Attachment
Dim FileName As String
Dim MyDocPath As String
Dim i As Integer
Dim wsh As Object
Dim fs As Object
On Error GoTo ThisMacro_err
Set ns = GetNamespace("MAPI")
Set Inbox = ns.GetDefaultFolder(olFolderInbox)
Set SubFolder = Inbox.Folders(OutlookFolderInInbox)
i = 0
' Check subfolder for messages and exit of none found
If SubFolder.Items.Count = 0 Then
MsgBox "There are no messages in this folder : " & OutlookFolderInInbox, _
vbInformation, "Nothing Found"
Set SubFolder = Nothing
Set Inbox = Nothing
Set ns = Nothing
Exit Sub
End If
'Create DestFolder if DestFolder = ""
' If DestFolder = "" Then
' Set wsh = CreateObject("WScript.Shell")
' Set fs = CreateObject("Scripting.FileSystemObject")
' MyDocPath = wsh.SpecialFolders.Item("mydocuments")
' DestFolder = MyDocPath & "\" & Format(Now, "dd-mmm-yyyy hh-mm-ss")
' If Not fs.FolderExists(DestFolder) Then
'fs.CreateFolder DestFolder
' End If
'End If
'If Right(DestFolder, 1) <> "\" Then
'DestFolder = DestFolder & "\"
'End If
' Check each message for attachments and extensions
'JUST BEED TGE FIRST EMAIL
'Debug.Print Item(1).SentOn
For Each Item In SubFolder.Items
For Each Atmt In Item.Attachments
If LCase(Right(Atmt.FileName, Len(ExtString))) = LCase(ExtString) Then
FileName = DestFolder & Atmt.FileName
Atmt.SaveAsFile FileName
'I = I + 1
End If
Next Atmt
Next Item
' Show this message when Finished
' If I > 0 Then
' MsgBox "You can find the files here : " _
& DestFolder, vbInformation, "Finished!"
' Else
' MsgBox "No attached files in your mail.", vbInformation, "Finished!"
' End If
' Clear memory
ThisMacro_exit:
Set SubFolder = Nothing
Set Inbox = Nothing
Set ns = Nothing
Set fs = Nothing
Set wsh = Nothing
Exit Sub
' Error information
ThisMacro_err:
MsgBox "An unexpected error has occurred." _
& vbCrLf & "Please note and report the following information." _
& vbCrLf & "Macro Name: SaveEmailAttachmentsToFolder" _
& vbCrLf & "Error Number: " & Err.Number _
& vbCrLf & "Error Description: " & Err.Description _
, vbCritical, "Error!"
Resume ThisMacro_exit
End Sub
You could try this
Sub SaveEmailAttachmentsToFolder(OutlookFolderInInbox As String, _
ExtString As String, DestFolder As String)
Dim ns As Namespace
Dim Inbox As Folder
Dim SubFolder As Folder
Dim subFolderItems As Items
Dim Atmt As attachment
Dim FileName As String
Set ns = GetNamespace("MAPI")
Set Inbox = ns.GetDefaultFolder(olFolderInbox)
Set SubFolder = Inbox.Folders(OutlookFolderInInbox)
Set subFolderItems = SubFolder.Items
If subFolderItems.count > 0 Then
subFolderItems.Sort "[ReceivedTime]", True
For Each Atmt In subFolderItems(1).Attachments
If LCase(Right(Atmt.FileName, Len(ExtString))) = LCase(ExtString) Then
FileName = DestFolder & Atmt.FileName
Atmt.SaveAsFile FileName
End If
Next Atmt
End If
' Clear memory
ThisMacro_exit:
Set SubFolder = Nothing
Set Inbox = Nothing
Set ns = Nothing
Set subFolderItems = Nothing
End Sub
Consider ItemAdd. The most recent item is already known. How do I trigger a macro to run after a new mail is received in Outlook?

Saving Outlook email as PDF + Attachments, without overwriting when names are duplicated

I save incoming mail with an inbox rule and VBA code.
When there are multiple emails with the same name and also if the attachments have the same name they overwrite each other.
I need both the email and the attachments to loop through 1-10. There can be up to ten emails and attachments with the same names.
Sub SaveAsMsg(MyMail As MailItem)
' requires reference to Microsoft Scripting Runtime
' \Windows\System32\Scrrun.dll
' Also requires reference to Microsoft Word Object Library
Dim fso As FileSystemObject
Dim strSubject As String
Dim strSaveName As String
Dim blnOverwrite As Boolean
Dim strFolderPath As String
Dim looper As Integer
Dim strID As String
Dim olNS As Outlook.NameSpace
Dim oMail As Outlook.MailItem
strID = MyMail.EntryID
Set olNS = Application.GetNamespace("MAPI")
Set oMail = olNS.GetItemFromID(strID)
'Get Sender email domain
sendEmailAddr = oMail.SenderEmailAddress
companyDomain = Right(sendEmailAddr, Len(sendEmailAddr) - InStr(sendEmailAddr, "#"))
' ### USER OPTIONS ###
blnOverwrite = False ' False = don't overwrite, True = do overwrite
'### THIS IS WHERE SAVE LOCATIONS ARE SET ###
'Currently only saves to yPath. Change the yPath variable to mPath in other areas of the script to enable the month folder.
bPath = "C:\email\" 'Defines the base path to save the email
cPath = bPath & companyDomain & "\" 'Adds company domain to base path
yPath = cPath & Format(Now(), "yyyy") & "\" 'Add year subfolder
mPath = yPath & Format(Now(), "MMMM") & "\" 'Add month subfolder
'### Path Validity ###
'Make sure base path exists
If Dir(bPath, vbDirectory) = vbNullString Then
MkDir bPath
End If
'Make sure company domain path exists
'If Dir(cPath, vbDirectory) = vbNullString Then
'MkDir cPath
'End If
'Make sure year path exists
'If Dir(yPath, vbDirectory) = vbNullString Then
'MkDir yPath
'End If
'Make sure month path exists (uncomment below lines to enable)
'If Dir(mPath, vbDirectory) = vbNullString Then
'MkDir mPath
'End If
'### Get Email subject & set name to be saved as ###
emailSubject = CleanFileName(oMail.Subject)
saveName = Format(oMail.ReceivedTime, "yyyymmdd") & "_" & emailSubject & ".txt"
Set fso = CreateObject("Scripting.FileSystemObject")
'### If don't overwrite is on then ###
If blnOverwrite = False Then
looper = 0
Do While fso.FileExists(yPath & saveName)
looper = looper + 1
saveName = Format(oMail.ReceivedTime, "yyyymmdd") & "_" & emailSubject & "_" & looper & ".txt"
Loop
Else '### If don't overwrite is off, delete the file ###
If fso.FileExists(yPath & saveName) Then
fso.DeleteFile yPath & saveName
End If
End If
'### Save MSG File ###
oMail.SaveAs bPath & saveName, olTXT
'### If Mail Attachments: clean file name, save into path ###
If oMail.Attachments.Count > 0 Then
For Each atmt In oMail.Attachments
atmtName = CleanFileName(atmt.FileName)
atmtSave = bPath & Format(oMail.ReceivedTime, "yyyymmdd") & "_" & atmtName
atmt.SaveAsFile atmtSave
Next
End If
Set oMail = Nothing
Set olNS = Nothing
Set fso = Nothing
End Sub
Function CleanFileName(strText As String) As String
Dim strStripChars As String
Dim intLen As Integer
Dim i As Integer
strStripChars = "/\[]:=," & Chr(34)
intLen = Len(strStripChars)
strText = Trim(strText)
For i = 1 To intLen
strText = Replace(strText, Mid(strStripChars, i, 1), "")
Next
CleanFileName = strText
End Function
Sub SaveAsPDF(MyMail As MailItem)
' requires reference to Microsoft Scripting Runtime
' \Windows\System32\Scrrun.dll
' Also requires reference to Microsoft Word Object Library
Dim fso As FileSystemObject
Dim strSubject As String
Dim strSaveName As String
Dim blnOverwrite As Boolean
Dim strFolderPath As String
Dim looper As Integer
Dim strID As String
Dim olNS As Outlook.NameSpace
Dim oMail As Outlook.MailItem
strID = MyMail.EntryID
Set olNS = Application.GetNamespace("MAPI")
Set oMail = olNS.GetItemFromID(strID)
'Get Sender email domain
sendEmailAddr = oMail.SenderEmailAddress
companyDomain = Right(sendEmailAddr, Len(sendEmailAddr) - InStr(sendEmailAddr, "#"))
' ### USER OPTIONS ###
blnOverwrite = False ' False = don't overwrite, True = do overwrite
'### THIS IS WHERE SAVE LOCATIONS ARE SET ###
bPath = "C:\email\" 'Defines the base path to save the email
cPath = bPath & companyDomain & "\" 'Adds company domain to base path
yPath = cPath & Format(Now(), "yyyy") & "\" 'Add year subfolder
mPath = yPath & Format(Now(), "MMMM") & "\" 'Add month subfolder
'### Path Validity ###
If Dir(bPath, vbDirectory) = vbNullString Then
MkDir bPath
End If
'If Dir(cPath, vbDirectory) = vbNullString Then
' MkDir cPath
'End If
'If Dir(yPath, vbDirectory) = vbNullString Then
' MkDir yPath
'End If
'### Get Email subject & set name to be saved as ###
emailSubject = CleanFileName(oMail.Subject)
saveName = Format(oMail.ReceivedTime, "yyyy-mm-dd-hhmm") & "_" & emailSubject & ".mht"
Set fso = CreateObject("Scripting.FileSystemObject")
'### If don't overwrite is on then ###
If blnOverwrite = False Then
looper = 0
Do While fso.FileExists(bPath & saveName)
looper = looper + 1
saveName = Format(oMail.ReceivedTime, "yyyy-mm-dd-hhmm") & "_" & emailSubject & "_" & looper & ".mht"
pdfSave = Format(oMail.ReceivedTime, "yyyy-mm-dd-hhmm") & "_" & emailSubject & "_" & looper & ".pdf"
Loop
Else '### If don't overwrite is off, delete the file ###
If fso.FileExists(bPath & saveName) Then
fso.DeleteFile bPath & saveName
End If
End If
oMail.SaveAs bPath & saveName, olMHTML
pdfSave = bPath & Format(oMail.ReceivedTime, "yyyy-mm-dd-hhmm") & "_" & emailSubject & ".pdf"
'### Open Word to convert file to PDF ###
Dim wrdApp As Word.Application
Dim wrdDoc As Word.Document
Set wrdApp = CreateObject("Word.Application")
Set wrdDoc = wrdApp.Documents.Open(FileName:=bPath & saveName, Visible:=True)
wrdApp.ActiveDocument.ExportAsFixedFormat OutputFileName:= _
pdfSave, ExportFormat:= _
wdExportFormatPDF, OpenAfterExport:=False, OptimizeFor:= _
wdExportOptimizeForPrint, Range:=wdExportAllDocument, From:=0, To:=0, _
Item:=wdExportDocumentContent, IncludeDocProps:=True, KeepIRM:=True, _
CreateBookmarks:=wdExportCreateNoBookmarks, DocStructureTags:=True, _
BitmapMissingFonts:=True, UseISO19005_1:=False
wrdDoc.Close
wrdApp.Quit
'### Clean up files ###
With New FileSystemObject
If .FileExists(bPath & saveName) Then
.DeleteFile bPath & saveName
End If
End With
'### If Mail Attachments: clean file name, save into path ###
If oMail.Attachments.Count > 0 Then
For Each atmt In oMail.Attachments
atmtName = CleanFileName(atmt.FileName)
atmtSave = bPath & Format(oMail.ReceivedTime, "yyyy-mm-dd-hhmm") & "_" & atmtName
atmt.SaveAsFile atmtSave
Next
End If
Set oMail = Nothing
Set olNS = Nothing
Set fso = Nothing
End Sub
This works really well once you delete the if statements that delete the file. Thank you for the foundation.
I've modified the PDF portion of your code (for the better, I hope) and fixed an issue that the pdf filename would not increment if it existed already. I had to write a separate loop for the PDF because you basically stopped the loop with this line: pdfSave = bPath & Format(oMail.ReceivedTime, "yyyy-mm-dd-hhmm") & "_" & emailSubject & ".pdf" but I can't seem to get rid of that line without producing an error so made a new loop. Maybe someone can simplify that part for me.
I've also added a line to delete the .mht file only used to create the PDF and modified the filenames a bit:
Function CleanFileName(strText As String) As String
Dim strStripChars As String
Dim intLen As Integer
Dim i As Integer
strStripChars = "/\[]:=," & Chr(34)
intLen = Len(strStripChars)
strText = Trim(strText)
For i = 1 To intLen
strText = Replace(strText, Mid(strStripChars, i, 1), "")
Next
CleanFileName = strText
End Function
Sub SaveAsPDF(MyMail As MailItem)
' ### Requires reference to Microsoft Scripting Runtime ###
' ### Requires reference to Microsoft Word Object Library ###
' --- In VBE click TOOLS > REFERENCES and check the boxes for both of the above ---
Dim fso As FileSystemObject
Dim strSubject As String
Dim strSaveName As String
Dim blnOverwrite As Boolean
Dim strFolderPath As String
Dim sendEmailAddr As String
Dim senderName As String
Dim looper As Integer
Dim plooper As Integer
Dim strID As String
Dim olNS As Outlook.NameSpace
Dim oMail As Outlook.MailItem
Dim bPath, EmailSubject, saveName, pdfSave As String
strID = MyMail.EntryID
Set olNS = Application.GetNamespace("MAPI")
Set oMail = olNS.GetItemFromID(strID)
' ### Get username portion of sender email address ###
sendEmailAddr = oMail.SenderEmailAddress
senderName = Left(sendEmailAddr, InStr(sendEmailAddr, "#") - 1)
' ### USER OPTIONS ###
blnOverwrite = False ' False = don't overwrite, True = do overwrite
' ### Path to save directory ###
bPath = "Z:\email\"
' ### Create Directory if it doesnt exist ###
If Dir(bPath, vbDirectory) = vbNullString Then
MkDir bPath
End If
' ### Get Email subject & set name to be saved as ###
emailSubject = CleanFileName(oMail.Subject)
saveName = Format(oMail.ReceivedTime, "yyyy-mm-dd-hhmm") & "_" & emailSubject & ".mht"
Set fso = CreateObject("Scripting.FileSystemObject")
' ### Increment filename if it already exists ###
If blnOverwrite = False Then
looper = 0
Do While fso.FileExists(bPath & saveName)
looper = looper + 1
saveName = Format(oMail.ReceivedTime, "yyyy-mm-dd-hhmm") & "_" & senderName & "_" & emailSubject & "_" & looper & ".mht"
Loop
Else
End If
' ### Save .mht file to create pdf from Word ###
oMail.SaveAs bPath & saveName, olMHTML
pdfSave = bPath & Format(oMail.ReceivedTime, "yyyy-mm-dd-hhmm") & "_" & senderName & "_" & emailSubject & ".pdf"
If fso.FileExists(pdfSave) Then
plooper = 0
Do While fso.FileExists(pdfSave)
plooper = plooper + 1
pdfSave = bPath & Format(oMail.ReceivedTime, "yyyy-mm-dd-hhmm") & "_" & senderName & "_" & emailSubject & "_" & plooper & ".pdf"
Loop
Else
End If
' ### Open Word to convert .mht file to PDF ###
Dim wrdApp As Word.Application
Dim wrdDoc As Word.Document
Set wrdApp = CreateObject("Word.Application")
' ### Open .mht file we just saved and export as PDF ###
Set wrdDoc = wrdApp.Documents.Open(FileName:=bPath & saveName, Visible:=True)
wrdApp.ActiveDocument.ExportAsFixedFormat OutputFileName:= _
pdfSave, ExportFormat:= _
wdExportFormatPDF, OpenAfterExport:=False, OptimizeFor:= _
wdExportOptimizeForPrint, Range:=wdExportAllDocument, From:=0, To:=0, _
Item:=wdExportDocumentContent, IncludeDocProps:=True, KeepIRM:=True, _
CreateBookmarks:=wdExportCreateNoBookmarks, DocStructureTags:=True, _
BitmapMissingFonts:=True, UseISO19005_1:=False
wrdDoc.Close
wrdApp.Quit
' ### Delete .mht file ###
Kill bPath & saveName
' ### Uncomment this section to save attachments ###
'If oMail.Attachments.Count > 0 Then
' For Each atmt In oMail.Attachments
' atmtName = CleanFileName(atmt.FileName)
' atmtSave = bPath & Format(oMail.ReceivedTime, "yyyy-mm-dd-hhmm") & "_" & atmtName
' atmt.SaveAsFile atmtSave
' Next
'End If
Set oMail = Nothing
Set olNS = Nothing
Set fso = Nothing
End Sub
I have noticed the following lines of code:
strID = MyMail.EntryID
Set olNS = Application.GetNamespace("MAPI")
Set oMail = olNS.GetItemFromID(strID)
There is no need to get a new instance of the MailItem class. You can use the instance passed as a parameter.
If fso.FileExists(bPath & saveName) Then
fso.DeleteFile bPath & saveName
It looks like you delete existing files instead of saving a new ones with different names.
You may consider using the datetime (not only the date) marker when saving emails/attachments. Or you may check out whether such file exists on the disk already.