You can use a Run a Script rule or an ItemAdd macro to look for messages with attachments, then check the file type. If certain file types are found, the macro does something with the message, in the example, the message is moved to a folder.
Use a run a script rule if your mail load is lighter and you want to use the script only on messages meeting certain conditions. Use an ItemAdd macro for heavier mail volumes or when you need to check all messages you receive.
Use a Run a Script rule
To use the run a script rule, create a rule.
Select the has an attachment condition and any other conditions you want to check. The only action will be run a script. Set exceptions as needed.

If you need to do more actions, such as mark the message read, forward a copy, etc, you'll need to add it to the script.
To check additional file types, use 4 characters for the extension name. If the extension is 3 characters, use the leading dot in the Select Case list: docx or .doc
Run a script macros will work in ThisOutlookSession but should be placed in a module.
Sub MoveMail(Item As Outlook.MailItem)
If Item.Attachments.Count > 0 Then
Dim attCount As Long
Dim strFile As String
Dim sFileType As String
attCount = Item.Attachments.Count
For i = attCount To 1 Step -1
strFile = Item.Attachments.Item(i).FileName
sFileType = LCase$(Right$(strFile, 4))
Select Case sFileType
Case ".pdf", ".doc", "docx"
' do something if the file types are found
' this code moves the message
Item.Move (Session.GetDefaultFolder(olFolderInbox).Folders("Move"))
' stop checking if a match is found and exit sub
GoTo endsub
End Select
Next i
End If
endsub:
Set Item = Nothing
End Sub
To test a run-a-script macro, you either need to keep sending yourself mail, use Run Rules Now, or use a "stub macro" to trigger the script on the selected message, as macros with parameters in the macro name: (Item As Outlook.MailItem) cannot be run manually.
Sub RunScript() Dim objApp As Outlook.Application Dim objItem As Object ' MailItem Set objApp = Application Set objItem = objApp.ActiveExplorer.Selection.Item(1) 'macro name you want to run goes here YourMacroName objItem End Sub
Use an ItemAdd macro
ItemAdd macros can handle larger volumes of mail and can watch any folder for new items. This macro must be placed in ThisOutlookSession. Click in Application_Startup to test the macro without restarting Outlook.
Option Explicit
Private WithEvents olInboxItems As Items
Private Sub Application_Startup()
Dim objNS As NameSpace
Set objNS = Application.Session
' instantiate objects declared WithEvents
Set olInboxItems = objNS.GetDefaultFolder(olFolderInbox).Items
Set objNS = Nothing
End Sub
Private Sub olInboxItems_ItemAdd(ByVal Item As Object)
On Error Resume Next
If Item.Attachments.Count > 0 Then
Dim attCount As Long
Dim strFile As String
Dim sFileType As String
Dim i
attCount = Item.Attachments.Count
For i = attCount To 1 Step -1
strFile = Item.Attachments.Item(i).FileName
Debug.Print strFile
sFileType = LCase$(Right$(strFile, 4))
Debug.Print sFileType
Select Case sFileType
Case ".pdf", ".doc", "docx"
' do something if the file types are found
' this code moves the message
Item.Move (Session.GetDefaultFolder(olFolderInbox).Folders("Move"))
Exit Sub
End Select
Next i
End If
End Sub
How to use these macros
First: You need to have macro security set to low during testing. The macros will not work otherwise.
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.
Some macros need to be in ThisOutlookSession, others go into a module or can be placed in either ThisOutlookSession or a module. The instructions are below.
Open the VBA Editor by pressing Alt+F11 on your keyboard.
If you are told to put the code in a module:
- Right click on Project1 and choose Insert > Module
- Copy and paste the macro into the new module.
If you are told to put the macro code in ThisOutlookSession:
- Expand Project1 and double click on ThisOutlookSession.
- Copy then paste the macro into ThisOutlookSession. (Click within the code, Select All using Ctrl+A, Ctrl+C to copy, Ctrl+V to paste.)
More information as well as screenshots are at How to use the VBA Editor
More Information
- 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
Michelle says
Hi, I have a particular software that is picking up emails from my inbox. The scenario I have is that on some occasions, there are senders that add an email as an attachment (to the email they are sending to me), and it throws this other software on this endless loop because it cannot open the email attachments. I am wondering if you can guide me on moving the email with the email attachment to a folder let's say called "Exceptions"
John says
I should clarify. the macro can't be selected from the Run menu in the VBA editor (to test) and when added to a rule it doesn't seem to actually move the emails
Diane Poremsky says
You need to use a "stub macro" to trigger the rules macro - they can't be run on their own.
John says
How would i go about fixing these?
some time in the recent past macros with subs that contain parameters stopped being runable / selectable...
https://stackoverflow.com/questions/45922417/macros-not-showing-up-in-the-run-macro-menu
David says
ItemAdd script works well! I've been able to move all emails with excel files attached to their own folder. What's the flag for follow up script and where would I add it to the ItemAdd script above?
Diane Poremsky says
Sorry I missed this earlier. If you want to flag messages you move, before the move line, add this block, changing the values as needed:
With item
.MarkAsTask olMarkThisWeek
' sets a specific due date
.TaskDueDate = Now + 3
.ReminderSet = True
.ReminderTime = Now + 2
.Save
end with
https://www.slipstick.com/developer/code-samples/set-flag-follow-up-using-vba/
Michael Morrison says
Will this script work for encrypted email?
Diane Poremsky says
I don't think so... I think it will see the encryption content as an attachment and apply to all messages.
Ashet says
Hi Diane
I have six rules that run six different scripts to copy attachments from emails to a unique folder based on the name of the rule. Basically all the scripts are the same except for the folder name the attachment gets copied, the folder name is the same name as the rule.
I want to have just one script and all the rules run it. I want the string value for the folder name to be the name of the rule that triggered it.
I cannot get the name of the rule that triggered the script. How do I get the name of the rule that triggered the script ?
Your help will be appreciated
Diane Poremsky says
is there anything in the emails that can be used to filter on? The other option is to use stub macros - the rule calls a macro, that macro sets the folder and pushes the value to the main macro that does the work.
if there is something in the messages that can trigger the folder, you could use one rule and one script.
' this is called by the rule and pushes the message to another macro
Sub MoveStuff(Item As Outlook.MailItem)
Set myFolder = [folder]
MoveMail Item
End Sub
Private Sub MoveMail(Item As Outlook.MailItem)
' all the move stuff here
' using myFolder object
End Sub
Josh says
How do you move the an email with certain attachments to a new folder but skip the attachment next to the signature?
In your example I add
If Item.Attachments.Item(i).Size < 5200 Then
GoTo nexti
End If
After the case line so it would look past the attachment in the signature line. Problem is that this is not working. It will move the emails correctly but if there is an attachment in the signature line it moves this too. Any help on this would be appreciated.
Diane Poremsky says
Are the attachments in the signature all images?> Are the attachments you need to move images? The problem is likely the size if the image in the signature - this is looking for 5KB attachments. If you are moving other files types, use the case statement to look only for that file type.
Josh says
yes. It still isn't working.
Here is what I have:
Sub MoveMail(Item As Outlook.MailItem)
If Item.Attachments.Count > 0 Then
Dim attCount As Long
Dim strFile As String
Dim sFileType As String
attCount = Item.Attachments.Count
For i = attCount To 1 Step -1
strFile = Item.Attachments.Item(i).FileName
sFileType = LCase$(Right$(strFile, 4))
Select Case sFileType
Case ".zip", ".jpg", ".gif"
If Item.Attachments.Item(i).Size < 9900 Then
GoTo nexti
End If
End Select
' do something if the file types are found
' this code moves the message
Item.Move (Session.GetDefaultFolder(olFolderInbox).Folders("Exception Attachments"))
' stop checking if a match is found and exit sub
GoTo endsub
nexti:
Next i
End If
endsub:
Set Item = Nothing
End Sub
Diane Poremsky says
so its still saving gif & jpg files if they are under ~9 KB? Do they have 'normal' file names or something you can filter on, like image00* ?
Josh says
It filters pdf's too. is my logic correct?
Diane Poremsky says
the macro should apply to pdf's - you are only filtering for attachments under approx. 8 KB.
Case ".zip", ".jpg", ".gif"
If Item.Attachments.Item(i).Size < 9900 Then GoTo nexti End Ifit should work - if those types are small files, it goes to the next attachment. if any other file is found, or those files are larger, it moves and quits. Item.Move (Session.GetDefaultFolder(olFolderInbox).Folders("Exception Attachments")) ' stop checking if a match is found and exit sub GoTo endsub
Josh says
No, They will be different since this rule is for a mailbox that gets mail from all sorts of different customers.
Josh says
I fixed this but and it seems to be working but know it applies the rule to pdf's. Not sure why this is. Any ideas?
John Harvey says
I've upgraded to Outlook 2013 and the VB doesn't seem to recognize that there is an attachment, so the VB fails. Anyone else run into this?
Diane Poremsky says
Any error messages? Are you using 32 or 64 Bit Outlook? Is the macro running at all?
(Most of the macros on the site were tested in 2013 or 2016.)
Nigel Foster says
Hello Diane,
I want to print messages with PDF attachments. I have written code to do so, but the code has limitations. When it hits a message which has OTHER MESSAGES as attachments, I need to be able to check these messages as well, for PDF attachments. My first attempt involved saving the attachment-as-message to a file on my desktop and "re-creating" it using CreateItemFromTemplate. This corrupts the PDF attachment withing the attachment-as-message and prevents it either being opened or printed by Adobe Reader or Acrobat. I have tried and failed to copy the attachment-as-message to an Outlook folder (as you can do, without corruption to any attachments it may contain, with a simple drag-and-drop) as I have not found a command in VBA which can copy or move an ATTACHMENT to an Outlook folder. Can you help at all?
Davd says
Is it possible for the script to use the name of the rule to assign an attachment to a folder with the same name? I can't seem to be able to use the rule.name correctly.
Jonathan says
hi i trying to move a mail with an atach file but who start with "anyword" but don't work
Sub MoveFilesToTest(Item As Outlook.MailItem)
Dim olkAtt As Outlook.Attachment
'Check each attachment
For Each olkAtt In Item.Attachments
'If the attachment's file name ends
If Left(LCase(olkAtt.FileName), 7) = "SR-Dash" Then
'Move the message to Test
Item.Move (Session.GetDefaultFolder(olFolderInbox).Folders("Test"))
'No need to check any of this message's remaining attachments
Exit For
End If
Next
Set olkAtt = Nothing
End Sub
Diane Poremsky says
Add Debug.print Left(LCase(olkAtt.FileName), 7) after the For each attachment line then show the immediate window (View menu) and see what it's grabbing.
Oh... you are converting it to lower case but trying to match upper case - it should be "sr-dash"
If Left(LCase(olkAtt.FileName), 7) = "SR-Dash" Then
Stephen H says
Hi Diane,
I'm trying to use the ItemAdd function on a shared mailbox which has subfolders within the Inbox. Some of the emails that come in trigger Rules which pickup emails and automatically moves them into a subfolder depending on text strings within the mail body. As I'm monitoring the Inbox and not the subfolders the ItemAdd doesn't fire when the rule automatically picks up the mail.
I understand I need to add the items as a collection however I'm struggling with the syntax. Any suggestions would be appreciated!
Diane Poremsky says
So you need to watch multiple folders? It might be easier to use rules to set categories (which are the folder names) then use itemadd to do whatever and if a category exists, move to that folder.
Balaji says
Can you please advise on the VBA script to read the contents of attachments of an Email and move it to a specific folder?
For EG: If attachment has Approved or Rejected word, the mails should be moved to different folder
Diane Poremsky says
Is this a word document? Reading contents of attachments would require vba support in the program that opens the attachment. if the subject or filename has approved or rejected in it, it would be easy.
Balaji says
Dear Diane,
Thanks for supporting!!
Incoming mail comes with
a notepad attachment. Users' will receive 50 to 100 mails a day in which they have to open this notepad attachment and see whether its' approved or rejected. Problem is out of 100 mails only 2 or 3 mails with attachment has rejected word. So, they were asking me is there any way to set rule to find out these mails and move it a seperate folder.
Note: Filename or Subject doesn't have approved or rejected word in it. Only the content of the file (i.e notepad) has it.
Diane Poremsky says
What version of Outlook? Instant search works on the message i just tested - attachment:rejected -
Balaji says
Hi Diane,
We are using outlook 2007.
Thank you very much for your wonderful support...!!
It works fine with what you have suggested..!! This saved a lot of our production time..
I'm really glad to get your assistance!!
God bless you, take care!
Daniel says
I have used the second macro ItemAdd following all your indications and nothing happened. I really do not understand the first declaration Private WithEvents olInboxItems As Items. If it is an event then I should wait to receive a new item in my inbox. I Clicked in the Application_Startup to test the macro but the main routine "olInboxItems_ItemAdd" wasn't called at all. Does it work in Outlook 2010 ? Thank you in advance.
B-rad says
Hi,
I am using the code you posted above for the MoveMail macro. The code works for me sometimes and other times I receive a Run-time error stating, "Cannot move the items." I've done some research, but I'm not able to find any solution. Any help is greatly appreciated.
Thank you in advance.
P.S. the error I'm receiving is "Run-time error '-2147352567(800200009)': Cannot move the items."
the code I'm using is below:
Sub MoveMail(Item As Outlook.MailItem)
If Item.Attachments.count > 0 Then
Dim attCount As Long
Dim strFile As String
Dim sFileType As String
attCount = Item.Attachments.count
For i = attCount To 1 Step -1
strFile = Item.Attachments.Item(i).filename
sFileType = LCase$(Right$(strFile, 4))
Select Case sFileType
Case ".pdf"
' do something if the file types are found
' this code moves the message
Item.Move (Session.GetDefaultFolder(olFolderInbox).Folders("Purchase Orders"))
' stop checking if a match is found and exit sub
GoTo endsub
End Select
Next i
End If
endsub:
Set Item = Nothing
End Sub
Diane Poremsky says
The error means something is preventing it from moving the message. What type of email account? How large are the attachments?
B-rad says
Thanks for the quick replay. It's a Microsoft Outlook 2007 e-mail account. The attachments are PDF files which typically range in size from 100 bytes to 130 kilobytes. It's very strange, When I receive that run-time error, the e-mail is getting moved twice... So, I receive the error stating that the items cannot be moved; however, when I check the "Purchase Orders" folder, I have two copies of the same e-mail. Sometimes it will work perfectly fine and other times this happens. As far as I can tell, there it is completely random, sometimes this happens when the attachments are small and sometimes when they are larger.
Diane Poremsky says
Are there multiple attachments on the message? it's supposed to exit when it finds a match, but i wonder if its not - when it loops for attachment #2, it errors.
B-rad says
It also might be worth mentioning that when I set a breakpoint and step through the code, the error doesn't seem to occur nearly as often.
B-rad says
Some of the emails that I am using for testing contain multiple PDF attachments; however, the message that it is most frequently receiving the error has only one attachment. Like I said earlier, when I set the breakpoint at the beginning of the Sub and then step through each line of code, everything works fine which makes it difficult to find exactly what is causing this error. When I receive the error it highlights the following line in the VBA editor:
"Item.Move (Session.GetDefaultFolder(olFolderInbox).Folders("Purchase Orders"))"
I then check the Purchase Orders folder which shows that the message was moved. Then, when I click to stop/reset the program in the VBA editor, the same email is moved to the Purchase Orders folder again.
Diane Poremsky says
That line is marked because the Move command is failing, because the message was moved already. I haven't been able to repro an error yet but will keep trying.
With just one file type, you couls use an if statement but I'm not sure it will end the error, since we don't know the cause.
sFileType = LCase$(Right$(strFile, 4))
If sFileType = ".pdf" Then
Item.Move (Session.GetDefaultFolder(olFolderInbox).Folders("Moved"))
GoTo endsub
End If
Next i
B-rad says
I've tried using an If statement earlier, unfortunately, I still receive the same error.
Diane Poremsky says
The rule that is calling this script, does it have any other actions in it?
B-rad says
The rule description is as follows:
Apply this rule after the message arrives
sent to "myemail@mydomain.com"
and which has an attachment
and on this machine only
run Project1.MoveMail
Diane Poremsky says
How fast and frequent are the messages? If multiple messages arrive at once, rules can fail, but they usually just don't work.
Try it using entryId to identify the message -
Sub MoveMail(Item As Outlook.MailItem)
If Item.Attachments.Count > 0 Then
Dim objMail As Outlook.MailItem
Dim strID As String
Dim attCount As Long
Dim strFile As String
Dim sFileType As String
strID = Item.EntryID
Set objMail = Application.Session.GetItemFromID(strID)
attCount = objMail.Attachments.Count
For i = attCount To 1 Step -1
strFile = objMail.Attachments.Item(i).FileName
sFileType = LCase$(Right$(strFile, 4))
Select Case sFileType
Case ".pdf"
objMail.Move (Session.GetDefaultFolder(olFolderInbox).Folders("Moved"))
GoTo endsub
End Select
Next i
End If
endsub:
Set objMail = Nothing
End Sub
B-rad says
The reason I need the "sent to" portion is because the entire customer service department is going to be using this. So, whenever an e-mail is sent to the customer service department I want any e-mails with PDF attachments that are sent to the customer service e-mail address to be moved to the Purchase Orders folder. I see in your example that you only have:
"Apply this rule after the message arrives
and which has an attachment
and on this computer only
run Project1.ThisOutlookSession.MoveMail"
Do I NEED to put this in ThisOutlookSession?
Diane Poremsky says
No, it doesn't need to be in ThisOutlookSession. The sent to portion shouldn't affect it, it prevents it from applying to all messages, so it runs faster. We don't need the attachment counter in the script since we're checking it in the rule, but that wouldn't cause the error either.
Is there a second rule that could apply to the message? If the second rule does something, it could cause issues with this rule.
If the message has images in a signature, that counts as an attachment - but the script should exit as soon as it finds the pdf.
B-rad says
The messages aren't very frequent. Perhaps 5-10 throughout the course of the day so usually at least a few minutes apart. Also, I don't have any other rules that would apply to this message and none of the test emails that i am using have any images in the signatures...
I tried using the entryID to identify the message. I don't seem to be receiving the "Cannot move item" error anymore; however, I am still getting two copies of the e-mail moved to my Purchase Order folder.
Diane Poremsky says
It seems like something is causing it to process twice.
Try writing the extensions to a variable and testing the variable:
Replace the end of the macro with this:
attCount = objMail.Attachments.Count
For i = attCount To 1 Step -1
strFile = objMail.Attachments.Item(i).FileName & ";" & strFile
Next i
If LCase$(InStr(strFile, ".pdf")) > 0 Then
objMail.Move (Session.GetDefaultFolder(olFolderInbox).Folders("Moved"))
End If
End If
Set objMail = Nothing
End Sub
B-rad says
I've tried this, but I'm still getting duplicate emails.
mande01 says
Hi,
I have been looking for a while now to do something like this but different.
I need to move the contents of multiple pst into another one.
I have very little experience in vba and I am really struggling to find a solution.
Could you assist?
My main issue is around selecting a pst and then moving all content to another pst.
Thanks,
Der
Diane Poremsky says
Have you considered using the Import command? That will import everything for you.
Gustavo Verde says
Thank you for your reply. I am not very good with scripting, but I will give it a try.
Gustavo Verde says
Hi Diane,
I am looking for a way to create a rule in Outlook that would take the file attached to an incoming message meeting certain criteria like subject line for example, and create a new message with that file attached and send it to someone else using a template.
Any help will be appreciated.
Diane Poremsky says
You need a run a script rule.Run a Script Rule: Send a new message when a message arrives. The conditions will be in the rule, the script will handle all of the actions.
You'll need to save the attachment and then add it to the new message. You'll need the function from CopyAttachments. You'll use the same method to attach the files as the macro on that page uses.