Issues with the types of custom properties in a Single Send email


#1

I recently posted about issues with the int filter. Since then, I’ve discovered a few other issues with filters and custom properties, and made a template to exercise them. With that template, I’ve discovered that, according to the pprint filter, all custom properties now have a type of PyMap instead of string, etc. Is it possible that is the cause for the filters not being able to properly handle those values?

My test template:

<p>An integer in customProperties arrives as a PyMap: {{custom.an_int|pprint}}</p>
<p>A PyMap integer in customProperties can't be converted to an int: value - {{custom.an_int|pprint}}, |int - {{custom.an_int|int|pprint}}</p>
<p>What if we convert it to a string first? value - {{custom.an_int|pprint}}, |string - {{custom.an_int|string|pprint}}, |string|int - {{custom.an_int|string|int|pprint}}</p>
<p>What happens if we extract is as an attribute? value - {{custom.an_int|pprint}}, |attr('an_int') - {{custom|attr('an_int')|pprint}}, |attr('an_int')|int - {{custom|attr('an_int')|int|pprint}}</p>
<p>But can be if created in the template: value - {{"3"|pprint}}, |int - {{"3"|int|pprint}}</p>
<p>The length of a string (which arrives as a PyMap) from customProperties is incorrect: value - {{custom.a_string|pprint}}, |count - {{custom.a_string|count}}</p>
<p>What if we convert it to a string first? value - {{custom.a_string|pprint}}, |string - {{custom.a_string|string|pprint}}, string|count - {{custom.a_string|string|count}}</p>
<p>But is correct for a string created in the template: value - {{"abcd"|pprint}}, |count - {{"abcd"|count}}</p>
<p>The wordcount for a string (which arrives as a PyMap) from customProperties is incorrect: value - {{custom.a_sentence|pprint}}, |wordcount - {{custom.a_sentence|wordcount}}</p>
<p><span>What if we convert it to a string first? value - {{custom.a_sentence|pprint}}, -|string - {{custom.a_sentence|string|pprint}}, |string|wordcount - {{custom.a_sentence|string|wordcount}}</span></p>
<p>But is correct for a string created in the template: value - {{"This is a sentence"|pprint}}, wordcount - {{"This is a sentence"|wordcount}}</p>

My test email:

{"emailId":1234,
 "message":{"to":"tcrawley@example.com"},
 "customProperties":
 [{"name":"an_int","value":3},
  {"name":"a_string","value":"abcd"},
  {"name":"a_sentence","value":"This is a sentence"}]} 

Together, when sent to the Single Send API, they result in:

An integer in customProperties arrives as a PyMap: (PyMap: 3)

A PyMap integer in customProperties can't be converted to an int: value - (PyMap: 3), |int - (Integer: 0)

What if we convert it to a string first? value - (PyMap: 3), |string - (String: 3), |string|int - (Integer: 0)

What happens if we extract is as an attribute? value - (PyMap: 3), |attr('an_int') - (PyMap: 3), |attr('an_int')|int - (Integer: 0)

But can be if created in the template: value - (String: 3), |int - (Integer: 3)

The length of a string (which arrives as a PyMap) from customProperties is incorrect: value - (PyMap: abcd), |count - 0

What if we convert it to a string first? value - (PyMap: abcd), |string - (String: abcd), string|count - 19

But is correct for a string created in the template: value - (String: abcd), |count - 4

The wordcount for a string (which arrives as a PyMap) from customProperties is incorrect: value - (PyMap: This is a sentence), |wordcount - 2

What if we convert it to a string first? value - (PyMap: This is a sentence), -|string - (String: This is a sentence), |string|wordcount - 2

But is correct for a string created in the template: value - (String: This is a sentence), wordcount - 4

There are a few interesting things here:

  • all custom properties come through as PyMaps (which is different than when I posted the int filter issue (linked above), when they all reported as strings)
  • none of the three filters tried here give correct results when applied to these properties

There may be other filters that don’t work as well, these are just the three I’ve tried in an effort to get an integer to survive from the client -> API -> template so I can use it as an argument to range in a for loop. I’ve been unsuccessful so far.

If you’ve read this far and work at HubSpot, could you please point this issue out to someone that has the power to resolve it?

  • Toby

#2

I have the same problem

Previously urlencode filter works but a client reported that all links are now dead. The issue is that custom properties are PyMap and could not be converted to string. See my test email below

<table>
    <tr>
        <td>contact.location_name_1</td>
        <td>{{ contact.location_name_1 }}</td>
    </tr>
    
    <tr>
        <td>contact.location_name_1|pprint</td>
        <td>{{ contact.location_name_1|pprint }}</td>
    </tr>
    <tr>
        <td>contact.location_name_1|string|lower</td>
        <td>{{ contact.location_name_1|string|lower }}</td>
    </tr>
    <tr>
        <td>contact.location_name_1|lower</td>
        <td>{{ contact.location_name_1|lower }}</td>
    </tr>
    <tr>
        <td>contact.location_name_1|wordcount</td>
        <td>{{ contact.location_name_1|wordcount }}</td>
    </tr>
    <tr>
        <td>contact.location_name_1|upper</td>
        <td>{{ contact.location_name_1|upper }}</td>
    </tr>
    <tr>
        <td>contact.location_name_1|string|urlencode</td>
        <td>{{ contact.location_name_1|string|urlencode }}</td>
    <tr>
        <td> contact.location_name_1|urlencode </td>
        <td> {{ contact.location_name_1|urlencode }} </td>
    </tr>
    <tr>
        <td>USING TEXT WIDGET</td>
        <td>
            {% text "encode" value={{ contact.location_name_1 }}, label="Enter slug", export_to_template_context=True %} 
            {{ widget_data.encode.value|urlencode }}
        </td>
    </tr>
</table>

and the ouput

contact.location_name_1                     The Next Location Name
contact.location_name_1|pprint              (PyMap: The Next Location Name)
contact.location_name_1|string|lower        The Next Location Name
contact.location_name_1|lower               The Next Location Name
contact.location_name_1|wordcount           2
contact.location_name_1|upper               The Next Location Name
contact.location_name_1|string|urlencode    The Next Location Name
contact.location_name_1|urlencode           (no output here)
USING TEXT WIDGET                           The Next Location Name 

Hopefully a HubSpot Dev can see this and resolve it asap.


#3

Hi @tcrawley and @arvinalmario

This looks like it’s related to a recent change we made to how some properties are handled. I’m working with our Email team now and post back here when I have any updates on this.


#4

Hi @tcrawley . The PyMap issue here is a bit of a red herring when debugging - the change here from String to PyMap should not have caused any problem. However we have released a fix so that these properties should appear as Strings again when passed to pprint.

The root cause of your issue is that most HubL features are not available when operating on contact / company / owner / custom properties. Internally the way we do this is when the HubL engine encounters a token like {{custom.abcd}} in an email while evaluating your HubL, it just echoes out the string “{{custom.abcd}}” without your filters. Later on when the email sending system sees this, it subs in the real value. This is why you get strange results like
{{custom.a_string|string|count}} = 19
The reason is that it’s actually counting the length of {{custom.a_string}} which is 19.

This is done because for email sending we first evaluate all HubL properties while preserving those 4 categories of tokens to later be subbed in at send time. This is for performance reasons when sending batch emails, which may be sent to 1,000,000+ recipients - substituting those variables at the last minute is much more performant. We are aware that this is a big limitation and have work planned to bring full HubL support to email. I can’t give you a timeline for its completion unfortunately.


#5

Hi @arvinalmario . Your issue is pretty similar to the first one reported in this thread but slightly different. In your case the change from these variables reporting as Strings to reporting as PyMaps did cause a change in behaviour. This was an unexpected bug caused by some recent upgrades to the HubL engine used for email, to support the new “custom owner” feature. This bug has been fixed and your values should now correctly appear as Strings instead of PyMaps again. Sorry for the bug and the confusion.

That’s not the full story though, since as I mentioned in my comment above, filters / conditions / expressions / loops etc do not work on contact / company / custom / owner properties in emails. Usually they just do nothing, but sometimes they can also cause the token to just disappear. We have work planned to add full support at some stage in the future, but I can’t give you a timeline.

In the mean time I suggest not using them at all in emails. We will also consider adding some validation / warning if we see that HubL is being used in a way that will give the wrong result in an email, pending full HubL support being available.


#6

Thanks @Padraig_Farrell ! all my emails are now working.

filters / conditions / expressions / loops etc do not work on contact / company / custom / owner properties in emails.

So this kind of statement will not work?

{% if "New York" in  {{ contact.location_name_1 }} %}
      Lorem Ipsum Dolor?
{% endif %}

I am using conditional statements on my emails but mostly checking the email’s internal name to see what kind of content should be displayed.

for example

{% if "Reminder 1" in content.name %}
    Please reminded that your next location is at {{ contact.location_name_1 }} on {{ contact.schedule_1 }} 
{% endif %}

#7

@arvinalmario you’re correct that the first statement will not work. This is because it’s operating on a contact property, which will not be available at the time when most of the template’s HubL is evaluated.

The second example does work, because the {{content}} object is available.


#8

Hi,
I am using custom contact property to store some numeric value e.g. carrier count. I want to write condition based on this property in my email template.

{% if contact.carrier_count > 2 %}

{% endif %}

It is not working. I tried to cast contact.carrier_count with int but it is returning 0.

Do you have any workaround for this?

Thanks,