Skip navigation
All Places > Products > Blog
1 2 3 4 5 Previous Next

Products

362 posts

**Posting on behalf of Chelsea Kiko Marketing Automation Team Lead at Hileman Group**

 

Reporting in Various Marketo Spaces

I have been building Marketo architecture and planning strategic marketing automation plans for about five years now and I still get the Marketo question about reporting. ‘Is that in Marketing Activities or Analytics section?’ – and there is a lot of confusion about which is better, which holds what type of reporting and what works best for subscriptions.

For me, it really comes down to the question ‘what are you trying to report?’ – if it is instance-wide and holistic reporting, I want to always say head to the analytics section to build those reports. However, there are reasons for usage of both and I will go through that in this blog post.

 

The biggest difference between program-level marketing activities reporting is the level of the reporting you want to accomplish. Analytics section is for that holistic reporting on a large group of assets/activities or even the whole instance. Also, if you want to see more details on ‘who’ not just the numbers, then program level reporting is your best bet as it can dive into the details a little more than analytics reporting can, and also, it makes more sense to build some reports next to the programs so that folder/reporting organization is intact.

 

I am going to talk about key factors and which reporting space would be a better for common situations.

 

Dashboard/Monthly Instance-Wide Reporting

I use analytics reporting for all my high-level reporting for my instance. For example, if I want to see how all my emails are doing YTD – I will use email insights and get that reporting. However, you can change your time period and pick and choose what emails you report on – but, this is a nice view for high level reporting or dashboards.

Image_01_Elevate_Analytics.jpg

 

Speaking of dashboards, depending on what type of tool you use, you may have to have data sources plug in to that external platform. Or, maybe you have a reporting dashboard where you still check out the instance and record it. Either way, it is great to organize reporting for dashboards in the analytics section. This makes it clean, easy to find and doesn’t get cluttered by marketing activities programs that are being deployed.

Image_02_Elevate_Analytics.jpg

 

**Expert Tip** [see below]– one nice feature of analytics reporting is you can actually layer on smart lists to your reporting to add additional detail for a holistic report. The below screenshot shows a lead lifecycle report with additional UTM smart lists so we can see exactly where each lead came from within the lead lifecycle. This is simply done by creating the smart lists and then adding them in within the setup tab of the report. You can also drill down on certain fields or attributes to see more information about the report. For example, say you want to add the custom columns of various UTMs and then drill down the reporting by company name – below is how you’d do that to achieve more data. This cannot be done to this extent in marketing activities.

Image_03_Elevate_Analytics.png

Image_04_Elevate_Analytics.jpg

Image_05_Elevate_Analytics.jpg

 

User & Roles

This is a popular reason to do reporting in analytics (or database) vs program level, marketing activities reporting. Many times, we want to make sure we have our users and roles to the point where it makes sense for the organization. If you tend to have a marketing person go rogue in Marketo when they want to see reporting but then manipulate or change marketing programs, you can lock them down to just see the analytics area of Marketo. Or, another reason for this would be for possibly a role where a team member’s role is to report how the marketing influenced campaigns are helping overall ROI. This way, you can give the user access to analytics, send them the Marketo link and they can export their own data. For example, Matty Marqeto is your analytics manager and he needs to see pre-built reports (or reports he builds on his own) in order to connect his dashboard and complete his role on the team. You can give him access to just the analytics section of Marketo so he can get in, pull the numbers he needs, and then go about his day. You can also do this in the database section of Marketo for smart lists. If you want to build out a smart list of data and don’t want to give the analytics manager or campaign reporter access to marketing activities – you can build the smart list in database and give the user access to database and analytics section only in Marketo. You can even choose if the user can export data or not – which is a nice feature.

Image_07_Elevate_Analytics.jpg

 

Specific Reporting by Campaign

It is best practice to build reports in advance within a program process template so when a new program is created or cloned, you have readily available common reporting within each program. This can help the campaign stakeholders know what reporting is available and be able to easily see the reporting in the program instead of searching in analytics.

Image_08_Elevate_Analytics.png

 

It is nice to have these reports ready because campaign specific reporting should be done at the program level versus in analytics so the organization is consistent and campaign stakeholders know where to find the reporting.

 

Subscriptions

Both the marketing activities reporting and analytics reporting can create subscriptions to be mailed to a user on a predetermined frequency. All you have to do is create the report how you want and then right click and create new subscription. The subscription will live where the report lives, so remember that if you want someone to have access to be able to modify the report. For example, Susan cannot edit her smart list report from her event in analytics section if the report lives in marketing activities.

 

Ad Hoc Reporting & Troubleshooting

Lastly, another common reason why users dive into the marketing activities program reporting versus analytics is for additional reporting and troubleshooting within campaigns. It makes sense to keep everything grouped together. When troubleshooting a potential area within a campaign, many times smart list reporting or even local asset reporting is used to see what an issue could be and how it can be resolved. Building these in the programs is best practice so all of the data is organized within the campaign and doesn’t get lost in another area of the platform like analytics.

 

The same goes for ad hoc reporting. For example, you have a unique campaign that needs some extra reporting for various campaign owners, so building it within the tree organization in the campaign makes sense to all parties. The reports can be easily found and reported on that campaign only.

 

Those are some common reasons to use one section of Marketo over the other and some extra details on why. Reporting with third parties can make these practices change as well as internal team organization.

Custom Forms 2.0 JavaScript behaviors are best managed via an external JS file and <script src="/yourfile.js"> tag in the LP. This allows your code to be updated without touching any other part of the page or form, sharing behaviors across forms & pages, and so on.

 

At tonight's NYC MUG meeting, my man Nick asked if you could put the custom behaviors JS into the form itself via Form Editor.

 

Indeed, if you want a quick-and-dirty JS enhancement, and you don't want to figure out where in the LP to put your <script> tag[1] or talk to your webmaster, yes, it's possible to use the Forms JS API from a Rich Text area. If you insist.

 

That should be good news! The only, let's say, more guarded news is that you have to do it right or can get craaaaazy results.

 

There's one major concern and one minor concern:

 

    (1) Major: You must ensure the code in your embedded <script> only runs once. Because of the curious way in which forms are rendered, this is a harder than you probably think.

    (2) Minor: You have to completely hide the Rich Text area so it doesn't show up in the layout, which means hiding its entire form row (margins, padding, et al.).

 

(2) is easy to accomplish with some CSS. So let's wait on that.

 

Run only once

Let's see what happens if we naïvely add a RT area containing a <script> with a simple whenReady listener function inside. Note I've put some text at the top of the RT so it looks in-use in Form Editor (“[Form Behaviors JS - Do Not Delete]”). Such text is optional but recommended; otherwise, the RT might be accidentally deleted as it looks empty until you double-click it.

 

ss

 

When you load a page with just that one Marketo form in it, you might see the following Console output:

 

ss

 

That's the same function run 4 different times even though we only have one Rich Text. Really bad if you're adding event listeners!

 

This happens because of the way the <form> DOM is built out. As the <script> is ejected and injected into the page repeatedly, it ends up executing its code repeatedly.

 

And that's not the same function running, technically speaking, but 4 functions that happen to have the same code running in a row. Because they're all separate from each other, they don't share a parent scope in which you could add behaviorsLoaded = true or something like that.

 

Instead, you can set an HTML data- attribute on the <form> element, since that will of course persist across executions. Each time the code runs, check for the attribute and return immediately if it's already true:

 

ss

 

In copy-and-pastable form:

 

[Form Behaviors JS - Do Not Delete!]
<script type="application/javascript">
MktoForms2.whenReady(function(form){
  var formEl = form.getFormElem()[0];

  if( formEl.getAttribute("data-inline-behaviors-loaded") == "true" ) {
    return;
  }

  formEl.setAttribute("data-inline-behaviors-loaded", "true");

  // now continue
  console.log("Doing something special");
});
</script>

 

Now you can see the meat of the code only runs once:

 

ss

 

Back to CSS

If you make the Rich Text area the first row in Form Editor, it's easy to select and hide:

 

ss

 

Copypasta:

 

.mktoFormRow:nth-of-type(1) {
    visibility: hidden;
    position : absolute;
}

 

I'd typically recommend a more resilient method of selecting the right row. But that would likely involve loading my FormsPlus::Tag Wrappers helper JS first… problematic if the whole idea is to consolidate the JS all within the form!

 

 


NOTES

[1] As a reminder, when not using the Rich Text method described here, put the behaviors <script> just inside the closing </body> tag on a Marketo LP, or anywhere after the form embed code on a non-Marketo LP.

Featured in the October edition of the Fearless Forum, Amber Hobson of Applied Systems is walking us through her journey of implementing Dynamic Content. In this master class, Amber goes into detail about her team's marketing strategy before rolling out Dynamic Content, lessons learned during implementation, and how it ultimately impacts marketing efficiency and reporting.

 

Q1: Can you describe how you leverage personalization at your organization?

Every single email is personalized to some extent. Our CMO is very much about the right content to the right person. We had implemented specific letterhead, envelopes, etc. throughout the organization to ensure that when you receive something from Applied, the address matches your country’s main location. He wanted us to do this for digital as well. We started with multiple emails for each region to get the right footer address, which later grew into the sophistication that we have today.

 

Q2: What are some specific benefits you’ve seen from implementing personalization?

It saved time for our Demand Gen team significantly! It’s much easier to change words or make minor edits within the Dynamic Content than it is to create multiple emails and set up our smart campaigns to send the right one based on country. Now, we can just build a single email and schedule it in a simple campaign.

 

It also had an unanticipated benefit where it can now flow into our reporting. We can actually do our reporting for email statistics based on the Dynamic Content segments as well. This is huge for our regional teams! It allows us to see how an email performs based on each group. For example, we’ve learned now that shorter emails perform better in North America while longer emails are better received in Europe.

 

Q3: Can you go into detail about efficiencies?

We work in 4 countries and technically 2 languages. In our industry, there are minor wording changes even between the US and Canada. This means that we were having to build separate emails for just a single word or a CTA link change. At this point building multiple emails for minor nuances was difficult to manage and we would have a single program with at least 5 emails to ensure we were getting the right content to the right person. By implementing Dynamic Content, we were able to scale down to a single email that we segment appropriately to make the necessary regional changes. We always start with the US (our largest market) and then we can quickly run a find/replace for some of the smaller copy changes.

 

Q4: How are you setting up your Dynamic Content campaigns within Marketo?

Our most used campaign is our Geographic segment. We set up a segment to catch country & language for everyone in our database. We’ve had to expand this segment over time as our company has grown by adding other markets. We also switched to using the State/Country picklist functionality in SFDC. One thing you have to remember is that when a change like that is made, you have to update all of your segments. Otherwise you end up with more people in the “Default” category than you want.

Picture1 (1).png

Then we created a Footer & Unsubscribe snippet for our emails as the most basic quick win. This allows us to have unique subscription centers and to include our local addresses in the footer of our emails.

Picture2 (1).png

Picture3 (1).png

Picture4 (1).png

Then for every email we do, we use that Snippet in our footer section.

Picture5 (1).png

 

Q5: What are some unique ways you’re leveraging Dynamic Content with Marketo?

We have two unique ways that we’re using Dynamic Content. One is geography. All emails automatically have a geographic segment added, even if it is just for the footer & unsubscribe content. The second method that we do is leverage Acuity to manage scripts. We use Acuity to provide each of our sales reps with their own calendar link. Then we create a segment based on SFDC account owner and simply change the URL based on the reps.

Picture6 (1).png

 

Q6: How are you layering features of Marketo to make Dynamic Content work for you by utilizing tokens/buttons?

This one took us a while to figure out! We had been using Dynamic Content for our copy for years before we realized that we could use it for our CTA links as well. We have added Dynamic Content to each of our five program tokens, which we use to populate our CTAs. We standardized our CTA to always include one of these tokens (with a few minor exceptions).

Picture7 (1).png

We also layered Marketo features into our modules when we are working in a newsletter. We have our client newsletter that goes out each month and each module corresponds loosely to a certain product. We segmented each module to have different content based on if you do or do not have that product. It gets crazy when working through QA, but we’ve identified key client accounts that will get specific content sections that we use as our QA people.

Picture8 (1).png

 

Q7: What was the trial and error process like leading up to the current Dynamic Content model you’re using?

It was more just us being paranoid about what we thought might happen versus what is actually likely to happen! We put our marketing team on every email that went out, but since we all have US information, the test results may not always be ideal. We got so many questions from the team asking if it should have said this or if it was correct for the market. I think we finally have them set up to understand it, but it made everyone so nervous!

 

Then, we had to train our communications team how to write the copy so that we were getting all regions at once so we could actually schedule them correctly. The other issue with the geographic segment was that we used to have our French copy translated for a later date, but now we’re providing the copy at the same time as the other regions. It creates a better experience for our client base (especially because a single account may have both French & English filters), but it took some training for our team.

 

Q8: What was the most challenging part of building out your Dynamic Content model?

It took a lot of research to decide how we wanted to start. We knew that building three (at the time) different emails every time that we sent something wasn’t working, but we weren’t sure how to fix it. After digging around on the Marketing Nation Community, talking to other users, and then going through trial/error, we decided that Dynamic Content was the way to go. Building out our segments was very challenging. We found originally that our data wasn’t as clean as sales thought it was, so we had to do a clean up campaign in SFDC and then we set up standardization for country & language across all areas of SFDC as well as within our Marketo forms. We still do periodic audits to ensure the data is correct and have had to expand our standardization to other systems that simply touch SFDC or Marketo (finance system, implementation system, etc.)

 

Q9: What advice would you give to Marketo users who are considering implementing Dynamic Content for localization purposes?

Think through your segments. You have to remember that no person can be a member of two segments so if there is any chance of overlap, you may need to diagram it out. And start small! Pick one type of item to do dynamically. For us, it was geography. As soon as you have that first one worked out, the ideas will just flow and you will find so many uses!

 

We hope you enjoyed reading about how Applied Systems is leveraging Dynamic Content to make the lives of their marketers easier.

In the feedback from our Marketo Fearless Forum: Edition 03 , we received a lot of comments asking for more information on the inaugural members of our Fearless 50. As a result, we have created a new series for our customer newsletter called How 2B Fearless.

 

In this first edition, we sat down with Brooke Bartos, who is not only a Fearless 50 member, but she is also a Marketo Champion and a Chicago MUG Leader. Brooke tells us about what being a fearless marketer means and what that has meant for her career.

 

What does fearless marketing mean to you?

Fearless marketing means knowing the risks and the rewards of trying something new and making an educated decision with full commitment.

Who is a fearless marketer you look up to and why?

When it comes to fearlessness, I have always admired Oprah Winfrey for the brand and the legacy she has created. When you learn about her background, her childhood, and her teenage years, this is someone who had every excuse not to succeed, and yet, she did in the most spectacular of ways. Oprah has become a globally recognized brand in media, literature, and consumer products. She chose to rise above the obstructions life placed in her path.

How did your career start out in marketing?

I went to school for psychology because I was intrigued by the puzzle of what motivates people. My first internship out of college was working in a market research department for a major automotive manufacturer, where I worked on the relaunch of their dealership incentive program. This relaunch was heavily based on feedback gained through interviews, surveys, and focus groups about what motivates them in the sales process. I learned that when it comes to business, there are subtle ways you can influence behavior through how you communicate— words, images, and styling that you use in marketing is all psychology at the core.

 

How did you get to the point you are at in your career today?

I learned a tremendous amount about how to communicate with people through my market research internship and time in field marketing. These experiences helped me learn what motivates people and how to talk to them.

When I went to work for a company where I had my hands in just about every element of our marketing, both  and offline, I was able to bring all that knowledge to helping transform the company from a traditional offline marketing company into one focused primarily on digital marketing. It was not an easy transformation! It took gaining buy-in from areas of the organization that were ingrained in the traditional marketing ideas of print and tradeshows and getting them to try new channels, upgrade strategies, and prove results.

 

That company was where my Marketo journey began. At first, I was a part-time user, “backup trigger” to our admin at the time. When she left, I asked to move into that role, but the response I got from HR was “no.” They wanted to bring in someone with more Marketo experience to manage and grow the instance. I started job hunting—this was something I was strongly interested in, and if that meant that I had to go out to go up, I would.

 

During the process, my boss found out I was interviewing. We were able to sit down and have a candid conversation about what I wanted and what I was looking for. She went to bat for me, and I moved into that admin role two weeks later! Within four months of that move, I became Marketo Certified for the first time. That only served to fuel the fire—I went on to get recertified and obtain all eight of the Specialization Certifications Marketo when they were released. I had something to prove to myself, and to my boss, for taking the chance on me. Early this year, I put myself out there and applied to the Marketo Champions program. In February, I was named to the 2018 Champions class.

 

I eventually ran out of room to grow at that company. From there, I moved to my current role with a full-service digital marketing agency. Every day I get to work with clients on a global enterprise scale to build out and optimize their Marketo instances in support of their overall demand gen and content marketing strategies. I am excited by new opportunities and resources afforded me as a part of an agency and I look at every challenge as a chance to grow.

I would not be where I am without an incredible support network of mentors, cheerleaders, and people who believe in me. I will be forever grateful to have them in my life and as a part of my journey.

What have you learned from other members of the Fearless 50?

This inaugural class of Fearless Marketers comes with such a diverse set of skills and from a broad set of backgrounds, industries, and roles. From them, I’ve learned that fearlessness comes in many forms, some personal and some professional. Commitment to success is at the core of every single one of their stories and is a principal I have really taken to heart.

What are three pieces of advice you would give to the next generation of fearless marketers?

#1. Take calculated risks! If you always play the safe game, you’ll never know what you could truly accomplish. When we try new things in marketing and in life, that hesitant moment of “can I do this?” that comes from self-doubt should not be a question, it should be a commitment. I CAN do this. Lean into that hesitation as a way to grow.

#2. Make smart decisions. When you are ready to commit to an idea, make sure you have gathered as much information as you can to make the most educated decision possible, and commit. Understand the pros and cons and make the best and smartest decision you can.

#3. Learn from failures. Do not berate yourself or others when something goes wrong. You cannot go back and change it. Take it as a lesson. Examine what went wrong and what you can learn from it to do things differently in the future.

 

 

Check out the rest of the content featured in Marketo Fearless Forum: Edition 04.

 

About Brooke Bartos

BrookeBartos-400x400.jpg

 

LinkedIn: https://www.linkedin.com/in/brookembartos/

Community Page: Brooke Bartos

 

Have any questions for Brooke about her fearless marketing career? We would love to hear them in the comments below.

At Marketo, we understand that sharing knowledge with your peers is a great way to help accelerate learning. That’s why we partnered with our 2018 Marketo Champions to pull together a new ebook that dives into how you can leverage Marketo like some of our top performers. The new ebook, titled the [Marketo Success] Guide, provides detailed insights on everything from setting up email templates to which reports you should be pulling to prove your impact on revenue. Check out an excerpt from the ebook below written by Erik Heldebro, Chief Marketing Officer at Bambuser and Rachel Noble, Manager Client Services at Digital Pi to learn how they manage engagement program memberships in Marketo.

 

Managing Engagement Programs

Nurture programs aren’t just hard to conceive. They can be hard to manage, too, especially if you don’t have a program set up for just that purpose. We call this a Nurture Traffic Controller, and here’s how to build one:

  1. Create a Default Operational Program named Nurture Traffic Controller.
  2. In the new program, create three folders: Smart Campaigns, Smart Lists, and Reports.
  3. In the Smart Lists folder, create a Smart List named “1. Nurture Target Audience.” The Smart List criteria should include anyone who would potentially qualify for any nurture program. We’ll specify which program later. Remember that Marketo filters out Unsubscribed, Marketing Suspended, and Blacklisted leads automatically.
  4. If you have one Engagement Program that everyone goes into, skip to step 5. Otherwise, you will need to create additional target audience Smart Lists to identify which Engagement Program qualified leads should go into. For example, if you have an Engagement Program specifically for VP’s, create a Smart List “2. VP Target Audience.”
  5. In the Smart Campaigns folder, create a new Smart Campaign named “1. Add Qualified Leads to Nurture.”
    1. Smart List:

EP_Champion_EBook_Image01.png

  1. Flow:
    1. If you have a generic nurture program, your only Flow step should be: Add to Engagement Program -> Generic Engagement Program, Stream=Stream 1. Add choices to determine which stream if you have multiple streams.
    2. If you do not have a generic nurture program, you can use the Smart Lists you created in step 4 to identify which program they should go into
    3. Add to Engagement Program If Member of Smart List A, Engagement Program A Stream = Stream 1 and so on. Like in (i), you can also add choices to determine which stream if any of these programs have multiple streams.

EP_Champion_EBook_Image02.png

 

6. Schedule this to run recurring just before the cast of the nurture program(s). If the casts are not consistent, consider scheduling this daily. Remember that the campaign is set so people can only run through once, so you don’t have to worry about this re-assigning everyone to new nurture programs each time it runs.

7. If you don’t have any other nurture programs, you’re done! Otherwise, we need to set up transition rules to get people into the correct nurture program. For each additional nurture program, we need to create a new Smart Campaign to transition leads who qualify:

EP_Champion_EBook_Image03.png

EP_Champion_EBook_Image04.png

 

And that Smart List referenced in Flow step #1?

EP_Champion_EBook_Image05.png

 

Now your leads will be in the right Engagement Programs!

 

Engagement Program Checklist

When setting up your Engagement Programs, here’s a checklist you can use to make sure you have everything you need.

  • Engagement Program built
  • Content Streams created
  • Unsubscribed/Invalid Stream created
  • Transition Rules defined
  • Smart Campaign to track success at the Engagement Program level built and activated
  • Emails added to nested Default Programs within the Engagement Program
  • Smart Campaigns to track success at nested Default Program level built and activated
  • Excluded Smart Campaigns built-in nested Default Programs and activated
  • Default Programs/Email Assets added to streams
  • Default Programs/Email Assets activated in streams
  • Cadence/first Cast scheduled
  • Traffic Controller created/updated

 

We hope you enjoyed reading this excerpt from the upcoming [Marketo Success] Guide: Best Practices from Marketo Champions. Keep an eye out for more tidbits from the new ebook that is launching in late 2018. Have questions about the content? Let us know in the comments!

Hello Marketing Nation,

 

This week Marketo reopened the gates to the Marketo Champion Program and we wanted to extend the invitation to all of you in the Marketing Nation Community. Many of you have been impacted by a Marketo Champion in one way or another. Whether you've seen some of their content here on Community or you've attended a Champion-lead Marketo User Group, the Champions are deeply devoted to helping our customers win with Marketo. The application will be open until November 30th.

 

For more details around becoming a Marketo Champion, check out the Champion Info page listed here: Requirements & Benefits of the Champion Program

 

If you're ready to apply today, you can find the application here: https://engage.marketo.com/championapplication2019.html

 

If you have any further questions about the Champion Program’s Criteria & Requirements, please email customermarketing@marketo.com

 

Good luck to all the 2019 applicants!

As you dive into the world of webhooks for advanced database tasks, the number of webhook definitions in the Admin UI can get pretty crazy. I've seen instances with 100 different ’hooks!

 

Many webhooks do need to stand alone, but some come in pairs or groups. For example, an Add to Event Registration Counter webhook needs a companion Remove from Registration Counter. A Lookup in Suppression List webhook running against an external db likely means Add to Suppression List is also defined. And so on.

 

To consolidate webhooks and make the UI (and your code) more manageable, a cool trick is to send the {{Campaign.Name}} token along with the hook, so the remote service can decide which direction/action to take, and you only need to define one webhook to cover a group of related actions.

 

For example...

I have a webhook that maintains, in a Textarea custom field, all the Static Lists a lead is currently in. (This view is notoriously hard to get at, in both the UI and the API, unless you flatten it onto a field like this.) The field uses a semicolon-delimited format, as is typical for such things: Apples;Peaches;Pumpkin Pies.[1]

 

Naturally, the webhook is triggered on Added to List and on Removed from List. So I have those 2 campaigns set up with informative names:

 

ssss

ss

 

And the onRemove flow is exactly the same as the onAdd flow pictured above. They both call the same webhook, rather than there being 2 webhooks, one for each direction.

 

Then within the webhook itself, I can detect the direction because {{Campaign.Name}} is included in the payload (in addition to {{Trigger.Name}}, which is the List name):

 

ss

 

This I find infinitely more manageable than the alternative, since the onAdd and onRemove handlers sit right next to each other.

 

Obviously, the exact way your webhook service switches between different directions/modes depends on your architecture. Since this webhook uses JavaScript, there's a literal JS switch statement, while in other cases you might pass {{Campaign.Name}} in the URL path or query string (the dotted Program Name.Campaign Name could represent the dot-path to different Java class methods, that would be cool!).

 

 

Notes

[1] In this case, a single Static List can't have a semicolon within its name, for obvious reasons.  You can switch delimiters as necessary.

Isn't it annoying to add a Wait step before sending a registration confirmation, crossing your fingers that the provider has phoned home with the {{Member.Webinar URL}} token?

 

I've always hated this step. Not only because of the experience for the end user, who might think you've forgotten about them, but on a pure technical level. Techies hate timers that are “probably sufficient”: we want tools that are predictable, not best-case guesses with fatal downsides. Not only might a 15 minute Wait not be sufficient under load,  there's no Wait that will fix a major problem with the integration, so users will eventually get an email with a big blank in the middle anyway.

 

What if I told you you don't need to hold off on such emails at all?

 

Instead, set up an LP in the webinar program that redirects to the {{Member.Webinar URL}}. Send them a link to that LP with no delay. Unless it's very close to the webinar's start time, most people aren't going to click a Join Webinar link right away, so you've got lots of breathing room for the API to sync up the {{Member.}} token.

 

When they do click the email, you'll be ready for them and will immediately bounce them over to the webinar, hands-free.  If it does happen that the URL isn't yet ready when they click, well, you weren't going to get it to them any quicker with an arbitrary delay! You can give them a countdown timer and reload the page in 30 seconds, and you can send them a follow-up email since you know they're eager (that second email might as well have a Wait step).

 

Here's the briefest possible copypasta to add to that LP:

 

<style type="text/css">
.webinar-pending-note { 
  display: none; 
}
[data-url-ready-state="pending"] .webinar-pending-note { 
  display: block; 
}
</style>
<script>
var memberWebinarURL = "{{Member.Webinar URL}}";
if ( memberWebinarURL ) {
  document.location.href = memberWebinarURL;
  // just for completeness
  document.documentElement.setAttribute("data-url-ready-state","ready"); 
} else {
  document.documentElement.setAttribute("data-url-ready-state","pending");
}
</script>
<div class="webinar-pending-note">
Your customized webinar URL is still being assembled. 
Please refresh this page or re-click the email link in a few minutes!
</div>

 

More ideas

Once the LP is in place, you can extend the user experience in several ways:

 

1. As noted above, you can add a periodic document.location.reload(true) in case they did hit the page before the API phoned home.

2. You can adapt some of my Redirector Page JS to add a progress indicator before reloading. Note sending leads to the Webinar Redirector LP also enables Munchkin tracking, which is a benefit in its own right.

3. You can add Agical Add to Calendar links to the page, referencing the {{Member.Webinar URL}} using the alternate separator syntax originally designed for this very case.

4. If you want to send the lead an Add to Calendar link that works from the start, then reference the Redirector LP's URL in your .ICS file or Agical link, not the {{Member.Webinar URL}}.

5. You can retarget the lead with rich contextual content if they land on the page after the webinar is over (check another {{my.}} token that stores the event date) or well before it begins, instead of taking them to this beautiful page:

ss

For any Velocity project, I've taken to offering clients a separate config token, call it {{my.ThisIsWhereYouChangeStuff}}, where they can manage some output settings without having to email me all the time.

 

Then there are one or more {{my.PleaseDontChangeAnythingInHereItsFragile}} tokens with the meat of the code.

 

Velocity #define directives are really handy for the config token. They're a bit more fault-tolerant than #set statements, where the non-technical person has to remember to escape quotes, close parentheses and such.

 

That is, instead of:

 

#set( $baseURL = "https://www.example.com/preferencecenter" )
#set( $linkText = "Say \u0022Hello\u0022 to our new preference center." )

 

I give them a token like so:

 

#define( $baseURL )
https://www.example.com/preferencecenter
#end
#define( $linkText )
Say "Hello" to our new preference center.
#end

 

As long as they leave the #define/#end lines alone they can change anything in-between (especially good for multiline text, as you might imagine).

 

There's a little trick to using #define, though, and that is like everything in Velocity, it preserves whitespace.  What whitespace, you may ask? Well, look at the end of this line:

 

https://www.example.com/preferencecenter

 

That has a carriage return + line feed (or just LF, depending on the OS) at the end.

 

So if I output a link like so:

 

<a href="${baseURL}">${linkText}</a>

 

The email will contain:

 

<a href="https://www.example.com/preferencecenter
">Say "Hello" to our new preference center.
</a>

 

Instead of what you intended:

 

<a href="https://www.example.com/preferencecenter">Say "Hello" to our new preference center.</a>

 

Which is bad because it will wreck your links even though you may not even see the wreckage in Preview because of the way HTML itself swallows line breaks.

 

Now, you can suppress the trailing whitespace by adding a comment ## at the end of the line

 

https://www.example.com/preferencecenter##

 

but I daresay that's not an improvement, since the idea is to offer this token as a not-too-fragile place for a non-technical person to make adjustments, and adding ## is something they're bound to forget or mess up.

 

So what you want to do is let them enter text in as close to free-form fashion as possible. Then in your code, strip out extraneous whitespace at the beginning or end to be tolerant of minor messups.

 

How trim() works

The documentation of the trim() method in Java, which exists on any Java String and therefore on any Velocity String is almost lovable in its complexity.

 

trim() does exactly what we want, but you have to understand the ASCII table to know that! Not that a programmer shouldn't understand ASCII, but it's a particularly circuitous explanation IMO:

 

[L]et k be the index of the first character in the string whose code is greater than '\u0020' (the space character), and let m be the index of the last character in the string whose code is greater than '\u0020'. A new String object is created, representing the substring of this string that begins with the character at index k and ends with the character at index m-that is, the result of this.substring(k, m+1).

 

Let me put that in clearer terms:

 

If a contiguous block of characters between ASCII 0 and ASCII 32 is found at at the beginning and/or end of the string, the whole block is removed.

 

ASCII 0 through ASCII 32 means the nul (0) through space (32) characters, inclusive. In that range are the quite common carriage return (13), line break (10), and tab (9) characters, and some more obscure ones like vertical tab (11).[1]

 

So though it only explicitly mentions the space character \u0020 (hex 20 is decimal 32), which you're probably familiar with as %20 in URLs, in fact it covers line breaks as well. If there's a long intro or outro of spaces, line breaks, and tabs, trim() will clean 'em all out.

 

trim()-ing what's inside a #define

So trim() is perfect, but you can't simply do this:

 

<a href="${baseURL.trim()}">${linkText.trim()}</a>

 

That'll throw an error. The reason is that any #define, when you address it directly, is a Velocity-specific Block$Reference, not a generic java.lang.String.

 

A Block Reference doesn't itself have a trim() method. But it does have a toString() method. (In fact, toString() is called under the hood when you output a plain ${reference} in Velocity, otherwise you couldn't output it at all.)

 

So I know this was long-winded but hopefully you learned something you need:

 

<a href="${baseURL.toString().trim()}">${linkText.toString().trim()}</a>

 

And you're done!

 

 


 

Notes

[1] But not all whitespace characters, since some as common as non-breaking space (the famous &nbsp; in HTML) are above ASCII 32. And over in JavaScript, the almost-identically-purposed trim() does strip non-breaking space. Is there nothing in programming that's not complicated when you care to learn the details? ☺

Will Harmon

Adobe to Acquire Marketo

Posted by Will Harmon Employee Sep 20, 2018

As you may have heard, earlier today Adobe announced they have entered into a definitive agreement to acquire Marketo to widen their leadership in customer experience. Marketo CEO Steve Lucas published a blog that highlights both Marketo's and Adobe's joint vision to empower marketers to deliver exceptional end-to-end customer experiences:

 

"I am thrilled to announce that Marketo has entered into a definitive agreement to be acquired by Adobe. Adobe and Marketo both share an unwavering belief in the power of content and data to drive business results. Together we will deliver an unrivaled solution that will place customer experience and engagement at the heart of digital transformation. This announcement is a momentous occasion for Marketo, as it signals the next phase of our company’s growth."

For more information about the pending acquisition, please read Steve Lucas' full blog and Adobe's press release below.

 

Blog from Marketo CEO Steve Lucas: Adobe to Acquire Marketo to Place Customer Experience and Engagement at the Heart of Digital Transformation
Adobe Press Release: Adobe Expands Customer Experience Leadership with Addition of Marketo | Adobe Blog

Quick Velocity learner EC asked a seemingly simple question:

 

How do you sort Velocity objects based on a Boolean field, such that false values come first?

 

What makes it not-so-simple is that it's actually 3 questions in one!

 

Realize that something labeled as Boolean in Marketo (in the Field Management or Custom Objects admin sections) may or may not end up as a Boolean field in Velocity.

 

Booleans on Leads

As I've delved into before, regardless of the data type set in the database, Lead/Person fields in Marketo become String properties of the $lead object in Velocity:

  • Dates and DateTimes are not dates in Velocity, but merely date-like Strings (that's why you need to go through all that pain to convert them).
  • Integers are number-like Strings (which can wreak havoc on comparisons if you don't realize it).
  • Boolean fields are boolean-ish Strings. They have the possible values "" (empty String) if the original Boolean was false and numeric String "1" if true.

 

But the same doesn't hold for Boolean fields on other objects besides the Lead.

 

Booleans on Oppties and Salesforce COs

On Opportunities and other SFDC Custom Objects, bizarrely, Booleans become a different type of String, which has the possible values "0" for false and "1" for true (this is admittedly a more traditional conversion than empty String and "1" but why, oh why, must it be different?).

 

Booleans on Marketo COs

On Marketo Custom Objects, Booleans are presented as true Booleans! As in real Java Booleans with the reserved values true and false, the way we dream they'd be everywhere.

 

Wow, that's confusing!

Uh-huh. As I'm sure you realize, such differences all have to be considered for sorting.

 

So the 3 questions EC was implicitly asking were:

 

     (1) How do you sort objects based on a String field that can be empty string "" or numeric string "1", such that "" comes first?

     (2) How do you sort objects based on a String field that can be numeric string "0" or numeric string "1", such that "0" comes first?

     (3) How do you sort objects based on a Boolean field that can be true or false, such that false comes first?

 

Now, at the code level, the answer to all 3 questions happens to be the same. But this is coincidental because it derives from different Java sorting rules. The fact that there's one answer that covers these 3 cases must not be interpreted to mean any ways of representing true and false will follow the same sorting logic.

 

At any rate, that answer is:

 

#set( $sortedList = $sorter.sort($originalList, "fieldName:asc") )

 

Because ascending (:asc) is the default order in SortTool, this can be shortened to:

 

#set( $sortedList = $sorter.sort($originalList, "fieldName") )

 

So if you have these 3 objects in a list $originalList:

 

[{
  "Name" : "A",
  "IsActive" : false,
  "ExternalCreatedDate" : "2017-07-01"
},
{
  "Name" : "B",
  "IsActive" : true,
  "ExternalCreatedDate" : "2017-08-01"
},
{
  "Name" : "C",
  "IsActive" : false,
  "ExternalCreatedDate" : "2017-09-01"
}]

 

And you do:

 

#set( $sortedList = $sorter.sort($originalList, "IsActive") )

 

Then $sortedList will be:

 

[{
  "Name" : "A",
  "IsActive" : false,
  "ExternalCreatedDate" : "2017-07-01"
},
{
  "Name" : "C",
  "IsActive" : false,
  "ExternalCreatedDate" : "2017-09-01"
},
{
  "Name" : "B",
  "IsActive" : true,
  "ExternalCreatedDate" : "2017-08-01"
}]

 

And the same code also works if IsActive uses either of the 2 "boolean-ish" String conversions instead of true Boolean.

 

But again (and I'm going to pound you over the head with this) it's a coincidence. If Marketo happened to use yet another way of String-ifying Booleans, you might need to sort descending ($sorter.sort($originalList, "fieldName:desc")) or use another sorting method entirely to get the falses to the top.

 

The challenge

Now, the fun part. Rather than jump right to Part II (where I go deep into the technical details) I'll keep that follow-up post as a draft for a week, until September 18, 2018. 

 

From now 'til Sept. 18, if you can answer the below challenge correctly, I'll give you a major shout-out in the follow-up... and hey, I may even have some side gigs for you! (Leave your answers in the comments, and please only try once per person.)

 

The background:

 

If Marketo used the Strings "-1" for false and "+1" for true then you'd need to use :desc instead of :asc. (And there's no standard that says they couldn't String-ify Booleans this way.) And same if they'd used symbols "" and "" , which appropriately denote truth and falsity (verum and falsum) in logic. Ditto if they'd used the Unicode characters for thumbs-up and thumbs-down.*

 

The question:

 

Why, in these 3 alternate cases, do you need :desc to get the originally false values to come first?

 

Be precise... no credit for "Because that's what Velocity requires."

 

 

*Would've displayed the characters here, but the Jive editor strips them

out! You can see them on the original version of this post on my blog.

In the August edition of the Fearless Forum, we're diving deeper into the topic of marketing attribution. In a recent challenge on Purple Select, a lot of Marketo users signaled they struggled with proving marketing's impact to their organization. In order to shed some light on how the experts are successfully proving their marketing impact everyday, we asked Libby Koebnick of PitchBook to help us understand how she's leveraging Marketo + Bizible.

 

Q1: Can you describe how marketing attribution works at your organization?

Web visits and form fills are captured via Bizible’s tracking scripts, and offline activities, including prospecting, are tracked via Salesforce activities. Our model takes all these touchpoints, connects them to and normalizes them in the buyer journey, and attributes a percentage of revenue back to them. This allows us to see how marketing and sales are contributing to our bottom line.

 

Q2: How did you manage your marketing attribution efforts before implementing Bizible?

Before Bizible, we were using a siloed last touch attribution model. This means we would attribute an entire contract to a single action of a single individual on that account. Since we’re a B2B SaaS Company with enterprise subscriptions, that model doesn’t make much sense for us. Now we use a custom Bizible attribution model that takes into account all the touchpoints of all the individuals involved in the conversation of the sale.

 

Q3: Can you share a specific benefit you’ve seen from implementing marketing attribution?

Our Bizible attribution models have showed us that over half our potential clients’ early interactions with us are via pitchbook.com. Citing this data, we successfully petitioned leadership for the resources to redesign our entire website.

 

Q4: How do you use Bizible with Marketo?

The way we get Bizible to see Marketo campaigns is to tag all the links in our emails with UTMs that Bizible will parse out when it captures landing pages from web visits. We just have to make sure all our links direct to our website or other pages that have the Bizible tracking script on them.

 

Q5: What are some unique ways you’re using Bizible with Marketo?

We started using in-platform forms in social media, which are super effective, but they don’t allow us to add Bizible tracking scripts. We found a workaround by using a Marketo campaign triggered by the form fill that creates a Salesforce activity task with the appropriate medium, source and campaign values. Bizible then turns those activities into touchpoints under the correct channel and subchannel.

 

Here's a closer look at how Libby leverages a campaign trigger in Marketo to turn activities into touchpoints in Bizible:

Screen Shot 2018-08-27 at 3.37.21 PM.png

Bizible Touchpoint.png

 

Q6: What was the most challenging part of choosing/implementing/building out your attribution model?

The most challenging part is getting our entire organization to correctly and consistently use UTMs. Web visits are bucketed into channels by building rules around landing page UTMs. Every time someone uses a new UTM (such as a new channel) or has a typo in their link, I have to create a new rule in Bizible.

 

Q7: How did you decide on the particular attribution model you’re using?

We are using Bizible’s Full Path model that attributes 22.5% of the revenue to each of the following buckets:

  1) First touch

  2) Lead creation

  3) Opportunity creation

  4) Close

The remaining 10% is attributed to the other touchpoints prior to the closed deal. Our old last touch attribution model was attributing 100% to the opportunity creation touchpoint. The Bizible model gives us context to the sale, more like account based marketing. We can see how the account first learned about PitchBook, how we warmed them up over time, and what eventually contributed to the win.

 

Q8: What advice would you give to Marketo users who are considering more advanced attribution?

Start collecting Bizible touchpoint data now! Bizible will naturally collect touchpoints, so by the time you’re ready to build your model you’ll already have your data. It takes a long time to build up historical data, and you don’t need an attribution model to start tracking touchpoints.

 

No attribution model is going to be completely right or wrong, and you can always adjust as you go. The model we went with was the most logical, considering our sales process, and the output passed the gut check.

 

When you put it all together, here's what attribution data looks like in Bizible Discover:

Overview-Board-Screenshot-for-Discover.png

 

We hope you enjoyed reading about how PitchBook is setting themselves up for success when it comes to proving their marketing impact. For even more tips and tricks on best practices, check out our brand new edition of the Fearless Forum which features a special video by Marketo Champion Juli James!

In the April edition of the Fearless Forum, we received a lot of questions about how to use Marketo Engagement Programs. So we sat down with Chris Saporito of Paycor to discuss how he executes successful engagement programs within Marketo to onboard new clients.

 

Q1: What led you to develop an engagement program?

A: We decided to revamp the way that we are onboarding clients because we had a gap in the quality of the current process. Our service organization wants to combine automation and personal touches to make the process as seamless and easy as possible. By adding sophistication to the automation and mixing in personal touches we hope to improve the efficiency and quality of the onboarding process. The ultimate goal of the project is to reduce the number of no-starts that we have, meaning the clients don’t make it through onboarding and we lose the business.

 

Q2: Could you describe the engagement program you created for onboarding new clients?

A: Our engagement is a series of emails that are triggered throughout the onboarding process for new clients. We created a new custom object in SFDC and synced the object to Marketo so that we can key off of the values. There are 7 emails in the series that we use the custom object for to tell Marketo which dates to fire the emails and which versions of the emails to fire. Most of the emails are standard for all clients, where we do some tokening within the emails, but the fourth email in the series is critical for onboarding. The custom object that we created has a field that we can populate with the information that is needed from the client. So, when the email is triggered, we are dynamically sending a specific email based on what the client has or has not given us yet. This is important because the data and documentation are critical to have before the client can process payroll. Also, within the series of emails our client service department has a specific cadence where they are mixing in emails and phone calls with the client to ensure that the client is on track and has a good user experience.

 

Q3: What was the process like to build out the engagement program using custom objects to trigger emails in Marketo? How long did it take?

A: The entire process for the project took about 3 months due to some internal prioritization. It took some Salesforce development work to build the custom object and to dynamically populate it to meet the needs of the business. Also, during the process we were able to get a temporary Marketo Sandbox to test out these processes, which had a learning curve in itself. Once we had the custom object built I was able to easily sync it to the Marketo sandbox and begin QA’ing the processes. Within a couple of weeks of QA’ing and working out the kinks we were ready to pull the trigger on the program.

 

Q4: Before using the SFDC custom object, had you tried to create a similar engagement program in Marketo only?

A: We have an email series that we ran out of Marketo for a few years to help client onboarding. The issues that we ran into were that it was difficult to customize the process due to some nuances of our business. By creating a custom object and doing some of the complex decisions in SFDC, it made it possible to pass that information to Marketo and create a better experience for the client.

 

Q5: What was the most challenging part of building and executing the program?

A: The most difficult part of this project was figuring out what all was needed to build this out. There was a learning curve since this was the first time that we had built something like this. Also, with the customization there was definitely some trial-and-error to get it to where we wanted it. Anytime that you have multiple organizations within a business working together for the first time it can be difficult but overall, I think it was a great success.

 

Q6: What advice would you give to Marketo users who are creating engagement programs?

A: I would recommend with any project and especially projects of significance, understand what the ask is. Truly understanding what the project needs to accomplish before determining how to build it is critical to creating the best product that you can. Something else that is crucial to projects like this is to give yourself plenty of time to QA. Test everything and then test is again, that’s the best way to make sure these projects have the smallest chance of error when they launch.

 

We hope you enjoyed reading about Paycor’s new Engagement Programs. To start building your Engagement Program today, check out Josh Hill's 5 step guide to building a successful Engagement Program in Marketo.

In the feedback from the June edition of the Fearless Forum, we received a lot of comments asking for ABM success stories. We spoke with Kyle McCormick, Marketing Systems Manager at Palo Alto Networks, to learn what steps you need to take to achieve success with an ABM campaign.

 

What are the key steps to launching a successful ABM campaign?

The first and most important step to launching a successful ABM campaign is to define the main stakeholders and everyone’s level of involvement.  At a minimum, this list should include marketing operations, sales leadership and IT (SFDC product owners). Depending on the size of your company and who manages accounts and contacts, this list might be significantly larger and could include sales operations, sales enablement, and business development to name a few. Once these stakeholders are aligned on objectives, timelines, and success metrics for the campaign, the last box to check is determining which accounts will be targeted and how they will be flagged within the systems. When selecting accounts, start small by focusing on 20-30 accounts at most.  If you choose too many accounts, you will not be able to devote the attention needed to nurture those accounts through the sales cycle.

 

How do you pick the accounts to use for the campaign?

At my previous company, we took a three-step process for selecting our accounts. We first asked our enterprise sales managers to select the top 25 accounts they would like to target. As you would imagine, we were quickly inundated with an overwhelming number of accounts. It would be unrealistic to select all of them and we knew we needed to focus on just 20-30 accounts. Secondly, we leveraged Mintigo to aid in our account selection process by analyzing current customer data. Using their predictive model, we scored the accounts our sales managers sent and then chose target accounts with an “A” grade that were in the 99-100 percentile. Lastly, we got official sign off from all stakeholders to make sure everyone was on the same page as to which accounts would be selected. After receiving approvals, we ended with roughly 30 targeted accounts.

 

What steps are critical to success?

The most important step to ensure success is preparing and aligning systems prior to launch. At my previous company, we leveraged our sales operations team and pioneered a company-wide cleanup effort to remove duplicate accounts, contacts, and leads prior to launch to ensure we were not targeting accounts we already actively had in the sales cycle. Understanding sales operations’ processes and best practices were necessary to effectively measure the success of our ABM efforts. We also would not have been able to launch an effective program without engaging our information technology/systems team early (and often) to ensure our field-level tracking requirements were understood, tested, and in place prior to launch.

 

How do you align with other teams critical for campaign success?

Leveraging and integrating technologies, specifically Mintigo and Marketo, can play an essential role in aligning the sales and marketing teams. Understanding and sharing the power of predictive analytics with the sales team helped everyone realize the potential opportunity for account penetration. As previously mentioned, we were able to keep our IT/IS teams aligned with our goals by communicating early and often within the process.

 

What are some challenges you’ve had to overcome?

The biggest challenge at my previous company was getting global buy-in across all functional teams. Everyone talks about sales and marketing alignment, but it is bigger than just a catchphrase. You need to ensure your IT/IS teams are on board with changing fields in Salesforce and Marketo, and you need to make sure individual stakeholders are on board. The second most challenging obstacle was the account selection process. We went through a massive cleanup effort to remove duplicates, but duplicates will always remain, and it is important to regularly check and clean the database. We had to go through multiple iterations of combing through selected accounts to ensure we were not selecting current customer or partner accounts. 

 

 

About Kyle McCormick

 

 

LinkedIn: https://www.linkedin.com/in/kylehmccormick/

Community Page: Kyle McCormick

 

Have any questions or other ABM success stories to share? We would love to hear them in the comments below.

 

This content is featured in the August edition of the Marketo Fearless Forum: Edition 03 . Feel free to check it out for more best practices, tips and tricks, and product updates!

Can't believe someone other than me has thought about cryptographic techniques in Marketo! But in this recent Nation thread, a user asked about attaching the SHA-256 hash of a recipient's email address to (email) links.

The aim being to send a secure representation of a lead's email to an external (non-Marketo) site, where it could be looked up as part of a 3rd-party subscription center.

In other words, a link would look like this:

http://nonmarketopage.example.com/?emailHash=284C36B4333F55511617FB225C62813316038522DF5C2AEC6B6B13B3D3774F5C

The target site's database would hold pre-computed hashes of all their registered users' emails, the hash being stored in a separate column from the email itself.[1]

A match would then be done from hash-to-hash (the way hashes are always used, since they can never be reversed to the original input) to load the user's record.

Mind you, I have no idea why this would actually be done as opposed to sending the URL-encoded email address:

http://nonmarketopage.example.com/?email=sandy%40figureone.com

Or the easily reversed, Base64-encoded (not encrypted) address, which wouldn't require a hash lookup:

http://nonmarketopage.example.com/?emailB64=c2FuZHlAZmlndXJlb25lLmNvbQ==

Being a realist, I suspect the justification is merely that they want the links to look more “technical” than they would with Base64 (?) and they don't truly have any need for security (as it makes little sense to care about the security of the recipient's own email address![2]). UPDATE: OP says the client now wants AES encryption instead of hashing, so they really are trying to securely transport stuff in the URL. That gives me a chance to bring out the big guns and show you how encryption is done in VTL... at some point.

Anyway, should you need it, here's a utility Velocimacro to gen a SHA-256 hash:

#**
    HashTool in VTL v2
    @copyright (c) 2018 Sanford Whiteman, FigureOne, Inc.
    @license MIT License: all reproductions of this software must include the data above
*#
#macro( SHA256_v2 $mktoField )
## reflect some dependencies
#set( $Class = $context.getClass() )
#set( $java = {} )
#set( $java.lang = {
     "StringBuilder" : $Class.forName("java.lang.StringBuilder"),
     "Appendable" : $Class.forName("java.lang.Appendable")
} )
#set( $java.security = {
    "MessageDigest" : $Class.forName("java.security.MessageDigest")
} )
#set( $java.util = {
    "Formatter" : $Class.forName("java.util.Formatter").getConstructor($java.lang.Appendable)
} )
## get an MD and make it go, then (important) reset MD singleton for reuse
#set( $MD = $java.security.MessageDigest.getInstance("SHA-256") )
#set( $digestBytes = $MD.digest( $mktoField.getBytes("utf8")) )
#set( $void = $MD.reset() )
## gen hex string representation
#set( $hexString = $java.lang.StringBuilder.newInstance() )
#set( $hexer = $java.util.Formatter.newInstance($hexString) )
#foreach( $B in $digestBytes )
#set( $void = $hexer.format("%02x",$B) )
#end
## return uppercase, but note a hex string should be treated as case-insensitive
$hexString.toString().toUpperCase()##
#end

After including the above in its own token (best to not pollute your user code with utility functions) use the macro like so:

#set( $emailHash = "#SHA256_v2($lead.Email.toLowerCase())" )
<a href="http://www.example.com/?emailHash=${emailHash}">Click here</a>

Note that I toLowerCase()d the Email before passing it, as that's appropriate for that particular field (as I've written about before, though SMTP addresses are actually case-sensitive, they're commonly matched case-insensitively for sanity's sake).


NOTES

[1] Hope I'm not hoping for too much here. They'd better be already pre-computing hashes for all the stuff in their database, or this idea goes from merely frivolous to very bad. If they didn't pre-hash, they'd have to hash every record in the database, on-the-fly, for every lookup. This would absolutely destroy performance and be a sign that the back end was not well thought out.

[2] Long as the destination site runs SSL. But if the site doesn't run SSL then the connection could be intercepted and you have a lot worse problems than showing the attacker an email address.

Filter Blog

By date: By tag: