
Kevin writes and asks if there is any procedure that will update a distribution list in Outlook using a list of names and email addresses in Excel. Let's see what we can come up with.
Rather than update an existing distribution list, I prefer to simply delete and recreate the entire list. It's much easier than going through the worksheet and comparing each name against the existing members of the distribution list to see who needs to be added, or some complicated workaround (like a helper column) to "tell" the procedure where to start checking for new names.
We'll start with the event handler and then work on a procedure that can be run on demand.
Event Handler
Assume we have a workbook with one sheet — column A has names, column B has email addresses. The first row is a header row. Place the following code into the sheet module for the worksheet (see "Paste code in a Sheet module" in Where do I paste the code that I want to use in my workbook if you need placement assistance). Whenever the worksheet is updated, you'll be prompted to (re)create the distribution list.
Const DISTLISTNAME As String = "My Dist List"
Const olDistributionListItem = 7
Const olFolderContacts = 10
Private Sub Worksheet_Change(ByVal Target As Range)
Dim outlook As Object ' Outlook.Application
Dim contacts As Object ' Outlook.Items
Dim myDistList As Object ' Outlook.DistListItem
Dim newDistList As Object ' Outlook.DistListItem
Dim objRcpnt As Object ' Outlook.Recipient
Dim arrData() As Variant
Dim rng As Excel.Range
Dim numRows As Long
Dim numCols As Long
Dim i As Long
Dim msg As String
msg = "Worksheet has been changed, would you like to update distribution list?"
If MsgBox(msg, vbYesNo) = vbNo Then
Exit Sub
End If
Set outlook = GetOutlookApp
Set contacts = GetItems(GetNS(outlook))
On Error Resume Next
Set myDistList = contacts.item(DISTLISTNAME)
On Error GoTo 0
If Not myDistList Is Nothing Then
' delete it
myDistList.Delete
End If
' recreate it
Set newDistList = outlook.CreateItem(olDistributionListItem)
With newDistList
.DLName = DISTLISTNAME
.body = DISTLISTNAME
End With
' loop through worksheet and add each member to dist list
numRows = Range("A1").CurrentRegion.Rows.count - 1
numCols = Range("A1").CurrentRegion.Columns.count
ReDim arrData(1 To numRows, 1 To numCols)
' take header out of range
Set rng = Range("A1").CurrentRegion.Offset(1, 0).resize(numRows, numCols)
' put range into array
arrData = rng.value
' assume 2 cols (name and emails only)
For i = 1 To numRows
Set objRcpnt = outlook.Session.CreateRecipient(arrData(i, 2))
objRcpnt.Resolve
newDistList.AddMember objRcpnt
Next i
newDistList.Save
'newDistList.Display
End Sub
Function GetOutlookApp() As Object
On Error Resume Next
Set GetOutlookApp = CreateObject("Outlook.Application")
End Function
Function GetItems(olNS As Object) As Object
Set GetItems = olNS.GetDefaultFolder(olFolderContacts).items
End Function
Function GetNS(ByRef app As Object) As Object
Set GetNS = app.GetNamespace("MAPI")
End Function
Change the first line ("My Dist List") to the name of the distribution list you want. When you change anything on the worksheet (i.e. add a new name and email address in cols A and B), the code looks for the named distribution list. If it exists, it's deleted, so make sure you use only the worksheet to maintain the distribution list. Any names you add manually will be gone.
Then the looping begins. Here we can go two ways: If the names are in your Address Book or GAL, you can use
Set objRcpnt = outlook.Session.CreateRecipient(arrData(i, 1))
if you know the names will resolve properly. If not, you should use the code as written, because email addresses will always resolve.
The recipients need to be passed as Recipient Objects, hence the use of CreateRecipient to create a temporary Recipient Object.
We may also want to change the procedure so that it only checks a specific range. For example, if you use the worksheet for other things, you may not want it interrupting you if you aren't actually working on the dist list. Adding this at the top of the above event handler would help:
If Intersect(Target.Address, Range("B:B")) Is Nothing Then
Exit Sub
End If
On Demand Procedure
This procedure is essentially the same as the event handler, except that this one runs only when you want.
Const DISTLISTNAME As String = "My Dist List"
Const olDistributionListItem = 7
Const olFolderContacts = 10
Sub MaintainDistList()
Dim outlook As Object ' Outlook.Application
Dim contacts As Object ' Outlook.Items
Dim myDistList As Object ' Outlook.DistListItem
Dim newDistList As Object ' Outlook.DistListItem
Dim objRcpnt As Object ' Outlook.Recipient
Dim arrData() As Variant
Dim rng As Excel.Range
Dim numRows As Long
Dim numCols As Long
Dim i As Long
Set outlook = GetOutlookApp
Set contacts = GetItems(GetNS(outlook))
On Error Resume Next
Set myDistList = contacts.item(DISTLISTNAME)
On Error GoTo 0
If Not myDistList Is Nothing Then
' delete it
myDistList.Delete
End If
' recreate it
Set newDistList = outlook.CreateItem(olDistributionListItem)
With newDistList
.DLName = DISTLISTNAME
.body = DISTLISTNAME
End With
' loop through worksheet and add each member to dist list
' assume active sheet
numRows = Activesheet.Range("A1").CurrentRegion.Rows.count - 1
numCols = Activesheet.Range("A1").CurrentRegion.Columns.count
ReDim arrData(1 To numRows, 1 To numCols)
' take header out of range
Set rng = Activesheet.Range("A1").CurrentRegion.Offset(1, 0).resize(numRows, numCols)
' put range into array
arrData = rng.value
' assume 2 cols (name and emails only)
For i = 1 To numRows
Set objRcpnt = outlook.Session.CreateRecipient(arrData(i, 2))
objRcpnt.Resolve
newDistList.AddMember objRcpnt
Next i
newDistList.Save
'newDistList.Display
End Sub
Function GetOutlookApp() As Object
On Error Resume Next
Set GetOutlookApp = CreateObject("Outlook.Application")
End Function
Function GetItems(olNS As Object) As Object
Set GetItems = olNS.GetDefaultFolder(olFolderContacts).items
End Function
Function GetNS(ByRef app As Object) As Object
Set GetNS = app.GetNamespace("MAPI")
End Function
Here's what a sample spreadsheet would look like:

And here's an Outlook distribution list as a result:






Nice coding but I'll add a little variation to it because I like a normal name instead of two times the e-mail address.
Your coding above until the next lines ….
For i = 1 To numRows 'little variation on your theme ... Set objRcpnt = outlook.Session.CreateRecipient(arrData(i, 1) & "<" & arrData(i, 2) & ">") 'end of variation objRcpnt.Resolve newDistList.AddMember objRcpnt Next iContinue with your coding.
Hope you like it.
Thank you JP and Charlize.
This code is usefull for me.
Bye
Hi JP,
Appreciate the code this can come in very useful. I've set everything up the way you describe, but when I run the code I get a run time error 287 and the code debugs on objRcpnt.Resolve.
Any ideas why this happens?
It's hard to say, without more information. Which procedure are you using, the event handler or the code you have to run manually?
Hi JP,
Well it's what I expected. I just tested your code at home and it works perfect. I'm using the On Demand Procedure and I believe it has to do with the way our computers at work are configured…they will not allow some code to run.
For instance, if you generate an e-mail from Excel you have to change the .send to .display and then simply use the manual hit the send.
Hi o,
Thanks for the guide. Total n00b regarding Xcel but trying to make the best of your script for work. Question though: I'm using a spread sheet that has a variety of information from names, dates, to random numbers associated with that account. In Column B I have names, Column E email address.
Is there a way I can export the data from this sheet knowing their are multiple columns of data and I only want specific ones? In a 1:1 match for the rows the data lines up so it could just be for the whole column (B33:E33, etc…)
Here's another little quirk, some of the columns in row E are blank, so there is no email entered yet to associate to the name. Would that create a problem?
I tried creating a blank xcel linked the rows in so they auto completed and updated using just two columns, one for names one for emails. The script didn't like that though.
Thanks,
Jason