I need access to the contact id in my emails. I currently use the tracker in a rendering controller, but it only runs once for all emails. (Wondering if caching is turned on or I need to open enable personalization).

I tried using tokens but tokens only talk to facets. Is there a way, like tokens, to get the contact Id reliably?

Update: Turning personalization on made it run the footer each time. But I wish I could do contact ID like I do tokens.

  • 1
    I believe you need to override the default token map and add "Contact ID" to the token dictionary. See doc.sitecore.com/developers/exm/90/email-experience-manager/en/….
    – João Neto
    Jan 8, 2020 at 10:32
  • João Neto that is useful, but the token mapper is bound only to facets and not actual contact itself. The contact ID isn't in an Sitecore facets.
    – Chris Auer
    Jan 8, 2020 at 14:28
  • I think you'll need to override one of the pipelines that does the token or link replacement. The link replacement pipeline for example encrypts the contact ID along with other things. Jan 9, 2020 at 3:46

1 Answer 1


My custom email preferences (page to opt out of lists) is /emailpreferences.

The first thing you need to do is to trust in the RedirectUrlPage setting. This page url replaces all the links on your email. This is for tracking and other services. But what is important is that RedirectPageUrl.aspx does a lot of work. For me, what is important is that if you pass the page a ContactIdentifierSource and a ContactIdentifierIdentifier, the redirect page will new up the EXMContext which has all the details I need.

Step 1 add my page to the carryOverField configs

This is so the RedirectUrlPage knows to include it when someone asks for the /emailPreferences link.

<carryoverField type="Sitecore.EmailCampaign.Cd.Pipelines.RedirectUrl.CarryoverField, Sitecore.EmailCampaign.Cd">
    <param desc="fieldKey" ref="settings/setting[@name='QueryStringKey.ContactIdentifierSource']/@value" />
    <param desc="urlPattern">SubscriptionPreferences.ashx|.*ConfirmSubscription.aspx|.*Unsubscribe.aspx|UnsubscribeFromAll.aspx.*|.*sc_pd_view=1.*|emailpreferences.*</param>
<carryoverField type="Sitecore.EmailCampaign.Cd.Pipelines.RedirectUrl.CarryoverField, Sitecore.EmailCampaign.Cd">
    <param desc="fieldKey" ref="settings/setting[@name='QueryStringKey.ContactIdentifierIdentifier']/@value" />
    <param desc="urlPattern">SubscriptionPreferences.ashx|.*ConfirmSubscription.aspx|.*Unsubscribe.aspx|UnsubscribeFromAll.aspx.*|.*sc_pd_view=1.*|emailpreferences.*</param>

Now in my emailPreferences controller, the ContactIdentifierSource and ContactIdentifierIdentifier will be in the url, encrypted. But the fact that they existed when RedirectPageUrl was run, EXM hydrated the EXMContext for the page request. In my controller I can access the source/identifier and all the other message details in the EXMContext.

source = ExmContext.ContactIdentifier.Source;
identifier = ExmContext.ContactIdentifier.Identifier;

I can now use the source/identifier and call into xConnect to get all the contact's real details.

This is the flow.

  1. Add /emailprefences anywhere in my email. It is important to make it relative because EXM is going to treat it as an internal link, allowing you to add tokens to it.
  2. When the email is generated, Sitecore takes the /emailpreferences link and reformats it as /..../RediectUrlPage.aspx?ec_eq=LtlTlrs3hE2pR....... In the ec_eq is the encryted query string for all the information about the email.
  3. When the user clicks the RediectUrlPage.aspx link, the pipeline runs.
    • The pipeline decrypts the query string, finding out all the info about the email like messageId, campaign, etc...
    • It looks at the OriginalUrl (/emailpreferences) and looks it up in the carryOverFields list.
    • If it find the link in the carryOverFields, for each one it finds it builds a new query string and then encrypts it again.
  4. Out of the pipeline comes the FinalUrl which is encrypted if any carryOverFields were found. And just the originalUrl if no matches were found.
  5. The user is rediected to the /emailpreferences page with the encrypted ContactIdentifierSource and ContactIdentifierIdentifier in it.
  6. When the httpBeginRequest pipeline sees the ec_eq, it decrypt it and hydrates the EXMContext object. This is a static object that you can use in your code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.