Quickly share all linked Knowledge Articles in an email

Scenario

Picture it…you are sitting at your desk assisting a customer through a support incident. You are entering details in the case and have searched your knowledge articles to find an answers to assist the customer. You have linked multiple articles to the case that you know will help the customer. Now you want to share all the articles. What do you do next?

You can click on the ellipses directly under the article and select the option to email the article or email a link to the article. If you have multiple articles linked to the case, this can take a significant amount of time. This also inundates the customer with multiple emails to sort through to obtain answers.

Solution

There is a much more efficient way for you to share multiple articles with your customers via email. This feature uses a button on the email form that inserts the title and external portal URL for all linked Knowledge Articles in the body of the email message.

One afternoon I was working with my colleague and friend David Rodriquez. Using his master developer skills, he helped write most of the code used to build this feature. I needed this feature to be synchronous as users may want to add or edit content to the message after the titles and links had been inserted. Thus, we used JavaScript to complete the task.

Prerequisites

First, I wanted to drive customers to a portal to view the Knowledge Articles. This can help drive self-service in the future. It would also give me an indication on whether the article is being viewed at all. The Knowledge Article Views entity provides great metrics to help measure the success of articles. I installed the Customer Self-Service Portal. This portal template includes the ability to search published, external knowledge articles.

Second, I needed to obtain the URL for an external article on the portal so I could update the JavaScript to ensure the URL I would be including in the email would be correct. I accessed the portal after it has been configured, searched for and opened a published article.

Third, to ensure consistent message structure to my customers, I created a series of email templates for users that included the placeholder in a predefined location. This saves them time from having to compose an email and having to include the place holder.

Finally, if you follow the high level steps below, make sure you save and publish your changes as you create or update components.. I would suggest completing these steps in a sandbox environment.

Creating the Web Resource

First, we need to add the JavaScript to our solution as a web resource. In your solution, navigate to Web Resources on the left. Create a new Web Resource with the type of Script (JScript). Using the text editor, paste the JavaScript below. Make sure you edit the code with your environment information as described below in the Additional notes section.

Script web resource

Add the script web resource to the Email form

For the Email entity, add the main form that your end users will use when sending emails in Dynamics 365 Customer Service. Edit the form and click on Form Properties in the ribbon. Add your script web resource under the Form Libraries.

Adding a button to the ribbon

I wanted a button on the email form for users to click and insert the linked articles and titles on-demand. Using Ribbon Workbench, I added a button to the ribbon on the email form to execute the JavaScript and place the article titles and URLs in the body of the message.

Compose an email

You can test the functionality by simply inserting the {{INSERT_LINKED_KB}} placeholder in the body of an email. I would suggest creating an email template that contains the placeholder so you don’t have to copy and paste all the time.

Additional notes

Here are somethings to note for this feature:

  • In the JavaScript below locate the line “//UPDATE PORTAL URL HERE” and update the portalurl variable with your portal URL.
  • This script can be used to build an external URL to the Knowledge Article on the Portal.
  • The external URL that is built does not have any language reference included. You can modify the code that builds the URL to include the language so it will direct the customer to the language translation of the article.
  • This script will be looking for the {{INSERT_LINKED_KB}} placeholder in the body of an email. This placeholder can be used in email templates to ensure consistent placement in email communications.
  • The email message must have a Case set in the regarding field for the insert function to work. If the regarding is not a Case, nothing will happen.

Code

// JavaScript source code
function buttonArticles() {

    var articleContentPlaceholder = "{{INSERT_LINKED_KB}}";
    var regardingLookupValue = Xrm.Page.getAttribute("regardingobjectid").getValue();

    if (regardingLookupValue != null) {

        if (regardingLookupValue[0].entityType == "incident") { /* if the Email is regarding a Case */

            var descriptionCurrentContent = Xrm.Page.getAttribute("description").getValue();

            // Check if the Email Description has the placeholder
            if (descriptionCurrentContent.indexOf(articleContentPlaceholder) == -1) {
                Xrm.Page.ui.setFormNotification("An Email Template having the placeholder {{INSERT_LINKED_KB}} hasn't been inserted.", "INFO", "kbarticle");
            }
            else {
                Xrm.Page.ui.setFormNotification("Retrieving KB Article content from associated case...", "INFO", "kbarticle");

                try {

                    var req = new XMLHttpRequest();
                    req.open("GET", Xrm.Page.context.getClientUrl() + String.format("/api/data/v8.2/knowledgearticleincidents?$expand=knowledgearticleid($select=content,isinternal,statecode,title,articlepublicnumber)&$filter=_incidentid_value eq {0}", regardingLookupValue[0].id), true);
                    req.setRequestHeader("OData-MaxVersion", "4.0");
                    req.setRequestHeader("OData-Version", "4.0");
                    req.setRequestHeader("Accept", "application/json");
                    req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
                    req.setRequestHeader("Prefer", "odata.include-annotations=\"*\"");
                    req.onreadystatechange = function () {
                        if (this.readyState === 4) {
                            req.onreadystatechange = null;
                            if (this.status === 200) {
                                var results = JSON.parse(this.response);

                                if (results.value.length == 0) {

                                    Xrm.Page.ui.setFormNotification("There are no KB Article(s) associated with this case.", "INFO", "kbarticle");
                                    return;
                                }

                                var descriptionReplacedContent = "";

                                for (var i = 0; i < results.value.length; i++) {
                                    var knowledgearticleincidentid = results.value[i]["knowledgearticleincidentid"];
                                    //Use @odata.nextLink to query resulting related records
                                    var knowledgearticleid_NextLink = results.value[i]["knowledgearticleid@odata.nextLink"];

                                    //ENTER PORTAL URL HERE
                                    var portalurl = "https://<<ReplaceWithOrgName>>.powerappsportals.com/knowledgebase/article/";

                                    var title = results.value[i].knowledgearticleid.title; //
                                    var articlenumber = results.value[i].knowledgearticleid.articlepublicnumber;

                                    var portalarticleurl = (portalurl + articlenumber);
                                    var portalarticlelink = portalarticleurl.link(portalarticleurl);

                                    descriptionReplacedContent += ("<b>" + title + "</b><br/>" + portalarticlelink + "<br/><br/>");
                                }

                                descriptionReplacedContent = descriptionCurrentContent.replace(articleContentPlaceholder, descriptionReplacedContent);
                                Xrm.Page.getAttribute("description").setValue(descriptionReplacedContent);

                                Xrm.Page.ui.setFormNotification("KB Article(s) Content from associated case has been inserted into the Email Description.", "INFO", "kbarticle");

                            } else {
                                Xrm.Utility.alertDialog(this.statusText);
                            }
                        }
                    };
                    req.send();
                }
                catch (e) { Xrm.Page.ui.setFormNotification("Error retrieving article content from associated case.", "ERROR", "kbarticle_error"); }
            }
        }
    }
}

Conclusion

I hope you find this feature useful. I am not a professional developer which is why I knew to work with someone with experience. Let me know in the comments how this turned out for you.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s