Dmitry Kostochko

HowTo: Convert Exchange-based email address into SMTP email address

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.

Note. The code is provided as-is without warranty of any kind. It is written only for demonstration purposes and may not work correctly in your scenario.

Updated 5-Jul-2010: The samples were modified to support Outlook 2010 x86 and x64; the samples were rebuilt with Add-in Express 2010.

Updated 4-Jun-2018: It is possible to add an Exchange user to your local Address Book. This scenario (and solution) is discussed at https://www.add-in-express.com/forum/read.php?FID=5&TID=15007.

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

49 Comments

  • Ryan Farley says:

    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.

  • Dmitry Kostochko (Add-in Express Team) says:

    You are right, it can also be done that way. Thank you.

  • Himz says:

    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.

  • Dmitry Kostochko (Add-in Express Team) says:

    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.

  • Jasper Siegmund says:

    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?

  • Dmitry Kostochko (Add-in Express Team) says:

    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.

  • Dmitry Kostochko (Add-in Express Team) says:

    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!

  • Ed Salgado says:

    I don’t suppose you have an example of doing this in Delphi do you?

    Thanks!

    -ed

  • Daniel Garcia says:

    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!

  • Dmitry Kostochko (Add-in Express Team) says:

    Hello Ed,

    We don’t have such a sample in Delphi, or more precisely we don’t have a sample that could work with all Outlook versions and that can be compiled using any Delphi version.

  • Dmitry Kostochko (Add-in Express Team) says:

    Hello Daniel,

    Thank you for your suggestion. It is a really good idea!

  • Mark says:

    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

  • Dmitry Kostochko (Add-in Express Team) says:

    Mark,

    The GetSMTPAddress method expects a string as the parameter. So, you just need to pass the “from” variable to the GetSMTPAddress method.

  • Eugene Starostin says:

    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.

  • Mark Hodgkinson says:

    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?

  • Dmitry Kostochko (Add-in Express Team) says:

    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.

  • Pankaj Anand says:

    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

  • Dmitry Kostochko (Add-in Express Team) says:

    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?

  • Pankaj Anand says:

    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

  • Pankaj Anand says:

    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

  • Pankaj Anand says:

    smtpAddress = GetMAPIProp(entry.MAPIOBJECT, MAPI.PR_SMTP_ADDRESS);
    also throws the same exception saying item could not be found.

  • Dmitry Kostochko (Add-in Express Team) says:

    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.

  • Pankaj Anand says:

    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

  • Pankaj Anand says:

    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.

  • Dmitry Kostochko (Add-in Express Team) says:

    Hi Pankaj,

    I think you can use the SenderEmailAddress and SenderEmailType properties:
    https://msdn.microsoft.com/en-us/library/aa171942(v=office.11).aspx
    https://msdn.microsoft.com/en-us/library/aa171944(v=office.11).aspx

  • Pankaj Anand says:

    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

  • Dmitry Kostochko (Add-in Express Team) says:

    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:
    https://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?

  • glenn says:

    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.

  • Dmitry Kostochko (Add-in Express Team) says:

    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.

  • Dmitry Kostochko (Add-in Express Team) says:

    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:
    https://www.add-in-express.com/forum/read.php?FID=11&TID=10180

  • Tim Rasmussen says:

    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?

  • Dmitry Kostochko (Add-in Express Team) says:

    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?

  • Tim Rasmussen says:

    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.

  • terminat5r says:

    IUnknown* pUnk= NULL;
    olAddEntry->get_MAPIOBJECT(&pUnk);
    if( pUnk)
    {
    IMessage* pMsg;
    pMsg = (IMessage*) pUnk;
    LPSPropValue result = NULL;
    HRESULT hr;
    hr = HrGetOneProp(pMsg, 972947487, &result);

    if( hr == S_OK )
    {
    bstrAddress = SysAllocString(result->Value.lpszW);
    MessageBox(NULL,bstrAddress,L”message”,0);
    }
    }

    I use this code to get SMTP address from exchange address.
    It success with Microsoft exchange server but fail with [Office 365]
    Can you help me?

  • Dmitry Kostochko (Add-in Express Team) says:

    It looks like the PR_SMTP_ADDRESS property does not exist when Outlook is connected to Exchange Online. I would suggest trying other properties, you can use the OutlookSpy tool to examine all existing Extended MAPI properties.

    Thank you for your comment!

  • terminat5r says:

    Hi Dmitry,
    Thank you so much for your help!
    I think my problem is get MAPI property PR_SMTP_ADDRESS_W ,it may not exist. I try to use PR_SMTP_ADDRESS_A .

  • Dmitry Kostochko (Add-in Express Team) says:

    Probably you are right. Please let me know if the PR_SMTP_ADDRESS_A property works.

  • Jørgen says:

    Hi!

    We’ve just recently bought Add-In Express at work and we’re only in the startup of setting up integration with Office.

    Now we’ve run into a problem: in many cases we need to read SMTP-addresses from an Exchange Group. The sample project provided here does only read a single contact. Could you provide an example of how to read SMTP-addresses from a group?

  • Dmitry Kostochko (Add-in Express Team) says:

    Hi Jørgen,

    We don’t have a ready made sample that handles Exchange Groups. But I think the groups can be handled without any problems. In terms of the Outlook Object Model you will have to deal with the DistListItem or ExchangeDistributionList objects. The first object has the MembersCount property and GetMember method. The ExchangeDistributionList object has the GetExchangeDistributionListMembers method. So, you will be able to loop through all members of the group, get their EX-based addresses and convert them to SMTP.

  • Jørgen says:

    @Dmitry Kostochko (Add-in Express Team): Thank you for your reply.

    As part of a strategical solution we’ve changed our requirements to support only Office 2010 and above. Thus getting members of an Exhange Group becomes very easy :)

  • Dmitry Kostochko (Add-in Express Team) says:

    Hi Jørgen,

    A good solution! :)

  • Brian Coverstone says:

    We have a customer who was having an issue with the PR_EMS_AB_PROXY_ADDRESSES lookup, where it was returning garbled text. In my research I found an alternative way to obtain an exchange to SMTP address lookup. Does this seem like a reasonable alternative?

    Dim exchangeAddress As String = “”
    Dim SMTPaddress As String
    Dim oMailItem As Outlook.MailItem
    oMailItem = OlApp.CreateItem(Outlook.OlItemType.olMailItem)
    oMailItem.To = exchangeAddress
    oMailItem.Recipients.ResolveAll()
    SMTPaddress = oMailItem.Recipients.Item(1).AddressEntry.GetExchangeUser.PrimarySmtpAddress

  • Dmitry Kostochko (Add-in Express Team) says:

    Hi Brian,

    Yes, this code seems to be correct, it uses valid Outlook Object Model methods and properties.

    Don’t forget to release COM objects.

  • Robin Van Der End says:

    @Brian Coverstone

    Thanks, that piece of code is very usefull!

    SMTPaddress = oMailItem.Recipients.Item(1).AddressEntry.GetExchangeUser.PrimarySmtpAddress

  • Kushan Randima says:

    Hi,

    I use following code inside a method to convert an exchange type email address into SMTP. Here, the outlookExchangeUser variable is always getting null when I use a room mail box as the recipient. Please advice me

    //Some code here
    outlookAddressEntry= outlookRecipient.AddressEntry;
    outlookExchangeUser= outlookAddressEntry.GetExchangeUser();
    //Some code here

    Thank you

  • Dmitry Kostochko (Add-in Express Team) says:

    Hi Kushan,

    I have just tested this scenario and see that GetExchangeUser() returns the correct value for a room resource/recipient. What value is set in the AddressEntryUserType property of your room?

  • Peter Talbot says:

    Similar issue using VBA to retrieve the sender email address in the desktop version of Outlook (Microsoft 365 Apps for business – Version 2112) which gets an X.400 address if the sender is local to my AD, so…

    Set NewMail = oInspector.CurrentItem
    x = NewMail.SenderEmailAddress
    If Left(x & ” “, 1) = “/” Then
    ‘ convert from X.400
    x = NewMail.Sender.GetExchangeUser.PrimarySmtpAddress
    End If

  • Ganpat says:

    hi,

    it’s not proper working for outlook 365(2013) for some email address its given blank SMTP address

    if (entry.Type == “EX”)
    {
    string smtpAddress = string.Empty;
    if (this.HostMajorVersion >= 14)
    {
    smtpAddress = GetSMTPAddressViaOutlookObjectModel(entry);

    if (string.IsNullOrEmpty(smtpAddress))
    {
    smtpAddress = GetMAPIProp(entry.MAPIOBJECT, MAPI.PR_SMTP_ADDRESS);
    }

    }
    else
    {
    smtpAddress = GetSMTPAddress(entry.Address);

    }

    _strEmailAddressList = _strEmailAddressList + entry.Name + ” , “;

    }

  • Andrei Smolin (Add-in Express Team) says:

    Hello Ganpat,

    I suggest that you debug the code to find out the cause of this. May I ask you to share your modifications with other developers?

Post a comment

Have any questions? Ask us right now!