A visitor to our forums had a script to save attachments to his hard drive and wanted to add the attachment's modified date to the filename.
To get the modified date (or any other file property), you need to use the FileSystem Object, or FSO, to read the properties.
Instead of using the file's modified date, or if Outlook is not getting the expected modified date, you can use the email message's sent date. In many cases, the DateLastModified on the attachments will be the Sent date anyway. A macro using the SentOn field is here.
The first macro saves the attachments on selected messages and changes the names of the saved files to include the modified date. The second macro is used as the script in a rule a script rule.
The macros save the attachments to a subfolder under the user's Documents folder.
If you want to save the attachment in a folder by date, subject name, sender, etc, you would use the filescripting object to create a folder if one does not exist.
This macro saves the attachments on one or more selected messages.
Save & Rename Attachment with Subject
This macro renames the attachment as it is saved. Because it uses the message subject, we need to check for characters not supported as file system names and replace them.
We also need to get the file extension and add it to the filename. While you can use InStr to find the dot and use that to get just the last 4 or 5 characters (the dot and the extension), this sample gets the last 5. If the extension is 3 characters ( pdf, zip etc), it will include the last letter of the original file name.
Public Sub saveAttachtoDisk() Dim itm As Outlook.MailItem Dim currentExplorer As Explorer Dim Selection As Selection Dim strSubject As String, strExt As String Dim objAtt As Outlook.Attachment Dim saveFolder As String Dim enviro As String enviro = CStr(Environ("USERPROFILE")) saveFolder = enviro & "\Documents\Attachments\" Set currentExplorer = Application.ActiveExplorer Set Selection = currentExplorer.Selection For Each itm In Selection For Each objAtt In itm.Attachments ' get the last 5 characters for the file extension strExt = Right(objAtt.DisplayName, 5) ' clean the subject strSubject = itm.Subject ReplaceCharsForFileName strSubject, "-" ' put the name and extension together file = saveFolder & strSubject & strExt objAtt.SaveAsFile file Next Next Set objAtt = Nothing End Sub Private Sub ReplaceCharsForFileName(sName As String, _ sChr As String _ ) sName = Replace(sName, "'", sChr) sName = Replace(sName, "*", sChr) sName = Replace(sName, "/", sChr) sName = Replace(sName, "\", sChr) sName = Replace(sName, ":", sChr) sName = Replace(sName, "?", sChr) sName = Replace(sName, Chr(34), sChr) sName = Replace(sName, "<", sChr) sName = Replace(sName, ">", sChr) sName = Replace(sName, "|", sChr) End Sub
Use in a Run a Script Rule
This script is used in a run a script rule. It adds today's date to the attachment filename.
Public Sub saveAttachtoDiskRule(itm As Outlook.MailItem) Dim strSubject As String, strExt As String Dim objAtt As Outlook.Attachment Dim saveFolder As String Dim enviro As String enviro = CStr(Environ("USERPROFILE")) saveFolder = enviro & "\Documents\Attachments\" For Each objAtt In itm.Attachments DateFormat = Format(Date, "yyyy-mm-dd ") file = saveFolder & DateFormat & objAtt.DisplayName objAtt.SaveAsFile file Next Set objAtt = Nothing End Sub
Increment the filename
This version of the macro adds a number to the filename if the filename already exists in the folder, like this:
Change the string: FnName & x & fileext as needed. For example, if you want to the filenames in this format: 2015-06-12 error (2).png format, use FnName & " (" & x & ")" & fileext.
Public Sub saveAttachtoDisk() Dim itm As Outlook.MailItem 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\" Set currentExplorer = Application.ActiveExplorer Set Selection = currentExplorer.Selection Set fso = CreateObject("Scripting.FileSystemObject") On Error Resume Next For Each itm In Selection 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 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
Increment files name using Rules
For a run a script version of the above macro, you need to change the macro name and remove the code that works with the selected messages.
Public Sub saveAttachtoDiskRule(itm As Outlook.MailItem) Dim strSubject As String, strExt As String Dim objAtt As Outlook.Attachment Dim saveFolder As String Dim enviro As String enviro = CStr(Environ("USERPROFILE")) saveFolder = enviro & "\Documents\Attachments\" 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 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
How to use macros
First: You will need macro security set to low during testing.
To check your macro security in Outlook 2010 or 2013, go to File, Options, Trust Center and open Trust Center Settings, and change the Macro Settings. In Outlook 2007 and older, it’s at Tools, Macro Security.
After you test the macro and see that it works, you can either leave macro security set to low or sign the macro.
Open the VBA Editor by pressing Alt+F11 on your keyboard.
To put the code in a module:
- Right click on Project1 and choose Insert > Module
- Copy and paste the macro into the new module.
More information as well as screenshots are at How to use the VBA Editor
More Information
More Run a Script Samples:
- Autoaccept a Meeting Request using Rules
- Automatically Add a Category to Accepted Meetings
- Blocking Mail From New Top-Level Domains
- Convert RTF Messages to Plain Text Format
- Create a rule to delete mail after a number of days
- Create a Task from an Email using a Rule
- Create an Outlook Appointment from a Message
- Create Appointment From Email Automatically
- Delegates, Meeting Requests, and Rules
- Delete attachments from messages
- Forward meeting details to another address
- How to Change the Font used for Outlook's RSS Feeds
- How to Process Mail After Business Hours
- Keep Canceled Meetings on Outlook's Calendar
- Macro to Print Outlook email attachments as they arrive
- Move messages CC'd to an address
- Open All Hyperlinks in an Outlook Email Message
- Outlook AutoReplies: One Script, Many Responses
- Outlook's Rules and Alerts: Run a Script
- Process messages received on a day of the week
- Read Outlook Messages using Plain Text
- Receive a Reminder When a Message Doesn't Arrive?
- Run a script rule: Autoreply using a template
- Run a script rule: Reply to a message
- Run a Script Rule: Send a New Message when a Message Arrives
- Run Rules Now using a Macro
- Run-a-Script Rules Missing in Outlook
- Save all incoming messages to the hard drive
- Save and Rename Outlook Email Attachments
- Save Attachments to the Hard Drive
- Save Outlook Email as a PDF
- Sort messages by Sender domain
- Talking Reminders
- To create a rule with wildcards
- Use a Macro to Copy Data in an Email to Excel
- Use a Rule to delete older messages as new ones arrive
- Use a run a script rule to mark messages read
- Use VBA to move messages with attachments
Hello,
Can I set the subject as below?
Attachment file name : abc
Subject : HAWB: abc PODRT
I just want to say thank you! This was so easy to follow and saved me a TON of manual work. Very much appreciated.
Hello Diane, please, do you know if there is any way to rename the attachments of an email without exporting, renaming and then importing them; that is to say renaming them directly into the email?
Thank you in advance.
Yohann
The attachment needs to be saved to a temp folder to rename it - but a macro can save it, rename it and put it back. You need a dialog box asking for the new name or use a scheme to rename it automatically (like add the date or your initials to the existing name).
Here is a macro to change the attachment name in either incoming or when composing a message.
https://www.slipstick.com/developer/code-samples/rename-outlook-attachments/
Many thanks Diane.
Hi Team, Currently I am looking for a macro to save the attachments to a folder and rename the file names by adding prefix (FROM,SUBJECT, RECEIVED DATE AND TIMING & ONE MORE COLUMN WHICH IS REMARKS newly inserted in outlook which needs to be counted in the filename as prefix of the file name.
the default fields are no problem - you will definitely need to run it through an illegal character function to remove characters not supported in file names.
For a custom field, you need to use a userproperties field. An example is here:
https://www.slipstick.com/tutorial/create-a-custom-field-to-mark-messages/#macro
If I am running following Macro as rule in Outlook it works fine: Public Sub SaveAttachmentsToDisk(itm As Outlook.MailItem) Dim objAtt As Outlook.Attachment Dim saveFolder As String saveFolder = "C:\A_DANO\TEST\" For Each objAtt In itm.Attachments dateFormat = Format(Date, "yyyy-mm-dd ") file = saveFolder & dateFormat & objAtt.DisplayName objAtt.SaveAsFile file Next Set objAtt = Nothing End Sub but if I am runnign following Marco in Outlook - to save file and rename based on Subject it does nothing - no error - no files saved at all Public Sub SaveAttachmentsToDisk(itm As Outlook.MailItem) Dim itm As Outlook.MailItem Dim currentExplorer As Explorer Dim Selection As Selection Dim strSubject As String, strExt As String Dim objAtt As Outlook.Attachment Dim saveFolder As String saveFolder = "C:\TEST\" Set currentExplorer = Application.ActiveExplorer Set Selection = currentExplorer.Selection For Each itm In Selection For Each objAtt In itm.Attachments ' get the last 5 characters for the file extension strExt = Right(objAtt.DisplayName, 5) ' clean the subject strSubject = itm.Subject ReplaceCharsForFileName strSubject, "-" ' put the name and extension together file = saveFolder & strSubject & strExt objAtt.SaveAsFile file Next Next Set objAtt = Nothing End Sub Private Sub ReplaceCharsForFileName(sName As String, _ sChr As String _ ) sName = Replace(sName,… Read more »
Is the name correct? Right after file = saveFolder & strSubject & strExt, add msgbox file and test it. Is the filename the expected name?
(I'll test it here in a bit.)
The problem that I am having is it gives me a run-time error that it cannot find the file i want the attachment saved in. I have to hit "end" every time I get a fax/email and it then pushes the attachment to the folder.
But I have to hit end every time. If I hit debug, it says it's caught up on...
objAtt.SaveAsFile saveFolder _
& Format(itm.ReceivedTime, "mmdd~hhmmss~") _
& Mid(itm.Subject, 11, 12) _
& Right(objAtt.FileName, 4)
I am lost and have been trying to fix this since we upgraded our Outlook.
Add debug.print saveFolder _
& Format(itm.ReceivedTime, "mmdd~hhmmss~") _
& Mid(itm.Subject, 11, 12) _
& Right(objAtt.FileName, 4)
right before the saveasfile line - then check the immediate window (turn it on from the View menu) - is the path correct?
Still makes me hit end. It pushes the attachment into the folder before I do so, but it won't move on in Outlook until I either hit end or debug.
The path is correct. I am having it save attachments to a shared drive so that my department will have access to the faxes if I'm not in the office. It has been working fine for a few years until we upgraded to Office365 recently. Now, this is happening and I have queries in Access that quit working.
Here is the entire code (before the debug you suggested), maybe you can see something I can't. Any help is very much appreciated!!
Public Sub Save_Fax_to_W(itm As Outlook.MailItem)
Dim objAtt As Outlook.Attachment
Dim saveFolder As String
saveFolder = "W:\FAXES - Not Logged\"
For Each objAtt In itm.Attachments
objAtt.SaveAsFile saveFolder _
& Format(itm.ReceivedTime, "mmdd~hhmmss~") _
& Mid(itm.Subject, 11, 12) _
& Right(objAtt.FileName, 4)
' subject: Fax from [765-281-3436]...
' filename: 0307~163645~765-281-3436.pdf
Set objAtt = Nothing
Next
End Sub
Does it work as expected if you use a local drive? i know there can be issues with network drives.
Clarification: When two conditions are met (Sender and Attachment name), I'd like the saved attachment to be renamed 'XYZ A great site 08-11-2017 and saved into a dynamic path.
Sorry about that.
once you get the values you can use them in any way you want -
filename = attachment.name & strsubject & format(Date, "mm-dd-yyyy") & ".xlxs"
(you may need to strip the extension from the attachment.name first - again, not hard to do - strname = left(attachment.name, 5)
Thank you for the response! I'm still struggling through this. I can't get either lchar or regex to work at all, so I have the full subject line included on the saved file. Also, with the script below there are 3 additional .bin excel files that are created each run. Public Sub saveAttachtoDisk() Dim itm As Outlook.MailItem Dim currentExplorer As Explorer Dim Selection As Selection Dim objAtt As Outlook.Attachment Dim saveFolder As String Dim fso As Object Dim oldName Dim strsubject As String Dim lchar As String strsubject = ActiveExplorer.Selection.Item(1).Subject Dim enviro As String enviro = CStr(Environ("USERPROFILE")) saveFolder = enviro & "DesktopTest" Set currentExplorer = Application.ActiveExplorer Set Selection = currentExplorer.Selection Set fso = CreateObject("Scripting.FileSystemObject") On Error Resume Next For Each itm In Selection For Each objAtt In itm.Attachments file = saveFolder & objAtt.DisplayName objAtt.SaveAsFile file 'Get the file name Set oldName = fso.GetFile(file) 'Can not get any variation to work, or with regex If lchar = InStr(1, strsubject, "{") Then strsubject = Right(strsubject, Len(strsubject) - lchar) End If 'somehow now creates 3 additional unwanted Excel files newName = Left(oldName.Name, 19) & " " & strsubject & Format(Now, " mm-dd-yyyy") & ".xlsx" oldName.Name = newName Next Next Set objAtt = Nothing… Read more »
Any error messages?
The lchar stuff may need to be tweaked - i didn't test it. Will try to test it over the weekend.
oh, i see the problem - it's not an if.
get the position of the ( using this:
lchar = InStr(1, strsubject, "{")
then get the right most part of the subject by subtracting the position from the length of the entire subject:
strsubject = Right(strsubject, Len(strsubject) - lchar)
This might need to be tweaked - Len(strsubject) - lchar - but you won't know until you test it. if its way off, try
lchar = InStrRev(1, strsubject, "{")
(InstrRev counts from the right.)
Works exactly as I hoped for, thank you! Added a kill command to get rid of the additional files that were being created.
Thanks again!
Hi Diane,
Your coding is beautiful. Thank you for sharing. I'm trying to use the above with a twist. I'd like to take the attachment name and combine with all words to the right of an illegal character from the subject line (which the length of words will vary), and add the date. And then save to a daily folder.
Ex:
From: ABC
Subject: this is{A great site
Attachment: ZYZ.xlsx
When two conditions are met (Sender and Attachment name), I'd like the saved attachment to be renamed 'ABC A great site 08-11-2017 and saved into a dynamic path. The path I use in Excel VBA is Desktop" & "" & Year(Now) & "" & MonthName(Month(Now), True) & "" & Month(Now) & Day(Now) & "" & Range("A11").Text.
Thanks for any help you can provide.
You'll need to use instr function to get the location of the character (assume its the same character every time) then right function to get the text - or you could use regex to get the string to the right - this would allow you to easily look for different characters.
lChar = instr(1,item.subject, "(")
then
strsubject = right(item.subject, len(item.subject) - lChar)
for the date, you can use what you are using now or format(Date, "yyyymmmdd") ' 2017Aug16