Strip Outlook Attachments and Replace with Links
UPDATE OCT 2009: Reader jumpjack has created a Google Code project for this macro. You can download the latest source code on the project page.
_________________________________________
There are many good reasons to strip attachments from your email messages. The main reason for me is that I often embed email messages into my Outlook tasks for quick reference. Since some tasks have multiple emails (each with multiple attached files), I need a way to keep the task size manageable. So, I simply strip the attachments before embedding the email into the task. Another reason to strip attachments is to improve Outlook performance. Smaller PST files are less likely to be corrupted and are faster to search and index.
The Outlook VBA macro below is one easy way to strip attachments from your messages. Simply select one or more messages in the Outlook explorer window, then activate the macro. The result is shown in the screen shot below. As you can see, all of the attachments throughout the email are numbered and replaced with links at the top of the message. There is even a hyperlink to the folder containing the attachments. The macro also saves a text copy of the original email message along with the attachments for future reference.
You’ll notice that there is still one small attachment remaining called “Attachments Removed”. This is added so that the paperclip icon in Outlook is still active, which indicates that the message has (or had) attachments.
The attachments archive folder is organized with one folder per email, as shown below. The folders are named using the date of the message, the sender name, and the subject line. At the end of the year, you can grab the whole collection and zip it up for archive purposes. Since the links are hard coded into the emails, you’ll want to be consistent with your folder locations. That is why I simply use “C:\Outlook Attachments\” along with the year. If I ever want to restore some old messages and be able to browse the file attachments, I know exactly where to put them.
Ok, so here is an excerpt of the code. Download the full version (link to zip file below). Unzip and place the “Outlook Attachments” folder at your C:\ root. This will give you a copy of the 0 kb “Attachments Removed” file in the right location for the macro to use. Next, paste the code from the text file into any module in your Visual Basic Editor.
Public Sub StripAttachments_Explorer()
'This VBA Macro removes attachments from whatever emails are selected
'in the Outlook explorer window and stores them on the hard drive. Links
'to the stored files are added to the email. Note that RTF and PlainText
'messages are converted to HTML. The hooks are still below if you want to
'uncomment those line and handle text messages separately.
'Tested with Outlook 2003 only.
'v1.3, Carl C, 22-Feb-09
'http://manage-this.com
'
On Error GoTo ErrorHandler
'
'Edit this path to point to the root for your archive. This
'folder must already exist before for you start using this tool.
'Choose a root folder that is easy to remember for restoring
'message attachments later since the message bodies will be
'written with hard links to this location.
Const RootFolder = "C:\\Outlook Attachments\\2009\\"
'
'Threshold message size (in kilobytes) - Messages smaller than this get skipped.
Const THRESH As Long = 100 'kb
'
Dim olns As Outlook.NameSpace
Dim objMsg As Object
Dim objAttachments As Outlook.Attachments
Dim objSelectedItems As Outlook.Selection
Dim i, J, Counter As Integer
Dim msgFormat As Long
Dim Header, FileList, Footer As String
Dim attPath, attFileName, msgFolder, msgSender, msgSubject, yearFolder, temp As String
Dim oleFound, dropSubject As Boolean
'
Set olns = Application.GetNamespace("MAPI")
'
Set objSelectedItems = olns.Application.ActiveExplorer.Selection
'
'Make sure base path exists
If Dir(RootFolder, vbDirectory) = "" Then
MsgBox "Root Folder Not Found!" & vbCrLf & _
"Please create the following folder first: " & vbCrLf & RootFolder
GoTo ExitSub
End If
'
For Each objMsg In objSelectedItems
'
' Skip anything that's not a mail message (calendar items, tasks, etc.)
If objMsg.Class = olMail Then
'
Set objAttachments = objMsg.Attachments
Counter = objAttachments.Count
'
'Only execute if there is at least one attachment in the message
If Counter > 0 Then
'
'Check if the attachments have already been removed - if so, don't do it again
If objAttachments.Item(1).Type <> olOLE Then
If (objAttachments.Item(1).FileName = "Attachments Removed") _
And (Counter = 1) Then
GoTo TheNextMessage
End If
End If
'
'If the current message is fairly small, then skip it. It likely containts only
'tiny pics in the signature or a background image. No point in stripping those.
'Note - It would be better to check the size of each attachment, but there is no
'clean way to do this in Outlook 2003. Would require PR_ATTACH_SIZE (0x0E200003)
'property of the attachment... See http://www.cdolive.com/cdo10.htm
If (objMsg.Size < (1024 * THRESH)) Then
GoTo TheNextMessage
End If
'
'Check to see if any of the attachments are OLE format. If so, skip the
'entire message since stripping these is messy
oleFound = False
For i = objAttachments.Count To 1 Step -1
If objAttachments.Item(i).Type = olOLE Then
oleFound = True
Exit For
End If
Next i
If oleFound Then GoTo TheNextMessage
'
'Note - I disabled the year folder since it had to be checked for every
'message. Added it to the Root Path definition instead.
'
'Create the year folder if it doesn't already exist
'yearFolder = RootFolder & Strings.Format(objMsg.ReceivedTime, "yyyy") & "\\"
'If Dir(yearFolder, vbDirectory) = "" Then
' MkDir (yearFolder)
'End If
'
'Some of the dual-byte (DBCS) chars cause problems since the subject line is
'used in the file path name. If the message format does not belong to one of
'the formats below, then don't use the subject line in the path or file name.
dropSubject = False
msgFormat = objMsg.InternetCodepage
If ((msgFormat = 28592) Or (msgFormat = 1250) Or (msgFormat = 20127) _
Or (msgFormat = 28591) Or (msgFormat = 1252)) Then
msgSubject = objMsg.Subject
Else
msgSubject = "message"
dropSubject = True
End If
'
'Strip illegal chars from msgSubject
invalidChars = Array("\", "/", ":", "*", "?", """", "<", ">", "|", "…")
For J = LBound(invalidChars) To UBound(invalidChars)
temp = Replace(msgSubject, invalidChars(J), " ")
msgSubject = temp
Next J
msgSubject = Replace(msgSubject, "RE ", "")
msgSubject = Replace(msgSubject, "FW ", "")
'
'
'CODE CONTINUES FOR MANY MORE LINES...
'CLICK LINK BELOW TO DOWNLOAD FULL VERSION...
DOWNLOAD THE CODE: Email Attachments Stripper v1.3
NOTE: Version 1.3 will remain hosted here, but the source is being moved to Google Code as of Oct 2009. The latest version will be available on the project page here.
Note that this has only been tested with Outlook 2003 and Windows XP. If you have a different system configuration, it may require some tweaks. Thanks especially to Sue Mosher and her outstanding web site, OutlookCode.com. Many examples scattered throughout her site were used to create this tool.
To make this tool easier to use, I would also recommend adding a shortcut button to one of your Outlook menu bars. I like to use the little disk icon with the down arrow (shown below).

Yes, there are some other super-secret icons on that menu bar that will be revealed in future posts. In the mean time, have fun stripping!
-Carl



October 11, 2009 - 10:37 am
Sam – The error message you mentioned might be related to the object type, as jumpjack mentioned. I would try debugging as he suggested. In order to allow the Outlook debugger to trigger, you will have to comment out this line near the top of the macro:
On Error GoTo ErrorHandler
Also, there is currently an issue with running this macro on 100+ messages at once (at least if all 100 have attachments). See comments above from September 17th, 2009 at 12:27 pm. If you run this on a folder with 3000 emails I’m sure you will see this issue. I don’t have a workaround for this yet.
-Carl
October 11, 2009 - 10:49 am
jumpjack –
Thanks again for your comments. You had also asked about going back to messages that were previously processed and re-processing them to have shorter links. I think that will be very tricky. There is a field I added to the links to help you search on ones created by this macro. If you notice in the code, the file links contain a reference “REL=ATT_LNK” to help identify them. “ATT_LNK” was just something I made up in case I had to search for those links later. You could create a separate macro that searches the HTML body of each message and edits those links if they are too long based on certain criteria. The problem, however, is that the actual path names on disk will then not match and you will have broken links. (Unless I am misunderstanding your question?) Creating a macro that changed both the links inside the message and the real folder path on disk would be a lot of work. I think it would be easiest to just retrieve those attachments where you have path length errors by manually browsing for the folder. Since only certain messages would be affected, and the folders are named/sorted by the message date, it should be relatively easy to find. I just don’t think it would be worth your time to go backwards and try to re-process older messages.
-Carl
October 13, 2009 - 8:15 am
Carl,
yes, that’s what I was asking for. Of course I should also rename the folders to make them manageable by new outlook links.
Or maybe I should just edit folders names to get them down to 256 characters?
Two more questions:
1 – Doesn’t dis blog notify users about replies to comments?!?
2 – Isn’t it time to put this project on GoogleCode for better management?
http://code.google.com
October 13, 2009 - 8:21 am
For some reason, it looks like Outlook does not like links containing “#” characters: my broken links are NOT too long links, but links including this character, whose corresponding folders have name ending at the character right before the “#”.
???
October 13, 2009 - 6:07 pm
jumpjack – Here are some responses to your questions & comments…
[0] I guess I assumed you would not want to edit the folder names. Depending on how many folders you would have to edit (10, 100, 1000?) it may not be worth the effort.
[1] Regarding the notifications, unfortunately that’s not available. I thought about disabling comments altogether and instead implementing a forum. It’s great that there is more interactive discussion going on, and that would probably be easier to do with a proper forum.
[2] I think it would be good to move the macro to someplace like GoogleCode or SourceForge. Unfortunately I don’t have the time to set it up or maintain it. If you are motivated to do it, it’s all yours! All I would ask is that you keep a reference link back to the original post here.
[3] Very good catch on the “#” character, nice work! I haven’t run into that problem, but was able to reproduce it after you pointed it out. The “#” is a valid path/file name character in Windows, so I’m not sure why Outlook is choking on it. The easiest fix is to just add it to the invalid character list on this line:
invalidChars = Array(“\”, “/”, “:”, “*”, “?”, “”"”, “”, “|”, “…”)
That seemed to work just fine.
-Carl
October 16, 2009 - 7:01 am
Hi,
Fantastic!
Are you aware of anyone having created a script to delete the saved attachment when a mail message is deleted to keep the attachment folder as tidy as your inbox?
I guess if the attachment is named with logic the same logic could be applied to find and destroy the attachment triggered by the BeforeDelete event.
I’m no programmer so maybe a more accomplished writer may have already done the script?
Thanks again,
Jonny.
October 16, 2009 - 11:35 am
Hi Jonny – That is certainly possible, although I haven’t seen any examples of it. I’m a bit of a pack rat, which is why I needed the attachment stripper in the first place, so I don’t tend to delete much
.
-Carl
October 22, 2009 - 2:06 am
Hi all, I encountered another issue though. I have a outlook folder where all the emails are of the same title, from the same sender and all their individual attachments are of the same name.
The only distinction is that these emails are sent at different times.
What do i tweak to the macro in oder to
step 1) strip the attachments over to my windows folder
step 2) rename the attachments according to the time/date stamp of the email?
Please help? Thanks!
Sam
October 22, 2009 - 3:00 am
A bit more background on my issue – i have tweaked the macro to save all stripped attachments into a single folder, so i now face the problem of identical filenames.
What i tried to do is,
attFileName = objAttachments.Item(i).FileName
attPath = msgFolder & “\\” & attFileName
And replaced it with
attFileName = attFileName = Strings.Format(objMsg.ReceivedTime, “yyyy.mm.dd.hhnnss”)
attPath = msgFolder & “\\” & attFileName
It “sort of” works, but the file is now an unrecognizable file in my window’s folder with the yyyy.mm.dd.hhnnss filename.
i’m stuck…
October 22, 2009 - 3:25 am
ok i solved it…
attFileName = Strings.Format(objMsg.ReceivedTime, “yyyy.mm.dd.hhnnss”) & objAttachments.Item(i).FileName
I added the time stamp to the filename.. haha.. sorry for flooding
October 22, 2009 - 5:11 am
Sam – No problem, thanks for sharing your solution! The original macro separated the files into time-stamped folders, so if you want everything in one folder, what you did is probably the best solution.
-Carl
October 22, 2009 - 6:15 am
carl, I created the project on Google:
http://code.google.com/p/lightlook/
if you send me your email, I can add you to developers group.
October 23, 2009 - 6:27 am
jumpjack – Looks nice! I added some notes above to point people to the Google Code project. My email information is available on the About tab above.
-Carl
October 28, 2009 - 10:12 am
Hi,
Great bit of code. Is there anyway of adopting this to remove attachments in calendar items?
Removing the following code does not help, errors out with 438 object does not support property or method.
“If objMsg.Class = olMail Then”
Many thanks, Steve.
November 4, 2009 - 9:22 pm
Hi Steve – This can be done, but it requires additional changes since these are different types of objects in Outlook. See the comments from Aug 26th above for some code snippets from Dennis and some discussion. If it’s something you would really like to see, you can request to have the code added to the next version on the project page.
-Carl
March 1, 2010 - 4:39 pm
This is great! Now we just need a way to reattach the docuemnts if I want to forward the original email. Maybe something in conjunction the “Handy Outlook Attchment Reminder” (http://manage-this.com/handy-outlook-attachment-reminder-macro/) that looks for the “Attachments Archived: ” line and then reassociates the files.
March 1, 2010 - 7:34 pm
Hi Chuck -
I agree, that was definitely something I was hoping to add. If you dig into the macro code, you’ll notice that the links inserted into the email are tagged with the link type of “REL=ATT_LNK”. This is sort of a made up tag I used to indicate “attachment links”. I was hoping a later version of the code could use these links to find the original attachment and replace it when a message is forwarded.
I haven’t had much time to enhance this code, which is why I agreed to let it move to the open source project. You may want to raise this request on the project page there.
-Carl
July 30, 2010 - 6:53 am
Excellent code BTW I have used something similar to Stub my Public folders, Saving gallons of space. Occasionally our user need to bind the attachments back in to their emails so that they can forward them. At the moment I have to edit the email, navigate to the attachment and manually reattach it to the email. Do you have some code for doing this. I was thinking of creating a macro button and then distributing it. I can’t figure the code out however. Is this something you could help with?
July 31, 2010 - 3:57 am
An off the shelf script / program I have used for several years is ‘Attachments Processor for Outlook’ by MapiLab. It does cost ($39) but is a robust & reliable solution that has plenty of filters, rules and tweaks – the ‘restore attachments’ and ‘forward message w/ attachments’ being the key ones I use.
Marty