It would be true to say “get” rather than “convert”. There could be only one right way – to use Extended MAPI. Another method is described in the MSDN article: How to retrieve alternate e-mail addresses by using CDO, but we will not see into this approach, because CDO is optional in Outlook 2003 and is absent completely in Outlook 2007.
So, Microsoft Exchange Server can operate with email address types such as Exchange, SMTP, X.400, Microsoft Mail, etc. By default, the Address property of the Mail.Recipient object returns just an Exchange type address, for example this one:
/O=ORGANIZATION_NAME /OU=EXCHANGE_GROUP /CN=RECIPIENTS /CN=USER_NAME
To get other address types, we need to find the recipient in the Outlook address book by using the IAddrBook.ResolveName method, then reach the IMailUser interface with the IAddrBook.OpenEntry method and get the PR_EMS_AB_PROXY_ADDRESSES property. The code below gets the Address property from NameSpace.CurrentUser.AddressEntry, checks the address type and obtains the SMTP address if it is of the Exchange type:
Private Sub CommandBarButton1_Click(ByVal sender As System.Object) _
Handles CommandBarButton1.Click
' Outlook Explorer button
Dim ns As Outlook._NameSpace = OutlookApp.Session
If ns IsNot Nothing Then
Try
Dim currentUser As Outlook.Recipient = ns.CurrentUser
If currentUser IsNot Nothing Then
Try
Dim entry As Outlook.AddressEntry = _
currentUser.AddressEntry
If entry IsNot Nothing Then
Try
Dim smtpAddress As String = String.Empty
' Exchange address
If (entry.Type = "EX") Then
' Outlook 2010
If (Me.HostMajorVersion >= 14) Then
smtpAddress = GetSMTPAddressViaOutlookObjectModel( _
entry)
Else
smtpAddress = GetSMTPAddress( _
entry.Address)
End If
Else
smtpAddress = entry.Address
End If
MessageBox.Show("SMTP Address:" + _
Environment.NewLine + _
smtpAddress)
Finally
Marshal.ReleaseComObject(entry)
End Try
End If
Finally
Marshal.ReleaseComObject(currentUser)
End Try
End If
Finally
Marshal.ReleaseComObject(ns)
End Try
End If
End Sub
I will not publish the whole code of the GetSMTPAddress method right here, because it is rather huge. You can download VB.NET and C# samples with source code, including the declaration of Extended MAPI interfaces, types, tags and properties via the links below.
That’s all for now, have a nice weekend!
Updated 5-Jul-2010: The samples were modified to support Outlook 2010 x86 and x64; the samples were rebuilt with Add-in Express 2010.
Available downloads:
The sample add-ins below were developed on Add-in Express 2010 for Office and .net
C# sample Outlook add-in for VS 2005
VB.NET sample Outlook add-in for VS 2005






33 Comments
The problem with doing it this way (that I have found the hard way) is that if the user is offline and does not have an offline address book OR the Exchange address is an unpublished address/user then this will fail and cause Outlook to prompt the user with a “Check Names” dialog, asking the user to choose someone else, etc – rather than just resolve it using the PR_EMAIL field for the AddressEntry.
You are right, it can also be done that way. Thank you.
I am having the same problem for the users that are not published. How can fix this?
I am not sure how to use PR_EMAIL field to fix this problem. I don’t see any such field in the AddressEntry.
I have just modified and uploaded both samples. Now they can get an smtp address by using the PR_SMTP_ADDRESS (or RP_EMAIL) property without accessing the Outlook address book.
Hello. This doesn’t seem to work with Outlook 2010. I get an error about it not being able to find entrypoint MAPIInitialize@4 in MAPI32.dll. Is there something I’m missing, or is this method not supported for Outlook 2010 use?
As far as I understand you are trying to test this sample with Outlook 2010 x64. In this case the sample will not work because it was developed when 64-bit Outlook version did not exist yet. I will try to modify the sample in the nearest future.
The samples were updated. Now they work for Outlook 2010 x86 and x64 as well using the new features of the Outlook 2010 Object Model. Thank you, Jasper, for pushing me in the right direction!
I don’t suppose you have an example of doing this in Delphi do you?
Thanks!
-ed
I like Add-In-Express a lot but I keep finding myself searching the forums in order to piece together the code needed to perform very basic actions. Like retrieving the SMTP address for an exchange address. I am sure many Add-In-Express users have spent countless hours trying to put this together and then hoping the code works in all versions of Outlook.
So here is a suggestion for the Add-In-Express team: would it be possible for Add-In-Express to add a “OutlookHelper” class that will contain methods such as GetSMTPAddress? These methods should be tested, supported, and work “out of the box” in as many versions of Outlook as technically possible. I do not really care for all the “vodoo magic” needed to make GetSMTPAddress work. I just want to call the method when needed and concentrate on writting my plugin. Isn’t this the reason we purchased Add-In-Express in the first time?
To the Add-In-Express team: keep up the good work, but note there are areas where further improvement would be tremendously appreciated by your users!
Hello Ed,
We don’t have such Delphi sample, or rather we don’t have a sample that can work with all Outlook versions and that can be compiled using any Delphi version.
Hello Daniel,
Thank you for your suggestion. It is a really good idea!
Hi
This is *almost* what I need, but how do you modify the sample code to deal with getting the smtp email address of the SENDER of the email and not the recipients?
I can get the string representation of an Exchange user who has sent the email with:
string from = mailitem.GetType().InvokeMember(“SenderEmailAddress”, System.Reflection.BindingFlags.GetProperty, null, mailitem, null).ToString();
but this just gives me the Exchange format. How do I convert that into an Outlook.AddressEntry such that the rest of the sample code then slots into place?
Thanks
Mark
Mark,
The GetSMTPAddress method expects a string as the parameter. So, you just need to pass the “from” variable to the GetSMTPAddress method.
Hello Daniel,
> To the Add-In-Express team: keep up the good work, but note there are areas where further improvement would be tremendously appreciated by your users!
Wow! I have a feeling your are reading my thoughts! :) We will focus on this for the entire next year.
Hi there
I have been experiencing issues with the code in this blog – it works fine, however it fails in the MAPIInitialize call saying it could not find an entry point in mapi32.dll for MAPIInitialize@4.
This only happens on MS Outlook 2010 64bit. The posts above however suggest that this issue was actually fixed.
Does the sample project at the end of the link point to the updated source code?
Hello Mark,
I have just re-tested both samples (C# and VB.NET) against Outlook 2010 x64. Both work fine. I noticed that piece of code that was published in this post is out of date and corrected it. Please see the GetSMTPAddressViaOutlookObjectModel method, it is this method that should be used in case of Outlook 2010 x64.
Hi,
I tried your sample (with outlook 2010 x64), but I always get an exception which says item could not be found. This happens in both cases when I use the OutlookDomainModel and GetSMTPAddress function.
In my case, I am not connected to the exchange server, but I thought (as per your previous comments) that the code will take care of this scenario.
What could be wrong or is there another way of solving this problem?
Thanks
Pankaj Anand
Hi Pankaj,
We always test our samples before publishing, I have just retested this against Outlook 2010 x64 and did not see any exception. What code line throws the exception on your machine?
The exception is raised on this line. Th exception is “Exception has been thrown by the target of an invocation.”
return user.GetType().InvokeMember(“PrimarySmtpAddress”, System.Reflection.BindingFlags.GetProperty, null, user, new object[] { }).ToString();
in GetSMTPAddressViaOutlookObjectModel function.
I have been using MS Visual Studio 2010 and I do get a warning at the time of registration asking me to use latest version of Add-in express loader. But I continue to use the same loader as in your code. It registers successfully, and I reckon that is not an issue.
I am testing on a PST which is disconnected from its exchange server. And i tried printing all members (using reflection) of the user com object but I don’t see any primarysmtpaddress in it.
Thanks
Pankaj
Another piece of information…
the inner exception is “The item could not be found”. Since I had archived all exchange mails in a PST and I am trying to read it when there is no exchange server present (these are emails from my last organization), the GetExchangeUser returns a user object which does not contain any properties which has an SMTP address.
Could this be the case? Would using the PR_SMTP_ADDRESS help me. I will test this and let you know the status for this as well.
Thanks
Pankaj
smtpAddress = GetMAPIProp(entry.MAPIOBJECT, MAPI.PR_SMTP_ADDRESS);
also throws the same exception saying item could not be found.
Hi Pankaj,
It’s a really strange issue. The point is that PrimarySmtpAddress is a normal property of the Outlook 2010 Object Model. Please try to create a new add-in for Outlook using 2010 PIAs and get the PrimarySmtpAddress property directly by using early binding rather than late binding.
Hi Dmitry,
I have been able to use your code to get the SMTP email addresses for exchange users.
The problem that I am facing now is that the conversion doesn’t happen for the sender’s email address. Because there is no recipient object that I can obtain for the sender of the email.
For now, I have implemented a work around which creates a new MailItem and add sender as a recipient (using the sender’s name). And then I use Receipient.Resolve() method to get the email address. It works, but I have a few questions…
1. Is there a better way of getting the sender’s SMTP email address?
2. If the exchange allows creation of two users with the same name. I am afraid that this call will open a resolve dialog box to the user, which I dont want.
Thanks
Pankaj Anand
Small update to my problem
I have to support Outlook 2003 and above, so I cannot use Mailitem.Sender property which recently got added in 2010.
Hi Pankaj,
I think you can use the SenderEmailAddress and SenderEmailType properties:
http://msdn.microsoft.com/en-us/library/aa171942(v=office.11).aspx
http://msdn.microsoft.com/en-us/library/aa171944(v=office.11).aspx
Hi Dimitry,
Thanks a lot. I have another small issue. I tried your code on Outlook 2007 and it says MAPI ca not be initialized when I try to use the GetAddrBook() function. Can you please tell me what could be wrong?
Pankaj
Hi Pankaj,
I suppose the MAPIInitialize function (which is used in the GetAddrBook method) returns an error. You can find the full description of the function in the following MSDN article:
http://msdn.microsoft.com/en-us/library/ms527051(EXCHG.10).aspx
Do you use our code in an Outlook COM add-in or in a standalone application? Did you make any changes in our code?
Was this code ever revised to support when the user is offline and does not have an offline address book or… read below
The problem with doing it this way (that I have found the hard way) is that if the user is offline and does not have an offline address book OR the Exchange address is an unpublished address/user then this will fail and cause Outlook to prompt the user with a “Check Names” dialog, asking the user to choose someone else, etc – rather than just resolve it using the PR_EMAIL field for the AddressEntry.
Hi Glenn,
The samples demonstrate two ways of retrieving SMTP-based email addresses. One of them does not use address book at all, it just gets the PR_SMTP_ADDRESS (aka PR_EMAIL) property from AddressEntry.
Please download the sources and pay attention to the CommandBarButtonPR_EmailAddress1_Click and CommandBarButtonPR_EmailAddress2_Click methods.
Hi Glenn,
I have just finished testing the code against Outlook 2007 in Offline mode, neither way worked offline. Please see the details on our forum:
http://www.add-in-express.com/forum/read.php?FID=11&TID=10180
This is extremely useful sample code. But I worry that the GetAddrBook method, if successful, does not release some of the objects and pointers used to retrieve the Address Book. Is this a problem?
Hi Tim,
I have just reviewed the code: the sessionPtr, sessionObj and addrBookPtr variables are released, addrBookObj is returned by the GetAddrBook method. Could you please point me to the objects and pointers you mean?
Hi Dmitry,
Sorry, I forgot that the “finally” statements after the successful “return” statement do get executed. At least one of our customers is now using our add-in with your sample code in and it works superbly! Thank you.