This code sample shows how to load the contents of a text file into an array then use the array to do something, in this example, to move messages to a new folder.
An Outlook user asked a question our forum at Move email items based on a list of email addresses:
I have a huge number of emails in sent items and I am trying to move email items based on email addresses to a new folder. I have a huge list of addresses. Can this be done through a macro?
This example uses a text file containing one entry per line, checks the addresses against the recipients of the message and moves the messages if there is a match. For best results, the text file should not have blank lines at the end of the list, however the macro will remove the last blank new line, if one exists.
Public Sub MoveMessagesSenderFile() Dim objOutlook As Outlook.Application Dim objNamespace As Outlook.NameSpace Dim objDestFolder As Outlook.MAPIFolder Dim objSourceFolder As Outlook.Folder Dim obj As Object Dim lngMovedItems As Long Dim intCount As Integer Dim strAddress As String Dim totalCount As Integer Set objOutlook = Application Set objNamespace = objOutlook.GetNamespace("MAPI") Set objSourceFolder = objOutlook.ActiveExplorer.CurrentFolder Set objDestFolder = objNamespace.GetDefaultFolder(olFolderInbox).Parent.Folders("Movetosent") ' array from list Dim fn As String, ff As Integer, txt As String fn = "D:\Documents\addresses-to-move.txt" '< --- .txt file path txt = Space(FileLen(fn)) ff = FreeFile Open fn For Binary As #ff Get #ff, , txt Close #ff ' remove ending line break, if exists If Len(txt) <> 0 Then If Right$(txt, 2) = vbCrLf Or Right$(txt, 2) = vbNewLine Then txt = Left$(txt, Len(txt) - 2) End If End If Dim arrAddress() As String 'Use Split function to return a zero based one dimensional array. arrAddress = Split(txt, vbCrLf) ' end arrray totalCount = objSourceFolder.Items.count For intCount = totalCount To 1 Step -1 Set obj = objSourceFolder.Items.Item(intCount) ' only move mail If obj.Class = olMail Then ' clear the string for the next message strAddress = "" Dim Recipients As Recipients Set Recipients = obj.Recipients For i = Recipients.count To 1 Step -1 recip$ = Recipients.Item(i).Address ' To use only the alias from the x.500 address ' If InStr(1, LCase(recip), "/ou=") Then recip = Right(recip, Len(recip) - InStr(1, LCase(recip), "recipients") - 13) ' Use semicolon separator if there is more than 1 address If i = 1 Then strAddress = recip Else strAddress = strAddress & recip & "; " End If Next i ' Go through the array and look for a match, then do something For i = LBound(arrAddress) To UBound(arrAddress) If InStr(LCase(strAddress), arrAddress(i)) > 0 Then On Error Resume Next obj.Move objDestFolder 'count the # of items moved lngMovedItems = lngMovedItems + 1 GoTo NextMsg End If Next i NextMsg: End If Next ' Display the number of items that were moved. MsgBox "Moved " & lngMovedItems & " messages(s)." Set obj = Nothing Set objOutlook = Nothing Set objNamespace = Nothing Set objSourceFolder = Nothing End Sub
How to use the macros on this page
First: You need to have macro security set to the lowest setting, Enable all macros during testing. The macros will not work with the top two options that disable all macros or unsigned macros. You could choose the option Notification for all macros, then accept it each time you restart Outlook, however, because it's somewhat hard to sneak macros into Outlook (unlike in Word and Excel), allowing all macros is safe, especially during the testing phase. You can sign the macro when it is finished and change the macro security to notify.
To check your macro security in Outlook 2010 and newer, go to File, Options, Trust Center and open Trust Center Settings, and change the Macro Settings. In Outlook 2007 and older, look 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.
Macros that run when Outlook starts or automatically need to be in ThisOutlookSession, all other macros should be put in a module, but most will also work if placed in ThisOutlookSession. (It's generally recommended to keep only the automatic macros in ThisOutlookSession and use modules for all other macros.) The instructions are below.
The macros on this page should be placed in a module.
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
Hello, I used this Macro and it is working great for sent emails. What do I need to change to create a Macro for received emails as well?
To run it on messages you sent, you need to change the filter -
This is looking the the recipient field -
im Recipients As Recipients
Set Recipients = obj.Recipients
For i = Recipients.count To 1 Step -1
recip$ = Recipients.Item(i).Address
' To use only the alias from the x.500 address
' If InStr(1, LCase(recip), "/ou=") Then recip = Right(recip, Len(recip) - InStr(1, LCase(recip), "recipients") - 13)
you need to look in the sent to field - the macro in this article shows how.
Sort messages by Sender domain (slipstick.com)
I looked at that article and I still can't figure it out. Any chance you could copy and paste exactly what
Dim Recipients As Recipients
Set Recipients = obj.Recipients
For i = Recipients.count To 1 Step -1
recip$ = Recipients.Item(i).Address
' To use only the alias from the x.500 address
' If InStr(1, LCase(recip), "/ou=") Then recip = Right(recip, Len(recip) - InStr(1, LCase(recip), "recipients") - 13)
needs to be changed to so this macro works for received emails as well?
The macro on this page is for incoming mail - if it worked correctly on the sent folder, you don't need to change it.
Find the first and last lines - the new code goes in the between the line, replacing the code that is there now. This uses the first
strAddress = ""
' start changed code
Const PR_SMTP_ADDRESS As String = "http://schemas.microsoft.com/mapi/proptag/0x39FE001E"
Dim Recipients As Recipients
Dim recip As Outlook.Recipient
Dim pa As Outlook.propertyAccessor
Set Recipients = obj.Recipients
For i = Recipients.count To 1 Step -1
Set recip = Recipients.Item(i)
Set pa = recip.propertyAccessor
strAddress = LCase(pa.GetProperty(PR_SMTP_ADDRESS))
' end changed code
' Go through the array and look for a match, then do something
For i = LBound(arrAddress) To UBound(arrAddress)
I really apologize for not being able to figure this out, but when I entered the code above exactly as displayed I got the error message "For control variable already in use" by the For i = LBound(arrAddress)
Any chance you know what the problem is?
Thank you for all your help
Try the version in the text file. (I did not test it)
Unfortunately, I still get the "For control variable already in use" error message when I run this text file. The error happens after the updated code at the "For i = LBound(arrAddress)" line
ah! and change recepients to senders. I want to moved received @ :) thank you!
Hello, this is really nice macro! Thank you! Would you be so kind and advise how to change it that outlook checks not aliases, but domains (e.g. in txt I put "@microsoft.com" then all emails from this domain are moved)? Thank you!
To get the sender address you use the senderemailaddress field then to get just the domain , you need to find the @ and get everything to the righthe, using the Right & len function.
something like this - Right(obj.SenderEmailAddress, Len(obj.SenderEmailAddress) - InStr(obj.SenderEmailAddress, "@"))
https://www.slipstick.com/developer/file-messages-senders-name/ has some examples, I think most get the alias though.
Hello Diane,
I really love the way this macro is built. I have created my text file of emails I want moved from my Inbox to the Deleted Items folder. When I run it there are no errors but it moves zero emails too. I am not certain what I am doing wrong. I replaced this code:
Set objSourceFolder = objOutlook.ActiveExplorer.CurrentFolder
Set objDestFolder = objNamespace.GetDefaultFolder(olFolderInbox).Parent.Folders("Movetosent")
With this code:
Set objSourceFolder = objOutlook.ActiveExplorer.CurrentFolder
Set objDestFolder = objNamespace.GetDefaultFolder(olFolderInbox).Parent.Folders(olFolderDeletedItems)
What am I doing wrong? I really appreciate any help you can give me.
Regards,
Lynn
With the default folders, you call them by name
Set objDestFolder = objNamespace.GetDefaultFolder(olFolderDeletedItems)