Saying Goodbye to ActiveX

I’ve never had much reason to use ActiveX controls, though one major web application I support has a function where users are able to send log entries via Outlook email. This function was built using an ActiveX control many years ago, when Internet Explorer was the only browser we had to support. If a user wanted to run Chrome, they had to do without this function.

Now that Internet Explorer 11 is being sunsetted this year, and Microsoft Edge will only have IE 11 mode through 2025, it is high time to update any apps that rely on technologies like ActiveX that only work in IE or Edge’s IE 11 mode.

The original code that created the ActiveX control is below.

function(oContent,sSubject,sTitleHTML)
		{
			 try
			 {
				 var sContent = buildPrintHTML(oContent,sSubject,sTitleHTML,"email");
				 var outlookApp = new ActiveXObject("Outlook.Application");
				 var mailItem = outlookApp.CreateItem(0);
				 mailItem.Subject=sSubject;
				 mailItem.HTMLBody = sContent;
				 mailItem.Display (0);
			 }
			 catch(er)
			 {
				 alert(er.message);
			 }
			 finally
			 {
				mailItem = null;
				mailFolder = null;
				nameSpace = null;
				outlookApp = null;
			 }
		};

When a user clicked the link that called this function, the Outlook.Application ActiveX control would open a new HTML email in Outlook containing all the text, including URLs, from the shared log entry.

Initially, I thought about building an anchor tag that would store all the email data in the URL in the query string and use an HTTP GET request to send it to the server. I discovered quickly that this wouldn’t work, as there are limitations on how long a query string can be, and that limit is around 2000 characters if the URL is to be compatible with most browsers.

An article on Stack Overflow pointed me in the right direction: creating an anchor tag with all of the data in the href attribute, but not to be used in a GET request. The link would use the download attribute, which would cause the data stored in the href attribute to be downloaded as a file. Though any file format can be placed here, only one that would cause an Outlook email to be generated would work for this purpose. A MIME file type that can be used for this is EML.

The JavaScript code below would, after building the anchor tag and adding it programmatically to the form as a hidden link, automatically “click” the hidden link, which would download the contents of the href attribute as an EML file, which would open in Outlook just as the ActiveX control did.

function(oContent,sSubject,sTitleHTML,sEmailLogEntryID)
		{
			 try
			 {
				var sContent = buildPrintHTML(oContent,sSubject,sTitleHTML,"email");
				
				if(browserUtility.isIE()||browserUtility.isIE11()) {
					var outlookApp = new ActiveXObject("Outlook.Application");
					var mailItem = outlookApp.CreateItem(0);
					mailItem.Subject=sSubject;
					mailItem.HTMLBody = sContent;
					mailItem.Display (0);
				} else {					
					sContent = sContent.replaceAll('#','%23');
					sSubject = sSubject.replaceAll('#','%23');
								 
					var emlContent = "data:message/rfc822 eml;charset=utf-8,";
					emlContent += 'To: \n';
					emlContent += 'Subject: '+sSubject+'\n';
					emlContent += 'X-Unsent: 1'+'\n';
					emlContent += 'Content-Type: text/html'+'\n';
					emlContent += ''+'\n';
					emlContent += sContent;
					
					var d = new Date();
					var sDate = d.getUTCFullYear() + ("0"+(d.getUTCMonth()+1)).slice(-2) + ("0" + d.getUTCDate()).slice(-2)   + ("0" + d.getUTCHours()).slice(-2) + ("0" + d.getUTCMinutes()).slice(-2) + ("0" + d.getUTCSeconds()).slice(-2) + ("00" + d.getUTCMilliseconds()).slice(-3);
					
					var encodedUri = encodeURI(emlContent); //encode spaces etc like a url
					var a = document.createElement('a'); //make a link in document
					var linkText = document.createTextNode("fileLink");
					a.appendChild(linkText);
					a.href = encodedUri;
					a.id = 'fileLink';
					a.download = 'logEntryEmail_' + sEmailLogEntryID + '_' + sDate + '.eml';
					a.style = "display:none;"; //hidden link
					
					document.body.appendChild(a);
					document.getElementById('fileLink').click(); //click the link
				};					
			 }
			 catch(er)
			 {
				 alert(er.message);
			 }
			 finally
			 {
				outlookApp = null;
				mailItem = null;
				sContent = null;
				emlContent = null;
				encodedUri = null;
				a = null;
				linkText = null;				
				d = null;
				dateString = null;
			 }

There were a few pitfalls that had to be overcome in completing this. If the HTML code includes any octothorpes (a.k.a, number sign, pound sign, hashtag), these must be escaped by replacing them with the hex code “%23” (no quotes). Otherwise, they will cause the URL to be processed incorrectly, causing errors.

In some cases, escaping the number signs won’t work. For instances where they are used as CSS colors, either the common name should be used when one exists (i.e., #FFFFFF is “white”), or RGB should be subbed in instead.

For the filename, I concatenated both a unique log entry ID, and the UTC time the file was created to prevent duplicate filenames in the user’s downloads folder.

 

Leave a Reply