JosephW1
Tera Guru

Hello!

 

OUTLINE
1. Introduction
2. What's The Big Deal With Outlook?
3. How Do We Fix This?
4. STEP 1: New Script Include
5. STEP 2: Update Our Email Script(s)
6. What's The End Result?

 

1. INTRODUCTION
This article explains how to utilize buttons with rounded corners that are compatible with both Outlook and HTML clients such as Gmail.

These are highly likely to be compatible with most email clients, but I don't want to make that claim without testing. And I don't want to test that, haha!

 

2. WHAT'S THE BIG DEAL WITH OUTLOOK?
Why single Outlook out from HTML clients, you ask? Good question. Have you seen what Outlook does to ServiceNow's email "buttons"?

find_real_file.png

Once you get back from the 1990s, which that button brought you back to, I'll explain.

The Outlook Desktop Client uses VML to draw shapes. Not HTML. Interesting, isn't it? Wikipedia calls VML a "depreciated format" used for "legacy reasons only". Haha, I'm sure they have good reasons, but man that complicates things. (I'm guessing they like VML's mysterious, complicated, and undocumented current-use aspect, as it causes a border-to-entry which probably helps keep their product proprietary, making it difficult to copy/imitate their product.) This means that it ends up taking our HTML shapes that we feed to it, does its best to translate the HTML into VML - while dropping a lot of "words" that it cannot comprehend - and we end up with these ugly rectangles with 90 degree edges, and malformed padding and borders.

 

3. HOW DO WE FIX THIS?
Three words. Outlook Conditional Comments. I'm no expert, I just did a bunch of research on this so that I could stop Outlook's tyranny, as I like to call it. I'm sharing with you what I found in my research and development.

CREDIT WHERE IT'S DUE: Thank you VanAlbert! This gentleman provided the answer to the Rounded corners in outlook without images Stack Exchange question, which I heavily used to produce this solution. I just translated it to ServiceNow speak in a re-usable format, that's all. 😉

If you follow these steps, you too can generate professional, modern looking buttons from ServiceNow that do not break in the Outlook email client, while still remaining compatible with HTML email clients.

 

4. STEP 1: New Script Include
First, let's create this script include. This has code that detects if the email client is "mso" (Outlook) and uses VML if it is, HTML if it's not. This creates compatibility for Outlook's legacy rendering scheme, while retaining compatibility with our normal HTML clients.

We're housing this in a script include for convenience, to allow easy re-use elsewhere.

Just call one of the two script includes below and feed it the variables (message, size, colors, link, border-radius) that fit your own unique situation, and you've got your own customized button, anywhere you want to include it, easy!

Object: Script Include
Name: OutlookRoundedButtonDynamic
Application: Global
Accessible from: This application scope only
Client callable: FALSE
Description:Script include for creating rounded buttons usingy using VML for the Outlook client, while using HTML for all others.
This version dynamically sizes the button to fit the text via the mso-fit-shape-to-text attribute.
Script:

function OutlookRoundedButtonDynamic(Message, FontSize, FontColor, bgColor, BorderRadius, Arcsize, Hyperlink){
//FontSize: CAUTION! The text's width grows faster than the autosize does, eventually causing clipping at roughly 30-40px FontSize and 25 characters.
//Arcsize: VML uses Arcsize, HTML uses border-radius. 20% arcsize equals roughly 7px border-radius.
//Padding: CAUTION! The VML's inset eventually outpaces the autosize, being likely to cause clipping when handled dynamically. Therefore, the HTML padding has been coded to the VML's inset default of 0.1in left/right and 0.05in top/bottom.

//Assemble the HTML string in logical pieces, pulling in the Variables
var ifmso = '<!--[if mso]>'; //Microsoft Outlook (Outlook Conditional Comments)
var thenVML = '<v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word" href="' + Hyperlink + '" style="mso-wrap-style:none; mso-position-horizontal:center;" arcsize="' + Arcsize + '" fillcolor="#' + bgColor + '" stroke="false"><v:textbox style="mso-fit-shape-to-text:true;"><center style="color:#' + FontColor + '; font-family:sans-serif; font-size:' + FontSize + 'px; font-weight:bold;">' + Message + '</center></v:textbox></v:roundrect><![endif]--><!--[if !mso]> <!-->';
var elseHTML = '<a href="' + Hyperlink + '" style="background-color:#' + bgColor + '; color:#' + FontColor + '; font-size: ' + FontSize + 'px; font-weight: bold; font-family:sans-serif; text-decoration:none; text-align: center; border-radius:' + BorderRadius + 'px; -webkit-border-radius:' + BorderRadius + 'px; -moz-border-radius:' + BorderRadius + 'px; display:inline-block; padding:0.05in 0.1in;">' + Message + '</a>';
var endif = '<!-- <![endif]-->';

//Return the compiled HTML string
return ifmso + thenVML + elseHTML + endif;
}

 

Object: Script Include
Name: OutlookRoundedButtonFixed
Application: Global
Accessible from:This application scope only
Client callable: FALSE
Description:Script include for creating rounded buttons usingy using VML for the Outlook client, while using HTML for all others.
This version uses a fixed size via the width and height attributes.
Script:function OutlookRoundedButtonFixed(Message, FontSize, FontColor, Width, Height, bgColor, BorderRadius, Arcsize , Hyperlink){
//Arcsize: VML uses Arcsize, HTML uses border-radius. 20% arcsize equals roughly 7px border-radius.
//Pros: Allows you to control the padding (indirectly via Width & Height), and to choose fixed-size buttons when desired.
//Cons: The Width/Height attributes render inconsistently on a few machines. We had a few desktop computers that were shrinking the buttons in Outlook by roughly 20%, causing the text to clip. VDI Outlook, OWA, and HTML all rendered the size consistently, just these two desktop's Outlook were shrinking it. (One such machine's symptoms disappeared after some misc system updates.)


//Assemble the HTML string in logical pieces, pulling in the Variables
var ifmso = '<!--[if mso]>'//Microsoft Outlook (Outlook Conditional Comments)
var thenVML = '<v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word" href="' + Hyperlink + '" style="width:' + Width + 'px; height:' + Height + 'px; mso-position-horizontal:center; mso-wrap-style:none;" stroke="false" arcsize="' + Arcsize + '" fillcolor="#' + bgColor + '"><v:textbox style="v-text-anchor:middle"><center style="color:#' + FontColor + '; font-family:sans-serif; font-size:' + FontSize + 'px; font-weight:bold;">' + Message + '</center></v:textbox></v:roundrect><![endif]--><!--[if !mso]> <!-->';
var elseHTML = '<a href="' + Hyperlink + '" style="width:' + Width + 'px; height:' + Height + 'px; line-height: ' + Height + 'px; background-color:#' + bgColor + '; color:#' + FontColor + '; font-size:' + FontSize + 'px; font-weight:bold; font-family:sans-serif; text-decoration:none; text-align:center; border-radius:' + BorderRadius + 'px; -webkit-border-radius:'+ BorderRadius + 'px; -moz-border-radius:' + BorderRadius + 'px; display:inline-block;">' + Message + '</a>';
var endif = '<!-- <![endif]-->';

//Return the compiled HTML string
return ifmso + thenVML + elseHTML + endif;
}

 

 

 

5. STEP 2: Update our Email Script(s)
Second, let's get in the incident_take_me_to_the_incident email script, clear out the old shape code, and utilize our new button script include.
NOTE: I've also merged a survey notification into my version of this email script, which is shown below. Please consider this and remove it as needed to fit your personal use cases.

Object: Email Script
Name: incident_take_me_to_the_incident
Application: Global
Newlines to HTML FALSE
Script:

(function runMailScript(current, template, email, email_action, event) {

//Get Instance Base URL
var instanceURL = gs.getProperty("glide.servlet.uri");
var overrideURL = gs.getProperty("glide.email.override.url");
if (overrideURL) {
instanceURL = overrideURL;
} else {
instanceURL = instanceURL + "nav_to.do?uri=";
}

//Find Relevant Survey, Get sysID, & Print Message
var instance = 'nosurvey';
var type = 'notype';
var gr = new GlideRecord('asmt_assessment_instance');
if (gr.get('trigger_id', current.sys_id)) {
gr.addQuery('state', '=', 'ready');
gr.orderByDesc('sys_created_on');
gr.query();
if (gr.next()) {
instance = gr.sys_id;
type = gr.metric_type;
}
var surveyURL = '';
surveyURL = instanceURL + 'assessment_take2.do%3Fsysparm_assessable_type=' + type + '%26sysparm_assessable_sysid=' + instance;
template.print('<p><font size="3" color="#808080" face="helvetica">');
template.print(gs.getMessage('Please click the <b><font color="#6FAC46">green</font></b> button below to complete a short survey about this incident.'));
template.print('</font></p>');
}

//Short Conditional Blurb (Resolution or otherwise)
var incidentURL = instanceURL + current.getLink();
if (email_action.name != "Incident Resolved") {
template.print('<p><font size="3" color="#808080" face="helvetica">');
template.print(gs.getMessage('You can view all the details of the incident by following the link below:'));
template.print('</font></p>');
}
else {
template.print('<p><font size="3" color="#808080" face="helvetica">');
template.print(gs.getMessage('If you feel the issue is has not been fully resolved, please click the <b><font color="#0086EA">blue</font></b> button below to visit your personalized portal page, or call your local help desk to reopen the incident.'));
template.print('</font><br></p>');
}

//Print Improved Outlook Buttons
if (surveyURL) {
template.print(OutlookRoundedButtonDynamic('Take me to the Survey', '16', 'FFFFFF', '6FAC46', '7', '20%', surveyURL) + '&nbsp;');
//template.print(OutlookRoundedButtonFixed('Take me to the Survey', '16', 'FFFFFF', '200', '30', '6FAC46', '7', '20%', surveyURL) + '&nbsp;');
}
template.print(OutlookRoundedButtonDynamic('Take me to the Incident', '16', 'FFFFFF', '0086EA', '7', '20%', incidentURL));
//template.print(OutlookRoundedButtonFixed('Take me to the Incident', '16', 'FFFFFF', '210', '30', '0086EA', '7', '20%', incidentURL));

//Print Portal Link
template.print('<p><br><font size="4" color="000000">Visit the <a href="https://www.google.com">End User Portal</a> for additional services, or call the Help Desk at 1-234-567-8901 for assistance</font></p>');

})(current, template, email, email_action, event);

 

6. WHAT'S THE END RESULT?
Congratulations, you now have an email notification script with rounded buttons that render correctly in Outlook instead of being corrupted! All while also rendering correctly in HTML email clients, and contained in an easy to re-use package. Mission accomplished. High-five!

 find_real_file.png

 

 

I hope that you find this article insight and helpful in your pursuits. Thanks!

 

Kind Regards,

Joseph

Comments
nborowiak
Tera Contributor

This is great @JosephW!

Question for ya,

Our users are creating requests and incidents from Service Portal.
A series of notifications are sent to users by email with the incident and/or request link from the email template.

The problem we are having is that those URL reference are redirecting users to the ServiceNow platform back-end instead of the Service Portal incident to request link.

What is the best way to define in email template the link to the SP?

I tried using the following along with your updated take_me_to_the_incident but I was unsuccessful at getting it to load properly.

var url = '<a href="' + gs.getProperty('glide.servlet.uri') + 'sp?id=ticket&table=' + current.getTableName() + '&sys_id=' + current.sys_id + '">' + current.number + '</a>';
template.print(url);
JosephW1
Tera Guru

You're not trying to make that link you posted into an Outlook button, right? Looks like you're just trying to add a plain bit of hyperlinked text to your email.

If so... I don't know. Your URL schematic looks correct, except it might be worth replacing "current.sys_id" with "current.getUniqueValue()" to see if that fixes your invalid link.

Version history
Last update:
‎10-23-2020 06:30 AM
Updated by: