An Exchange Server EWS JavaScript Client In A Single HTM File

Leave a comment
Share

I normally code server-side Exchange Web-based clients, but I am often asked by people with no admin access to their Exchange server (and are therefore not in a position to install anything on it) if I can make something similar that can be installed on the client side. Normally, I regretfully decline, since it doesn’t seem possible to do all the things I’d like to do using javascript. How might you access the address list, for example?

For some reason (and I can’t quite remember what it was) I was thinking some more about this recently, and it occurred to me that (leaving address books aside for the present) making a usable javascript client Exchange might not be as ridiculous an idea as I’d previously thought.

Anyway, if there’s anyone out there that is at all interested in this, here is what I’ve managed to do so far. It’s early days yet, and I don’t know how far I’ll be able to go with it. Google Chrome is already proving to be a pain, since it gets upset about cross-domain posting (the script posts EWS requests from your local computer to the Exchange server), so the only way you can use it in Chrome is to turn off its cross-domain checking. Or actually run it from the server’s default web site.

The code below is what I have up to now. Copy/paste into an .htm file, double-click it, and supply user name, password, and server name.

In case you prefer to download it, there is a copy here:

mailbox.zip

<!DOCTYPE html>

<html>

<head>

<style type="text/css">
body {font-family:Verdana;}
</style>

<script type="text/javascript">

var bHasDOMParser;
var p, pw0, server, un0;
var x, x2;
var iFirstItem, iItemsPerPage, iLastItem, iNumItems;
var nsm = "http://schemas.microsoft.com/exchange/services/2006/messages";
var nst = "http://schemas.microsoft.com/exchange/services/2006/types";

var oItemList, oItem;

function countItems()
{
var n = 0;
var strXML =
"<m:FindItem Traversal=\"Shallow\">" +
"<m:ItemShape>" +
"<t:BaseShape>IdOnly</t:BaseShape>" +
"</m:ItemShape>" +
"<m:IndexedPageItemView MaxEntriesReturned=\"1\" BasePoint=\"End\" Offset=\"0\"/>" +
"<m:ParentFolderIds>" +
"<t:DistinguishedFolderId Id=\"inbox\"></t:DistinguishedFolderId>" +
"</m:ParentFolderIds>" +
"</m:FindItem>";
doSoapRequest(strXML);
if (bHasDOMParser)
{
x2 = p.parseFromString(x.responseText, "text/xml");
n = x2.getElementsByTagNameNS(nsm, "RootFolder")[0].getAttribute("TotalItemsInView");
}
else
{
x2.loadXML(x.responseText);
n = x2.getElementsByTagName("//m:RootFolder")[0].getAttribute("TotalItemsInView");
}
iNumItems = n;
}

function doPreviousNext()
{
var e, e2;
e = document.getElementById("btnTopButton");
e2 = document.getElementById("btnPreviousButton");
if (iFirstItem > 1)
{
e.style.visibility = "";
e2.style.visibility = "";
}
else
{
e.style.visibility = "hidden";
e2.style.visibility = "hidden";
}
e = document.getElementById("btnNextButton");
e2 = document.getElementById("btnEndButton");
if (iFirstItem <= (iNumItems - iItemsPerPage))
{
e.style.visibility = "";
e2.style.visibility = "";
}
else
{
e.style.visibility = "hidden";
e2.style.visibility = "hidden";
}
e = document.getElementById("spnItemNumbers");
e.innerHTML = iFirstItem + " - " + iLastItem + " of " + iNumItems;
}

function doSoapRequest(inS)
{
var s = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<S:E XMLNS:SOAP XMLNS:T XMLNS:M>" +
"<S:B>" +
inS +
"</soap:Body>" +
"</soap:Envelope>";
s = s.replace("<S:B>", "<SP1><S:B>");
s = s.replace("<SP1>", "<soap:Header><t:RequestServerVersion Version=\"Exchange2010\"/></soap:Header>");
s = s.replace("S:E", "soap:Envelope");
s = s.replace("S:B", "soap:Body");
s = s.replace("XMLNS:M", "xmlns:m=\"http://schemas.microsoft.com/exchange/services/2006/messages\"");
s = s.replace("XMLNS:T", "xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\"");
s = s.replace("XMLNS:SOAP", "xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"");
s = s.replace("XMLNS:XSD", "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"");
s = s.replace("XMLNS:XSI", "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"");
x.open("POST", "https://" + server + "/EWS/Exchange.asmx", false, un0, pw0);
x.setRequestHeader("Content-type", "text/xml");

try
{
x.send(s);
}
catch(e)
{
alert("Error");
}
}

function doTop()
{
iFirstItem = 1;
showItemList();
}

function doPrevious()
{
iFirstItem = iFirstItem - iItemsPerPage;
if (iFirstItem < 1)
iFirstItem = 1;
showItemList();
}

function doNext()
{
iFirstItem = iFirstItem + iItemsPerPage;
showItemList();
}

function doEnd()
{
iFirstItem = (parseInt(iNumItems / iItemsPerPage) * iItemsPerPage) + 1;
showItemList();
}

function getFirstAndLastItems()
{
if (iFirstItem > iNumItems)
iFirstItem = (parseInt(iNumItems / iItemsPerPage) * iItemsPerPage) + 1;
if (iFirstItem < 1)
iFirstItem = 1;
if ((iFirstItem + (iItemsPerPage - 1)) > iNumItems)
iLastItem = iNumItems;
else
iLastItem = iFirstItem + (iItemsPerPage - 1);
}

function getFormValue(inID)
{
var e = document.getElementById(inID);
return e.value;
}

function showItem(inId)
{
oItemList.style.visibility = "hidden";
oItem.style.visibility = "";
var strXML =
"<m:GetItem>" +
"<m:ItemShape>" +
"<t:BaseShape>AllProperties</t:BaseShape>" +
"<t:BodyType>Text</t:BodyType>" +
"</m:ItemShape>" +
"<m:ItemIds>" +
"<t:ItemId Id=\"" + inId + "\"/>" +
"</m:ItemIds>" +
"</m:GetItem>";
doSoapRequest(strXML);
if (bHasDOMParser)
{
x2 = p.parseFromString(x.responseText, "text/xml");
}
else
{
x2.loadXML(x.responseText);
}
var oDiv = document.getElementById("divItemDetails");
var s = "";
var sSender;
if (bHasDOMParser)
sSender = x2.getElementsByTagNameNS(nst, "Name")[0].childNodes[0].nodeValue;
else
sSender = x2.getElementsByTagName("t:Name")[0].childNodes[0].nodeValue;
s = s + "From: " + sSender;
var sDateTimeSent;
if (bHasDOMParser)
sDateTimeSent = x2.getElementsByTagNameNS(nst, "DateTimeSent")[0].childNodes[0].nodeValue;
else
sDateTimeSent = x2.getElementsByTagName("t:DateTimeSent")[0].childNodes[0].nodeValue;
var dDateTimeSent = new Date(sDateTimeSent);
s = s + "\nTime: " + dDateTimeSent;
var sSubject;
if (bHasDOMParser)
sSubject = x2.getElementsByTagNameNS(nst, "Subject")[0].childNodes[0].nodeValue;
else
sSubject = x2.getElementsByTagName("t:Subject")[0].childNodes[0].nodeValue;
s = s + "\nSubject: " + sSubject;
var sBody;
if (bHasDOMParser)
{
sBody = x2.getElementsByTagNameNS(nst, "Body")[0].childNodes[0].nodeValue;
}
else
sBody = x2.selectSingleNode("//t:ExtendedFieldURI[@PropertyTag=\"0x1000\"]/following-sibling::t:Value").childNodes[0].nodeValue;
s = s + "\n" + sBody;
oDiv.innerText = s;
}

function showItemList()
{
var items;
oItem.style.visibility = "hidden";
oItemList.style.visibility = "";
countItems();
getFirstAndLastItems();
doPreviousNext();
var strXML =
"<m:FindItem Traversal=\"Shallow\">" +
"<m:ItemShape>" +
"<t:BaseShape>Default</t:BaseShape>" +
"</m:ItemShape>" +
"<m:IndexedPageItemView MaxEntriesReturned=\"" + iItemsPerPage + "\" BasePoint=\"Beginning\" Offset=\"" + (iFirstItem - 1) + "\"/>" +
"<m:ParentFolderIds>" +
"<t:DistinguishedFolderId Id=\"inbox\"></t:DistinguishedFolderId>" +
"</m:ParentFolderIds>" +
"</m:FindItem>";
doSoapRequest(strXML);
if (bHasDOMParser)
{
x2 = p.parseFromString(x.responseText, "text/xml");
items = x2.getElementsByTagNameNS(nst, "Message");
}
else
{
x2.loadXML(x.responseText);
items = x2.getElementsByTagName("t:Message");
}
var oDiv = document.getElementById("divItemListDetails");
oDiv.innerHTML = "";
var oTbl = document.createElement("table");
oDiv.appendChild(oTbl);
var sDateDisplayed = new Date().toLocaleDateString();
for (var i = 0; i < items.length; i++)
{
var oCell, oRow;
var item = items[i];
var sDateTimeSent;
if (bHasDOMParser)
sDateTimeSent = item.getElementsByTagNameNS(nst, "DateTimeSent")[0].childNodes[0].nodeValue;
else
sDateTimeSent = item.getElementsByTagName("t:DateTimeSent")[0].childNodes[0].nodeValue;
var dDateTimeSent = new Date(sDateTimeSent);
var sDateSent = dDateTimeSent.toLocaleDateString();
var sTimeSent = dDateTimeSent.toLocaleTimeString();
if (sDateSent != sDateDisplayed)
{
oRow = oTbl.insertRow(-1);
oCell = oRow.insertCell(-1);
oCell.colSpan = "3";
oCell.style.backgroundColor = "#80D0E0";
oCell.innerHTML = sDateSent;
sDateDisplayed = sDateSent;
}
oRow = oTbl.insertRow(-1);
oCell = oRow.insertCell(-1);
if (bHasDOMParser)
oCell.innerHTML = item.getElementsByTagNameNS(nst, "Name")[0].childNodes[0].nodeValue;
else
oCell.innerHTML = item.getElementsByTagName("t:Name")[0].childNodes[0].nodeValue;
oCell = oRow.insertCell(-1);
if (bHasDOMParser)
oCell.innerHTML = item.getElementsByTagNameNS(nst, "Subject")[0].childNodes[0].nodeValue;
else
oCell.innerHTML = item.getElementsByTagName("t:Subject")[0].childNodes[0].nodeValue;
var sId;
if (bHasDOMParser)
sId = item.getElementsByTagNameNS(nst, "ItemId")[0].getAttribute("Id");
else
sId = item.getElementsByTagName("t:ItemId")[0].getAttribute("Id");
oCell.setAttribute("onclick", "showItem(\"" + sId + "\");");
oCell = oRow.insertCell(-1);
oCell.innerHTML = sTimeSent;
}
}

function showMailbox()
{
un0 = getFormValue("un0");
pw0 = getFormValue("pw0");
server = getFormValue("Server");
if (window.XMLHttpRequest)
{
x = new XMLHttpRequest;
}
else
{
x = new(ActiveXObject("Microsoft.XMLHTTP"));
}
if (window.DOMParser)
{
p = new DOMParser();
bHasDOMParser = true;
}
else
{
x2 = new ActiveXObject("Microsoft.XMLDOM");
x2.async = false;
x2.setProperty("SelectionLanguage", "XPath");
x2.setProperty("SelectionNamespaces", "xmlns:m=\"" + nsm + "\" xmlns:t=\"" + nst +"\"");
bHasDOMParser = false;
}
oItemList = document.getElementById("divItemList");
oItem = document.getElementById("divItem");
iFirstItem = 1;
iItemsPerPage = 10;
showItemList();
}

</script>
</head>

<body>

<table>
<tr>
<td>User name</td>
<td><input type="text" id="un0" name="un0" value=""></td>
</tr>
<tr>
<td>Password</td>
<td><input type="password" id="pw0" name="pw0" value=""></td>
</tr>
<tr>
<td>Server</td>
<td><input type="text" id="Server" name="Server" value=""></td>
</tr>
</table>

<div style="padding-top:10px;">

<div id="divItemList" style="position:absolute;">
<button onclick="showMailbox();">GO</button>
<button id="btnTopButton" onclick="doTop();" style="visibility:hidden;">&lt;&lt;</button>
<button id="btnPreviousButton" onclick="doPrevious();" style="visibility:hidden;">&lt;</button>
<button id="btnNextButton" onclick="doNext();" style="visibility:hidden;">&gt;</button>
<button id="btnEndButton" onclick="doEnd();" style="visibility:hidden;">&gt;&gt;</button>
<span id="spnItemNumbers"></span>
<div id="divItemListDetails"></div>
</div>

<div id="divItem" style="position:absolute;visibility:hidden;">
<button onclick="showItemList();">BACK TO FOLDER</button>
<div id="divItemDetails"></div>
</div>

</div>

</body>

</html>




Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>