Reestablish links to Outlook contacts after exporting a mailbox
Sooner or later, every administrator of a Microsoft Exchange Server 5.5 (or earlier) system needs to move a mailbox from one site or container to another. A classic solution is to export the entire mailbox to a personal store (.pst) file, add the new mailbox, then import the .pst data into the new mailbox. Alternatively, you can use the Microsoft BackOffice Resource Kit's Exmerge utility to help automate that process.
Many administrators discover only after the fact that exporting to a .pst file and importing into a new mailbox breaks all the links between Microsoft Outlook items and related contacts. (Moving items within a mailbox doesn't break the links, as importing and exporting does.) For example, if after importing you double-click a link in the Contacts box on a task item, you get the error message The name or distribution list has been deleted and is no longer a valid Address Book entry. The operation failed. An object could not be found.
The message is accurate if not particularly helpful. By exporting and importing, you've actually created new contact items, and Outlook no longer has the original contact items that you linked to. Outlook provides no way to reconnect the links to their related contact items, other than to retype the contact names in the Contacts box.
In most cases, you can restore the links with the VBA ReconnectLinks subroutine in Listing 1, page 110, which examines all the items in a folder that the user selects and attempts to find the related contacts in the user's default Contacts folder. The code gets the name of each link and tries to find a matching contact in the Contacts folder. If the code finds a match, it deletes the old link and creates a new link to that matching contact. (The code can't find links that the user might have made to contacts in a different folder; you'll still need to fix those manually.)
Reading Listing 1's code gives you a fine opportunity to learn about the Links collection, which stores all the connections to contacts and displays them in an Outlook item's Contacts box. (In an email message, you must click View, Options to see the Contacts box.)
If you look in the Object Browser (press F2 while you're working in VBA), you'll see that every Outlook item object (e.g., AppointmentItem, MailItem) supports a Links collection, even NoteItem (the Outlook equivalent of sticky notes). Like other collections, Links has a Count property that lets you know how many links the item has, and the three standard collection methods: Add, Item, and Remove.
To get an object reference to a particular Link object in the Links collection, you use the Item method. At callout A in Listing 1, the code gets the Count from the Links collection, then counts down from that number to 1, using the Item method to obtain each Link in turn.
The code counts down in a For ... Next loop instead of a For Each ... Next loop because later the code removes the broken Link objects. If you remove an item inside a For Each ...Next loop, you end up skipping items because the parent application resets the index counter. I start with the Link that has the highest index number and work down so that I can replace each one in turn. To remove a Link from the Links collection, you need to specify its index:
colLinks.Remove i
A user can simply type a name into the Contacts box and create a link, even if no matching contact exists. However, a program that needs to add a Link to the Links collection must first obtain a valid ContactItem object. The Add method requires a ContactItem as an argument:
colLinks.Add objContact
A Link object has two primary properties: Name and Item. If the link is connected to a valid Outlook contact, the Item property returns the linked ContactItem. In the case of disconnected links, however, trying to access the Item results in a runtime error because the link is broken. (That's why Listing 1 contains the On Error Resume Next statement.)
Even though the Item property causes a problem, the program can still get the value of the Name property. After a little experimentation, I found that the text that Outlook uses for the Name property for a Link object is the FullName property of the corresponding ContactItem. This clue is what you need to find the item in the current default Contacts folder that corresponds to the broken link. The code at callout B assumes that just one contact has that name and uses the Find method to locate that contact. The Find method returns the first match for the search string that you provide as an argument (strFind, in this example).
One caution about using the ReconnectLinks routine: Outlook has a known memory-leak problem when processing large Items collections in a For Each ... Next loop. If you have folders with thousands of items that need to be relinked, you might want to move a few hundred items at a time into a temporary folder, run ReconnectLinks, then move the items back into their original folder. Increasing your Windows pagefile size might also help you avoid the memory leak. The Microsoft article "OL2000: Memory or Performance Problems Looping Through Items" (http://support.microsoft.com/support/kb/articles/q293/7/96.asp) also suggests a possible solution if the items you need to process use custom forms.
To learn more about using the Links collection to link items to contacts, see the following Exchange & Outlook UPDATE newsletter articles at http://www.win2000mag.com: "Linking Outlook Contacts," InstantDoc ID 20353, and "More About Links," InstantDoc ID 20475.
Change the vb code to allow for a manual pick of contacts folder, ie not hardcoded. If you have contacts stored in another folder, this is very appriciated.
Running XP Home Edition with XP Office Pro:
Gave very erratic results -- some worked, others didn't. Blanked out names, etc. Changed the REGISTRY as suggested, but there was no difference. Standard form replaced custom form here and there, etc.
Hello! I was very pleased to find this article, since the hundreds of links in my OL2002 .pst file were lost when I was required to export/import everything to fix another problem. However, not being a Visual Basic expert, I can't figure out how to actually run the code you provide with this article. I tried renaming the .txt file to .vbs and that didn't work. Can you tell me how to run the code? Thank you!
Goran, take a look at the Namespace.PickFolder method, which returns a MAPIFolder that the user selects.
Don, copy and paste the code from the .txt file into an Outlook VBA module. If you need really, really basic info, see http://www.win2000mag.com/Articles/Index.cfm?ArticleID=21522
Hi Sue Mosher,
I see that Object Link name doesn't contain the Preffix Name, In this case the script doesn't work because objLink.Name <> FullName. So one suggestion is to parse ObjLink.name into FirstName, MiddleName, LastName and use them as criteria for search. I hope this is not just an error in My outlook contacts. Thanks for your Article.
I ran the script, but nothing seems to happen. The script says it's running and finishes in less than 30 seconds. I have thousands of contacts so I expected it to run for a while. The error is not fixed after running the script.
I'm running OL 2000 SP-3 under Win2K. I ran the script by importing it into OL's VB engine, using Run Macro, and clicking my Contacts folder. Do I need to do anything else?
I found another fix that worked perfectly:
http://support.microsoft.com/?kbid=242074
This is a utility to clear OL's nickname cache.
Check out this great tutorial on using Microsoft Outlook for managing your ebay & amazon sales, or use it as an Outlook programming quickstart:
http://www.321books.co.uk/ebooks/outlook-vba-tutorial.htm