Help! My Velocity {{my.token}} previews correctly, but I canโt approve the email
Velocity is already verbose, but youโve still gotta code defensively even if that means a little more code.
Crucially, in the Marketo-Velocity ecosystem, donโt assume code will only run in the context of a Person record. Prepare for person fields and object lists to be empty. This is true, for example, during asset approval.
Take this little snippet that adds a footer including the email domain:
#set( $emailParts = $lead.Email.split("@") )
#set( $emailDomain = $emailParts[1] )
If this email was mistakenly routed to your spam folder, ask the administrator of the ${emailDomain} mailserver to allow future emails from info@example.com.
Itโll run fine when you preview by a Person or List, but when you try to approve youโll get:
You canโt see the full error in the popup, but if you look at the underlying Java error itโs an ArrayIndexOutOfBoundsException
.[1]
And this makes sense! On line 1 the (overly naรฏve) email parser does a split()
on @
, then on line 2 it assumes the resulting array has at least 2 items.
This assumption is true of any valid email address. But when you approve, the placeholder value in $lead.Email
, as with all Person fields checked off in Script Editor, is an empty string. You can split()
an empty string, no problem. But the array only has 1 item (also an empty string). So if you try to seek the 2nd item โ index [1]
since arrays are 0-based โ thatโs out of bounds.
While Velocity swallows a lot of errors that would be fatal in pure Java, this isnโt one of them. Exceeding the length of an array is always fatal.
Coding for Approve Email
Simplest defensive move is checking if $lead.Email
is empty before continuing. This will let you approve the asset:
#if( !$lead.Email.isEmpty() )
#set( $emailParts = $lead.Email.split("@") )
If this email was mistakenly routed to your spam folder, ask the administrator of the ${emailDomain} mailserver to allow future emails from info@example.com.
#end
The above assumes $lead.email
is either empty or valid. A valid address must have an @
sign, so it doesnโt check beyond that.
If you want to also cover people with an invalid โ but non-empty โ $lead.Email
, switch it around so you split()
and check the expected length:
#set( $emailParts = $lead.Email.split("@") )
#if( $emailParts.size() > 1 )
#set( $emailDomain = $emailParts[1] )
If this email was mistakenly routed to your spam folder, ask the administrator of the ${emailDomain} mailserver to allow future emails from info@example.com.
#end
Even better, rethink split-and-get-2nd-item. As noted above, this is a naรฏve way of parsing the domain out of an email address.[2] Donโt you really mean split-and-get-last-item? I think you do. So if you do that, no matter whether $lead.email
is empty, valid, or invalid, thereโs no error:
#set( $emailParts = $lead.Email.split("@") )
#set( $emailDomain = $emailParts[$math.sub($emailParts.size(),1)] )
If this email was mistakenly routed to your spam folder, ask the administrator of the ${emailDomain} mailserver to allow future emails from info@example.com.
Notes
[1] In a local Velocity environment you see the stack trace:
Error invoking method 'get(java.lang.Integer)' in [Ljava.lang.String; at dynmacro.vm[line 52, column 33]
at org.apache.velocity.runtime.parser.node.ASTIndex.execute(ASTIndex.java:175)
at org.apache.velocity.runtime.parser.node.ASTReference.execute(ASTReference.java:280)
at org.apache.velocity.runtime.parser.node.ASTReference.value(ASTReference.java:567)
at org.apache.velocity.runtime.parser.node.ASTExpression.value(ASTExpression.java:71)
at org.apache.velocity.runtime.parser.node.ASTSetDirective.render(ASTSetDirective.java:142)
at org.apache.velocity.runtime.parser.node.SimpleNode.render(SimpleNode.java:342)
at org.apache.velocity.Template.merge(Template.java:356)
at org.apache.velocity.Template.merge(Template.java:260)
at VTLRunner.main(VTLRunner.java:92)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.velocity.util.introspection.UberspectImpl$VelMethodImpl.doInvoke(UberspectImpl.java:395)
at org.apache.velocity.util.introspection.UberspectImpl$VelMethodImpl.invoke(UberspectImpl.java:384)
at org.apache.velocity.runtime.parser.node.ASTIndex.execute(ASTIndex.java:149)
... 8 more
Caused by: java.lang.ArrayIndexOutOfBoundsException
at java.lang.reflect.Array.get(Native Method)
at org.apache.velocity.util.ArrayListWrapper.get(ArrayListWrapper.java:43)
[2] Itโs wrong for old-school but valid syntax like "sandy@home"@example.com
.