Re: Introducing Agical.io, the smarter ICS file generator

SanfordWhiteman
Level 10 - Community Moderator

If you've used Marketo's dynamic ICS files (the "Calendar File" token type) you're probably not completely happy with 'em.

About a year ago, I published a (free) microservice that fills in the biggest gaps. With a little more attention on it lately (read: 2 people cared!), I blogged about it.

Read more on TEKNKL :: Blog →

57 REPLIES 57
SanfordWhiteman
Level 10 - Community Moderator

Well, you have it set to recur weekly, forever. So that's why it does that. You have to include "recuruntil" and a timestamp if you want it to stop.

But that's not the only problem... you have one event set to last an entire 2 weeks. I assume you actually mean 3 individual days. You need to set the "dtstart" and "dtend" accordingly for the first day, then let the weekly recurrence schedule the next 2.

Jyotsna_Gupta1
Level 1

This is awesome. Able to set the recurrence correctly now. Thank you!

One more ask - can we rename the ics file?

SanfordWhiteman
Level 10 - Community Moderator
One more ask - can we rename the ics file?

Sorry, not at this time.

Tags (1)
Samantha_Cossum
Level 3

Hey Sanford,

I have a couple of questions that I couldn't fine addressed anywhere but if it is sorry for re-asking!

1. I'm having issues using the recur with Outlook. It works fine when I open the file into my iCal but when I open into Outlook it says all meetings occur in the past.

http://ics.agical.io/?subject=Submit+Your+Stats&organizer=Results+Creator+Bootcamp&reminder=0&locati...

Screen Shot 2019-04-25 at 12.35.57 PM.png

2. Is there a way to set an end date for a recurring calendar? I tried setting the dtend but, at least in iCal, it just keeps going. The desire would be for the event to recur on the 1st every month and the final one to be on 02/01/2020. Here's what I tried:

http://ics.agical.io/?subject=Submit+Your+Stats&organizer=Results+Creator+Bootcamp&reminder=0&locati...

SanfordWhiteman
Level 10 - Community Moderator

Let's start with the first one.

The string "&replace00" looks pretty weird there. Are you sure you don't have a typo in the actual link sent to people (the sample URL you posted to the Nation is fine, but are you using {{lead.token}} or {{my.token}} in the email?). I'll do some more checking in Outlook if you tell me the exact version.

Jyotsna_Gupta1
Level 1

Hi Sanford,

I am also creating a recurring calendar invite and have specified the dtend parameter but when i am importing it in Outlook 2016 it just keeps going. Were you able to find the cause?

My ical url - http://ics.agical.io/?subject=Crash%20Course&organizer=Company&reminder=15&location=ON24&recur=weekl...

I know it is too long description but we require it like that. One more issue i am facing is when the cal is downloaded from Landing page new line character "\n" works but for emails it is not working so for emails i am using <br />(URL ecoding - %3Cbr%20%2F%3E). Could you please confirm if this is the right way?

Thanks,

Jyotsna

Samantha_Cossum
Level 3

No tokens just the straight link we are testing to use.

We're using outlook 2019 365 for Macs. Thanks for looking into this I really appreciate the help!

Anonymous
Not applicable

Great stuff, thanks Sanford. I think this is exactly what I am looking for.

Anonymous
Not applicable

Hey Sanford,

I hope you're doing well. I'm trying to use the Agical.io ICS file generator you built and am running into an issue that I hope you can help me resolve. Thank you for creating this tool and offering it to the Marketo community.

I have two velocity scripting based tokens for the event start date and end date that are record specific and need to be in the URL for the ICS file. When I try to reference those tokens as values in a URL an extra space is added, causing the hyperlink to fail when clicked. By fail, I mean that the event start time and end time reders as a static value: 12/31/1969 4:00 PM. I believe this is due to the URL being rewritten by Marketo for tracking purposes. If you copy and paste the non-rewritten URL in a browser, the link works just fine.

Rewritten/tracked URL: http://em.sungevity.com/dc/s4ZLka5FfdFC9m1cmI_hrfzCmWMofwKTi4SUWBNAIw3LVZb3cBJV4iftjWnumggM45sqe1n3F...

Copied and pasted URL with populated custom tokens: http://ics.agical.io/?subject=Sungevity%20Home%20Visit&organizer=Sungevity&reminder=45&location=1205...

See the spaces below. The issues looks specific to the token being included in a URL as the first two bullets are just non-linked token values. The rest are hyperlinks and are problematic. Please let me know if you have any ideas to resolve this issue. Thanks very much!

pastedImage_4.png

Daniel

SanfordWhiteman
Level 10 - Community Moderator

Are you positive there isn't whitespace being output from your script?  Remember, Velocity preserves whitespace like line breaks, because the output context may require it (think text part of an email as opposed to HTML part).

Anonymous
Not applicable

Thanks for your quick reply. That's great to know. I've removed all visible line breaks and spaces, but the link still populates with spaces. Do you have any other ideas for what could be causing the issue?

Here's script for the first token that's referenced as the dtstart parameter.

##Start of Script

## first want to grab the value of the home visit date time and convert it into format we want

## BASED ON SFDC CONFIG, ASSUMING THIS VALUE IS IN PST plus 2 hours

## used parseDate (string value, string format) within velocity

#set($dateObj = $convert.parseDate($Milestone1_Project__cList.get(0).Home_Visit_Date__c, 'yyyy-MM-dd HH:mm'))

## then we convert to a calendar object

#set($calendarObj = $convert.toCalendar($dateObj))

## comparing Time Zone on the Project and the to localize appointment time

#if ($Milestone1_Project__cList.get(0).Time_Zone__c == "EST" && $Milestone1_Project__cList.get(0).Home_Visit_Date__c.contains("12:00:00"))

## 10 represents 'hour' in calendar object?

## add 7 hours + 8 hours as it's translated into Greenwich in the final output.

$calendarObj.add(10,24)

#elseif ($Milestone1_Project__cList.get(0).Time_Zone__c == "CST" && $Milestone1_Project__cList.get(0).Home_Visit_Date__c.contains("12:00:00"))

$calendarObj.add(10,23)

#elseif ($Milestone1_Project__cList.get(0).Time_Zone__c == "MST" && $Milestone1_Project__cList.get(0).Home_Visit_Date__c.contains("12:00:00"))

$calendarObj.add(10,22)

#elseif ($Milestone1_Project__cList.get(0).Time_Zone__c == "PST" && $Milestone1_Project__cList.get(0).Home_Visit_Date__c.contains("12:00:00"))

$calendarObj.add(10,21)

## comparing Time Zone and value in Home Visit Date field to update all records that don't have an appointment at 12:00pm

#elseif ($Milestone1_Project__cList.get(0).Time_Zone__c == "EST" && !$Milestone1_Project__cList.get(0).Home_Visit_Date__c.contains("12:00:00"))

$calendarObj.add(10,12)

#elseif ($Milestone1_Project__cList.get(0).Time_Zone__c == "CST" && !$Milestone1_Project__cList.get(0).Home_Visit_Date__c.contains("12:00:00"))

$calendarObj.add(10,11)

#elseif ($Milestone1_Project__cList.get(0).Time_Zone__c == "MST" && !$Milestone1_Project__cList.get(0).Home_Visit_Date__c.contains("12:00:00"))

$calendarObj.add(10,10)

#elseif ($Milestone1_Project__cList.get(0).Time_Zone__c == "PST" && !$Milestone1_Project__cList.get(0).Home_Visit_Date__c.contains("12:00:00"))

$calendarObj.add(10,9)

#end

$date.format('yyyy-MM-dd',$calendarObj)T$date.format('HH:mm:ss',$calendarObj)Z

SanfordWhiteman
Level 10 - Community Moderator

Daniel Mandel did you make headway with this today?

Anonymous
Not applicable

Hey Sanford,

Yep, the token outputs the correct value without spaces. Thank you for providing a more scalable and easily modified structure for the token.

I encountered a bizarre issue when using that token within a URL or just as a standalone text value. This definitely looks like Marketo bug and I brought to Marketo Support who has already escalated internally to their engineering team since this is such bizarre behavior. See below for context. This issues doesn't seem to be specific to these tokens or tokens in general; it's a larger issue that seems to randomly remove sections of text and URLs in the email in both samples and in production.

1) I expected to see the static/non-token text that's in the emai draft prior to sending a sample.  See the text in purple below.

Inline image 1

2) I also expect to see the mytokens populated in one email with the following values for a specific Marketo Lead we've been testing. We tested these token individually and they populated, but when they are combined in one email (only the tokens, no URL or other text), only one token populates.

When these tokens did populate correctly in a sample email, they produced the following values as expected:

  • {{my.Project HV Start Date Calendar}}: 2017-01-04T23:00:00Z
  • {{my.Project HV End Date Calendar}}: 2017-01-05T02:00:00Z

3) I also expect to see the same URL referenced in the email draft with the same tokens populated. Instead though, the parameter "dtend=" just dissapears entirely and then the token value for the {{my.Project HV Start Date Calendar}} is shown twice: http://ics.agical.io/?subject=Sungevity%20Home%20Visit&organizer=Sungevity&reminder=45&location=1205...

When the URL is tracked, it just fails all together meaning it creates an ICS file, but the start and end date are incorrect.

Here's a screenshot of the sample email:

Inline image 1

Here's a screenshot of the production email:

Inline image 1

SanfordWhiteman
Level 10 - Community Moderator

(Yikes, I really want to rewrite that #if...#elseif block, but I'll hold myself back.)

The final line does likely have a line break.  End the whole script with ##.

Also, whenever you do "no-output output" like:

     $calendarObj.add(10,9)

that's still output.  If you're just calling a method and not expecting output, better practice is:

     #set( $tmp = $calendarObj.add(10,9) )

This is guaranteed to be a #set directive only, not an output line.

SanfordWhiteman
Level 10 - Community Moderator

(Yikes, I really want to rewrite that #if...#elseif block, but I'll hold myself back.)

I couldn't stop myself...

You don't have to do this now (it isn't causing your problem) but think about a collection-first coding approach. It makes for fewer errors because there's less repetition. In the Velocity world, this is especially important because VTL swallows errors that would be fatal in other languages, and also because of the whitespace issue as noted above (the fewer lines that may generate output, the easier it is to trim whitespace).

When you think of collections first, long lists of conditions become index and/or property lookups instead. Though "magic strings" and "magic numbers" are not completely eliminated, they're all in one place where they can be easily maintained and typos more easily caught.

#set( $DATE_PART_HOUR = 10 )

#set( $tzInfo = {

  "EST" : {

    "12:00" : 0,

    "" : 12

  },

  "CST" : {

    "12:00" : 23,

    "" : 11

  },

  "MST" : {

    "12:00" : 22,

    "" : 10

  },

  "PST" : {

    "12:00" : 21,

    "" : 9

  },

  "" : {

    "" : 0

  }

} )

#set( $project = $Milestone1_Project__cList[0] )

#set( $project.homeVisitCal = $convert.toCalendar($convert.parseDate($project.Home_Visit_Date__c, 'yyyy-MM-dd HH:mm') ) )

#set( $project.homeVisitTime = $date.format('HH:mm', $project.homeVisitCal) )

## /* get tz info based on stored tz abbr (including empty string) */

#set( $tzOffsets = $tzInfo[$project.Time_Zone__c] )

## /* get current offset based on "magic" time slot(s) or default slot */

#set( $currentOffset = $tzOffsets[$project.homeVisitTime] )

#if( !$currentOffset )#set( $currentOffset = $tzOffsets[""] )#end

## /* add hours to Calendar */

#set( $tmp = $project.homeVisitCal.add($DATE_PART_HOUR, $currentOffset) )

${date.format("yyyy-MM-dd'T'HH:mm:ss'Z'",$project.homeVisitCal)}##

Note the use of the empty string as the default key -- not something I'd do in other contexts but helpful in Marketo, where an empty value comes in often. So you have $obj["token_value_1"], $object["token_value_2"], or $object[""], where the last one is the default.

Also, as I'm sure I mentioned elsewhere, the manual management of hour offsets is prone to error in its own right. I'm not changing that approach here, but I would feel more comfortable if you used Java's timezone-awareness instead of adding to the calendar object. The only time I would use Calendar::add and such is if I weren't dealing with time zones but some other non-standard date arithmetic, like days of a trial period, etc.

Anonymous
Not applicable

Thanks sanford!