SOLVED

Re: How can I send 1 email with dynamic content blocks for products they have and products they don't have?

Go to solution
Ronn_Burner
Level 4

Here is what I'm being told from above that I need to solve for. I can't figure this out.

Think of our product model as DirecTV. A customer can go online and select (subscribe) to any channel or combination of channels they choose. - - So I have 10 ala carte products and a new subscriber signs up to any 1 single product or any number combination up to all 10 products. I only want ONE email to be sent per new subscriber regardless of how many products they subscribed to at one time. Then I will send a 2nd email later. Is it possible - and practical - to acknowledge each product they subscribed to uniquely with a text block and/or image for each AND a different text block promoting the products they did not subscribe to? And if not, what is the best way to handle this type of situation?

So many questions: 1. Segmentation logic? 2. Snippets, dynamic emails or unique streams or programs? 3. Engagement or Default Programs? 4. How to ensure ONLY 1 email regardless of new subscriptions deploys? 5. Smart campaign total and goal?

Any thoughts and or advice on how to handle this initial entry via new subscribers would be a life saver. Thank you!

1 ACCEPTED SOLUTION
SanfordWhiteman
Level 10 - Community Moderator
- I should only use $lead.DMSSubscribed or $lead.DMSSubscribedDate and not both, right?

Only the DateTime field.

- Do I simply just replace all $lead.DMSSubscribed with $lead.DMSSubscribedDate in the code?

Yes, that is, if you're going to convert a stringified DateTime (i.e., ISO8601 format) field into a Date, that's where you use the DateTime.

However I don't think these are ISO8601 "yyyy-MM-dd'T'HH:mm:ss".  They're actually ISO8601 "yyyy-MM-dd HH:mm:ss". That is, they have a space instead of the letter "T". So you can add this line to the code at the top:

#set( $ISO8601WithSpace = "yyyy-MM-dd HH:mm:ss" )

Then use $ISO8601WithSpace where you're using $ISO8601 now.

Parsing a String to a Date requires that you tell Velocity (actually Java) all the parts of the format.

- Do I uncheck the $lead.DMSSubscribed box in the Script Token?

For clarity, yes, but it's harmless to leave it checked as you won't be using it. Leaving it unchecked means it will always have the value null. That may be more or less confusing if you accidentally use it, I don't know.

View solution in original post

96 REPLIES 96
SanfordWhiteman
Level 10 - Community Moderator

During the past 24 hours? Or during the current calendar day in your timezone? (Different things)

Ronn_Burner
Level 4

The past 24 hours because these 'statuses' change in the CRM and there's only a single daily sync to Marketo. Obviously causing all DateTime/system.dates to match for that day regardless of when it really took place. Therefore all 'Data Value Change' triggers fire at the sync - so I typically just batch all yesterdays data to take action today.

SanfordWhiteman
Level 10 - Community Moderator

OK, then you'd need to use the DateTime math code from https://blog.teknkl.com/velocity-days-and-weeks/. It's too far afield for this post, you really need to know Velocity to support complex code like that in the long term.

Ronn_Burner
Level 4

In other words use only Product X Subscribed = "".

Will DateTime recognize system.date since that is the field I created? And the blog post touches on coding scenarios different than this particular one. The TimeZone one is closest but still not interchangeable.

SanfordWhiteman
Level 10 - Community Moderator

Will DateTime recognize system.date since that is the field I created? 

I don't understand the question...

And the blog post touches on coding scenarios different than this particular one. The TimeZone one is closest but still not interchangeable.

Actually all those recipes involve timezones -- because all Dates have timezones.

The difference in hours between 2 Dates follows the framework in Use Email Script Token to calculate number of years based on a date field (itself adapted from my main blog post) only you'd use getHours() instead of getYears().  Like:

#set( $calProductXSubscribed = $convert.toCalendar(
$convert.parseDate(
$lead.ProductXSubscribed,
$ISO8601,
$defaultLocale,
$defaultTimeZone
)
) )
#if( $date.difference($calNow,$calProductXSubscribed).getHours() >= -24 )
You subscribed to Product X within the past 24 hours.
#end‍‍‍‍‍‍‍‍‍‍‍
Ronn_Burner
Level 4

I don't understand the question...

In the 'Product X Subscribed Date' and 'Product X Canceled Date' custom fields I created I populated that value with {{system.date}} rather than {{system.dateTime}} and I was wondering if that mattered in this particular case.

only you'd use getHours() instead of getYears().  Like:

I have created and duplicated 8 times (specific to each product) this exact framework in the Email Script Token. I assume I need to have these 8 product specific blocks followed by the 8 false blocks like so:

#if( $lead.DMSSubscribed.equals("") )
Your DMS Subscribed is false.
#end

Am I missing anything or is this 100% completed and ready to go once I fill in the messaging?

SanfordWhiteman
Level 10 - Community Moderator

In the 'Product X Subscribed Date' and 'Product X Canceled Date' custom fields I created I populated that value with {{system.date}} rather than {{system.dateTime}} and I was wondering if that mattered in this particular case.

Then you probably got midnight on that day stored in the DateTime, which certainly matters as it could be up to 23 hours and 59 minutes off.

I have created and duplicated 8 times (specific to each product) this exact framework in the Email Script Token. I assume I need to have these 8 product specific blocks followed by the 8 false blocks like so:

#if( $lead.DMSSubscribed.equals("") )
Your DMS Subscribed is false.
#end

Yes. But you should also wrap the first set of conditions in a not-equals check, so you ensure that you don't try to convert an empty string to a Calendar (this will non-fatally fail but should be avoided).

#if( !$lead.ProductXSubscribed.isEmpty() )
#set( $calProductXSubscribed = $convert.toCalendar(
## etc., etc.
#end

Am I missing anything or is this 100% completed and ready to go once I fill in the messaging?

Sorry but I really can't sign off on your implementation, never having looked at it in reality. Once you put it through its paces, testing a representative set of cases, it's good to go.

Ronn_Burner
Level 4

So this issue has been resolved. I just updated all {{system.date}} flow steps in entire instance with {{system.dateTime}} so the times will all match in the daily CRM-Marketo sync.

Yes. But you should also wrap the first set of conditions in a not-equals check

This image is the snapshot of the transition from Product 8 to the not-equals check.

pastedImage_1.png

Sorry but I really can't sign off on your implementation

I understand that and I will certainly test once I at least "think" I have the script correct. For example, if this image is correct I can move in that direction, however, I'm not certain you meant to script it the way I have here or if you meant something else.

SanfordWhiteman
Level 10 - Community Moderator

That's not valid VTL, it will throw a fatal error instantly as you'll see in Preview.

I'm saying you need to wrap the entire Calendar creation in an isEmpty() check. The #etc., etc. represents where you'd put your existing code. You're adding a precondition around it, also called a guard.

#if( !$lead.ProductXSubscribed.isEmpty() )
#set( $calProductXSubscribed = $convert.toCalendar(
$convert.parseDate(
$lead.ProductXSubscribed,
$ISO8601,
$defaultLocale,
$defaultTimeZone
)
) )
#if( $date.difference($calNow,$calProductXSubscribed).getHours() >= -24 )
You subscribed to Product X within the past 24 hours.
#end
#end‍‍‍‍‍‍‍‍‍‍‍‍‍
Ronn_Burner
Level 4

Got it. I think. This now has the first set of conditions wrapped per product for an isEmpty() check. Then following the Calendar creation and guard I then transition into the #if( $lead.ProductXSubscribed.equals("") ) check to send that appropriate messaging.

This image transition from Product 8 into still yet to Subscribes.

pastedImage_2.png

I believe that is now accurate and correct. But in my email test sends I don't see anything populating. Where exactly do I place the {{my.VelocityTimeZone}} token?

SanfordWhiteman
Level 10 - Community Moderator
  • You can't send samples to test Velocity, you must send real emails
  • You don't need to send emails at all, using Preview-by-List with a static List (add a few representative leads) is the only way to stay sane while troubleshooting Velocity code
  • Please don't call this token {{my.VelocityTimeZone}}, it doesn't have anything do with the purpose/output; variables should have accurate + complete names, {{my.RecentlySubscribedProducts}} for example
  • You'd put the token in the body of an email, as with other {{my.tokens}} (or in theory in the Subject line, but presumably this content is designed for the body)
Ronn_Burner
Level 4

I've done everything you suggested. The email Preview-by-List view does not populate the token. And just after I felt soooo close. Bummer. Is this an indication of the VTL being broken somewhere or what could be causing this?

SanfordWhiteman
Level 10 - Community Moderator

You'll have to add some debugging lines. If you just put

${display.list( $lead.entrySet(), "\u000a" )}

on a line by itself, that will show you what the lead object looks like in raw form. Go to the Text version of the email to look at the output, then you can post a screenshot.

Ronn_Burner
Level 4

This was the result of that line.

pastedImage_1.png

Interestingly in a different email template I used for testing it rendered differently. And I should note this version is the actual template this emails will be built from.

pastedImage_1.png

SanfordWhiteman
Level 10 - Community Moderator

Do you have the required fields checked off in the tree on the right-hand side of Script Editor? Sure doesn't look like it.

Ronn_Burner
Level 4

Nope. I had no clue. Sorry. Your level of frustration must be approaching record levels.

I checked all 8 Product Subscribed and all 8 Product Subscribed Date only. Is that correct?

Here is the result of that...

pastedImage_1.png

SanfordWhiteman
Level 10 - Community Moderator

That's better, but you said they were DateTimes... those are stringified Date fields.

Ronn_Burner
Level 4

Yes. Ugh. I need to create all new custom fields with type set to' Datetime'... these were built as 'Date' apparently. I simply changed the {{system.date}} token to {{system.dateTime}} in the flow step that writes that data when the Subscription takes place.

Obviously I can build the appropriate new 'Product X Subscribed Date' (times 😎 custom fields moving forward but what suggestions do you have to remedy those records already populated with a 'Date'?

SanfordWhiteman
Level 10 - Community Moderator

Yes, a flow step cannot change the datatype (think about who can add flow steps vs. who has access to Field Management and this will surely make sense).

You don't need to create 8 new fields. You should be able to create 1 new, temporary Date field to hold old values while you change each existing Date to a DateTime, one at a time.

Converting a field is a destructive act. So you first copy, for example, oAPSubscribedDate to your temporary Date field using Change Data Value. Then convert the datatype for just that one field. Then copy the temporary field back to the changed oAPSubscribedDate.

Then clear all the values of the temporary field. Now the temporary field is ready for reuse. Repeat for cRMProSubscribedDate, copying to the temp field, changing the datatype of the real field, and copying the data back.

Or export all your values to CSV, together with the email address of course, change all the datatypes (which destroys all current values) and reimport the CSV. This wouldn't even require a temp field.

Ronn_Burner
Level 4

I've run into this in the past. I've selected the custom field then the 'Field Actions' > Change Type and this is what happens.

pastedImage_1.png

In order to change the type after I export CSV will I then need to go into all locations for each 'Product X Subscribed Date' and remove from each program/list? I like your way better to have the option to simply change the type and destroying current values and then importing new values.

SanfordWhiteman
Level 10 - Community Moderator

Whatever you do is going to require un-using the current field, either temporarily or permanently.

If you switch to 8 new fields then you need to switch all the places the old fields were used.

If you use the temp field then you need to temporarily switch all the places the old field was used, as you swap the values.

There's no way around needing to touch all the places the field is used.