This worked great until a couple of weeks ago when we migrated from Exchange 2003 to 2010 and it all stopped working.
Of course, the guy who put this all together has since left the company so it was down to me to work out what was going on and put it right.
The mailbox monitoring script was written in well commented VBScript so it was fairly easy to follow. I turned on some 'debugging' (wscript.echo !) and found that the script was crashing when trying to parse long email subject lines (it breaks the subject line into fields to find the client name, job name, success or failure, etc.) because there were not as many fields as it was expecting.
Now there is no native way to read a mailbox in VBScript so this script uses a 3rd party ActiveX control called FreePop to connect to the mailbox and download the messages.
A little experimentation found that the Exchange server was line-wrapping the subject at 72 characters which effectively truncated it as far as FreePop was concerned, causing the problem. At first I looked for some way to change this line-wrapping, but it seems to be hard-coded and immutable, so I then looked about for an alternative way to access a mailbox from VBScript.
Of course, I could have used a different language (Powershell sprung to mind) but then I would have had to re-write the whole thing. Far preferable would be to simply replace the section of code that pulls the emails from the mailbox.
After a bit of Googling I discovered that Exchange 2010 exposes a web service (imaginatively called Exchange Web Services or EWS) that can be used to do this and much more. The only problem is that all the examples I could find were written in other languages than VBScript.
Still, not one to be deterred, I fiddled around until I got some test code successfully reading a mailbox inbox.
This code manually creates a SOAP xml message, submits it to the web service and parses the response - don't worry if you have no idea of what these things are, copy and paste works a treat :)
Watch out for those pesky line-breaks...
' set some variables
servername = "myExchangeServer"
username = "DOMAIN\User"
password = "UserPassword"
' enumerate items in inbox
smsoapmessage = "<?xml version='1.0' encoding='utf-8'?>" _
& "<soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/' xmlns:t='http://schemas.microsoft.com/exchange/services/2006/types'>" _
& " <soap:Body>"_
& " <FindItem xmlns='http://schemas.microsoft.com/exchange/services/2006/messages' xmlns:t='http://schemas.microsoft.com/exchange/services/2006/types' Traversal='Shallow'>" _
& " <ItemShape>" _
& " <t:BaseShape>AllProperties</t:BaseShape>" _
& " </ItemShape>" _
& " <ParentFolderIds>" _
& " <t:DistinguishedFolderId Id='inbox'/>" _
& " </ParentFolderIds>" _
& " </FindItem>" _
& " </soap:Body>" _
set req = createobject("microsoft.xmlhttp")
req.Open "post", "https://" & servername & "/ews/Exchange.asmx", False,username,password
req.setRequestHeader "Content-Type", "text/xml"
req.setRequestHeader "translate", "F"
if req.status = 200 then
set oXMLDoc = req.responseXML
set ResponseCode = oXMLDoc.getElementsByTagName("m:ResponseCode")
if ResponseCode(0).childNodes(0).text = "NoError" then
Set oXMLSubject = oXMLDoc.getElementsByTagName("t:Subject")
For i = 0 To (oXMLSubject.length -1)
set oSubject = oXMLSubject.nextNode
WScript.echo i & vbTab & oSubject.text
WScript.echo "Exchange server returned error: " & ResponseCode(0).childNodes(0).text
WScript.echo "Failed to connect to Exchange server, error code: " & req.status
When I first ran this I was getting a 200 for the request object which is a success but the Exchange server was returning "ErrorServerBusy". This threw me for a while, but I then discovered another new feature in Exchange 2010 called Throttling Policies.
Throttling policies are designed to prevent malicious or unintentional large requests from affecting the performance of the server and are enabled by default in Exchange 2010
MSDN blog on Understanding Throttling Policies
Using the Exchange shell to run the get-ThrottlingPolicy shows you all the default settings. In my case the problem was caused by the default EWSFindCountLimit being 1000 - the inbox I was querying had over 2000 items in it.
I could have changed the EWSFindCountLimit setting in either the default throttling policy or created a custom one just for this user, but as the only reason there was so many emails in the inbox was because the script had not been running for a while and this normally clears them out when it finishes, I just deleted all the old emails to get below a thousand.
Everything then worked beautifully.
Deleting the emails from the inbox after they have been processed is achieved by calling the EmptyFolder method with another SOAP request. Here is the xml for the request, I'll leave the actual VBScript to do this as an exercise for the reader :)
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<t:RequestServerVersion Version="Exchange2010_SP1" />
<m:EmptyFolder DeleteType="HardDelete" DeleteSubFolders="false">