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?
August 4, 2010 - 11:20 pm
Tommyzoom – Unfortunately there’s no easy way to do this with this code. That is why in addition to links to the files, the macro also inserts a link to the *folder* at the top of the list.
To quickly forward the message with its original attachments intact, I first click the folder link to open the folder. I then forward the message. In the edit window of the forwarded message, I drag the files to attach them. I also delete the list of links and the “Attachments Removed” attachment. It does take a few steps, but it’s not too bad if you use the folder link.
Another tip is to not run the macro on messages right away. I usually run the macro on older messages that have already been filed so it is less likely that I’ll need to forward them.
You could also use a commercial tool like the one Marty mentions below.
Hope that helps!
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
August 4, 2010 - 11:25 pm
Marty – Thanks for the tip! For someone that deals with a lot of attachments or is severely limited on Exchange server space, a commercial solution is probably the best bet.
There are also a lot of attachment management tools listed on the Slipstick Systems website. There may be some free ones there that are pretty decent, but I haven’t really tried any of them.
-Carl
November 20, 2010 - 8:19 am
Hi Carl,
Great VBA Macro ! congratulations. I previously used “Attachment Remover” a free plug-in for IE but with the last rules of my IT management I have had to remove it (it’s not authorized !).
Your macro is working fine and is very well documented but I have a few questions (I didn’t find the answers in the present forum).
1- For a few e-mails with various attachments (not a certain type) I get an error message
[RemoveAttachments() Subroutine
Error Code: -2147467259]
It is the command line [objMsg.SaveAs msgFolder & msgSubject & ".txt", olTXT] which induces this error
Do you have a suggestion to solve this issue ?
2- With e-mails where there are pictures (*.jpg mainly) inside (not attached) the macro also removes these pictures.
Is it possible not to remove these pictures ?
Many thanks in advance for your support
L. Iquidenbar
November 28, 2010 - 1:38 am
For item 1, this may be the error that occurs when there is some unusual character in the subject line that is unsupported in a Windows file name. The subject line is used to create the file name when saving the TXT version of the message. There is a line in the macro that attempts to strip all of these characters (see the “invalidChars” array). You may need to add one to the array. You could also default to a simpler file name (see section where objMsg.InternetCodepage is checked).
For item 2, you can try to adjust the threshold size to exclude smaller messages. Another possibility is checking attachment types. OLE objects are already excluded (see oleFound flag).
If those suggestions don’t help, I would recommend posting to the group where the source code is now maintained.
Hope that helps!
-Carl
December 16, 2010 - 7:54 am
Hi,
nice code. I don’t use VB but C# then this code its not completely clear for me.
However, I have followed the instruction but the result I have is that the selected mail disappear completely from outlook and its moved in the attachment folder.
Can someone please help!!
Thansk
January 17, 2011 - 9:17 pm
Hi Felice –
The code places a text-only *copy* of the message in the attachment folder for reference, but the original message is not moved. The size of the message will change since the attachments are removed. If you are sorting the message list by size, the message will jump to a different location in the sort order. It may looks like it is gone, but it is likely still in the folder. Hopefully that is the case.
-Carl
January 31, 2011 - 10:14 am
Hi Carl
This is probably one of the best Codes for VBA ive ever seen. But one question left. Is it possible to replace the fix root string with a dirlistbox like the one of John Walkenbach. im not a programmer, but i think for you its done in heartbeat. the rest works perfect and thanks for all your work
Greetings Kurt
February 2, 2011 - 8:47 pm
Hi Kurt -
The macro is really designed to work in batch/silent mode, so rather than prompting you for a location for each message it just goes to work. It is definitely possible to modify this and have it prompt you for a save location on each message. Unfortunately, I don’t have time to maintain this macro and add new features – that is why the Google Code project was started. I would recommend posting a request on the project page.
-Carl