Out of the box, Dynamics CRM 4.0 lets you send a link to CRM activity records by clicking Actions->Send Shortcut from the top toolbar. This forces users to open up the link in order to view the contents of an Activity. When an email chain regarding the linked Activity starts to form, it can become a hassle to open up the Activity each time to see the message body. The following javscript code and addition to the isv.config file will simplify matters by giving users an 'Email' button to email the text of the activity.
Start off by exporting your isv.config file. Open up the customizations.xml file and locate the "<Entity name="task">" section. Paste the following code between the "Entity" tags for Task. If the Entity Task tag doesn't exist, copy and paste the whole section of xml below.
<Entity name="task"> <ToolBar ValidForCreate="0" ValidForUpdate="1"> <Button Client="Web, Outlook" Icon="../../../ISV/styles/outlookSmall.gif" JavaScript="createOutlookEmail(); " PassParams="1" WinMode="0"> <Titles> <Title LCID="1033" Text=" Email " /> </Titles> <ToolTips> <ToolTip LCID="1033" Text="Email Activity using Outlook" /> </ToolTips> </Button> </ToolBar> </Entity>
Download the Outlook icon we use for the button from the file here: Download Zip. You will want to place this Outlook icon inside the "C:\Program Files\Microsoft Dynamics CRM\CRMWeb\ISV\styles" of your CRM 4.0 server. A "styles" directory may not yet exist so please create one and then drop the smallOutlook.gif file in.
Next, we'll customize the Task entity by adding the javascript below to its Form Properties->OnLoad event. The following code uses the Outlook.Application ActiveX control, which provides a mechanism for Internet Explorer to access Outlook APIs. You will notice a FetchXml query in the code, this is used to find a Contact's Account name when the Regarding field of an activity has been set to a Contact. Feel free to change or modify the body of the Email message. I chose to include the Account name, Actual end date, Owner, Activity type, link to activity, Activity subject and Activity description fields but you may find other fields more useful.
// // export activity to Outlook Email, activated by button in toolbar // createOutlookEmail = function() { var linkLocation = location.href; //link to activity var emailBody = ''; //contents of body of email //ActiveX calls to open new Outlook email template var outlookApp = new ActiveXObject('Outlook.Application'); var nameSpace = outlookApp.getNameSpace('MAPI'); var mailFolder = nameSpace.getDefaultFolder(6); var mailItem = mailFolder.Items.add('IPM.Note.FormA'); if (crmForm.all.regardingobjectid.DataValue) { //regarding is set to an account if (crmForm.all.regardingobjectid.DataValue[0].type == 1) { emailBody = 'Account name: ' + crmForm.all.regardingobjectid.DataValue[0].name; } //regarding is set to a contact else if (crmForm.all.regardingobjectid.DataValue[0].type == 2) { //write fetchxml statement to query for contact's parent account name var fetchQuery = '<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="true" page="1" count="1"><entity name="contact"><attribute name="contactid"/><filter type="and"><condition attribute="contactid" operator="eq" uitype="contact" value="' + crmForm.all.regardingobjectid.DataValue[0].id + '"/></filter><link-entity name="account" from="accountid" to="parentcustomerid" visible="false" link-type="outer" alias="contactparentcustomeridaccountaccountid"><attribute name="name"/></link-entity></entity></fetch>'; //package fetchxml in xml statement var xmlQuery = '<?xml version="1.0" encoding="utf-8"?>' + '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">' + GenerateAuthenticationHeader() + ' <soap:Body>' + '<Fetch xmlns="http://schemas.microsoft.com/crm/2007/WebServices">' + '<fetchXml>' + _HtmlEncode(fetchQuery) + '</fetchXml>' + '</Fetch></soap:Body></soap:Envelope>'; //package xml into ajax soap request var xmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP"); xmlHttpRequest.Open("POST", "/mscrmservices/2007/CrmService.asmx", false); xmlHttpRequest.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/crm/2007/WebServices/Fetch"); xmlHttpRequest.setRequestHeader("Content-Type", "text/xml; charset=utf-8"); xmlHttpRequest.setRequestHeader("Content-Length", xmlQuery.length); xmlHttpRequest.send(xmlQuery); //format xml response to replace esacaped characters var resultXml = xmlHttpRequest.responseXML.xmlQuery.toString(); resultXml = resultXml.replace(/</g, "<"); resultXml = resultXml.replace(/>/g, ">"); resultXml = resultXml.replace(/&/g, "&"); //load xml response into xml parser var xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); xmlDoc.async = "false"; xmlDoc.loadXML(resultXml); //parse xml response to find account name node and add to emailBody var entityNodes = xmlDoc.selectNodes("//FetchResult/resultset/result"); var descriptionNode = ''; for (var i = 0; i < entityNodes.length; i++) { var entityNode = entityNodes[i]; descriptionNode = entityNode .selectSingleNode("contactparentcustomeridaccountaccountid.name"); emailBody = 'Account name: '; } //add contact name to emailBody emailBody += descriptionNode.text + '\nContact name: ' + crmForm.all.regardingobjectid.DataValue[0].name; } emailBody = emailBody + '\n'; } //escape '{' and '}' symbols in link to activity linkLocation = linkLocation.replace(/{/g, '%7b'); linkLocation = linkLocation.replace(/}/g, '%7d'); //set subject of Outlook email message mailItem.Subject = crmForm.all.subject.value; //set body of Outlook email message mailItem.Body = emailBody + 'Actual End Date: ' + crmForm.all.actualend.DataValue + '\nOwner: ' + crmForm.all.ownerid.DataValue[0].name + '\nActivity Type: Task\nLink: ' + linkLocation + '\n\nSubject: ' + crmForm.all.subject.value + '\n\nDescription: ' + (crmForm.all.description.DataValue == null ? '' : crmForm.all.description.DataValue); //show final Outlook email on user's screen mailItem.display(0); }
The final step is to enable ActiveX controls to run within your intranet. By default Internet Explorer is configured to block ActiveX controls as they can allow malicious virus writers to potentially take over your desktop. However, since our instance of Dynamics CRM 4.0 is on premise, we can safely choose to enable ActiveX controls on our local intranet. Follow the steps below to enable the setting for "Initialize and script ActiveX controls not marked safe for scripting." Make sure to select the Local Intranet icon in step 1, otherwise you may make your computer vulnerable to ActiveX script attacks. If you have a large organization, it may be helpful to script out the change in one blast.
In the above example I used the Task entity. If you want the Email button to appear for other Activity entities, you will need to add the javascript above to the Form Properties->OnLoad event of the other entities as well. In addition, you must also copy the xml code above and paste it into the other "<Entity></Entity>" sections for the other Activity types.