Hobby Chef
First thing first, this is just for demonstration purpose and might *not* be a supported solution by Microsoft. The setting we are reading from are hidden messages and not documented anywhere. I had to reverse engineer it for demonstration purpose.
Objective: To get OOF State of any user in your organization.
Challenges: You might ask me why not use GetUserOofSettings to query user’s OOF status with the help of Exchange Impersonation? This is due to the limitation of EWS’s GetUserOofSettings/SetUserOofSettings methods as they don’t support Impersonation.
Workaround: Directly reading the hidden messages from Mailbox Root where this Flag & OOF message is stored. Since we are read-only we should be good to do so, that’s my assumption.
We need to first make a FindItem call to the mailbox root and search for a message with ItemClass = “IPM.Microsoft.OOF.UserOOFSettings”. Assuming that there will be only one message with that message class at any given time, we get its ItemId and make a GetItem call to read the message body. The message body is plain text XML with following structure
For OOF enabled…
<UserOofSettings> <OofState >Enabled</OofState> </UserOofSettings>
For OOF disabled…
<UserOofSettings> <OofState >Disabled</OofState> </UserOofSettings>
There is also a state called SCHEDULED, please refer to the below mentioned article to know more about it
Reference: http://msdn.microsoft.com/en-us/library/aa580465.aspx
This code sample can do the job for you.
using System; using GetOOFState.MyEWS; namespace GetOOFState { class Program { static void Main(string[] args) { ExchangeServiceBinding esb = new ExchangeServiceBinding(); esb.Url = "https://server/ews/exchange.asmx"; esb.Credentials = new System.Net.NetworkCredential("ServiceAccount", Password", "Domain"); esb.ExchangeImpersonation = new ExchangeImpersonationType(); esb.ExchangeImpersonation.ConnectingSID = new ConnectingSIDType(); esb.ExchangeImpersonation.ConnectingSID.PrimarySmtpAddress = "username@domain.com"; FindItemType fit = new FindItemType(); fit.ItemShape = new ItemResponseShapeType(); fit.ItemShape.BaseShape = DefaultShapeNamesType.AllProperties; fit.Restriction = new RestrictionType(); IsEqualToType itemMessageClass = new IsEqualToType(); PathToUnindexedFieldType msgClassProp = new PathToUnindexedFieldType(); msgClassProp.FieldURI = UnindexedFieldURIType.itemItemClass; ConstantValueType msgClassValue = new ConstantValueType(); msgClassValue.Value = "IPM.Microsoft.OOF.UserOOFSettings"; itemMessageClass.Item = msgClassProp; itemMessageClass.FieldURIOrConstant = new FieldURIOrConstantType(); itemMessageClass.FieldURIOrConstant.Item = msgClassValue; fit.Restriction = new RestrictionType(); fit.Restriction.Item = itemMessageClass; DistinguishedFolderIdType rootFolder = new DistinguishedFolderIdType(); rootFolder.Id = DistinguishedFolderIdNameType.root; fit.ParentFolderIds = new BaseFolderIdType[] { rootFolder }; FindItemResponseType firt = esb.FindItem(fit); string itemID = ((ArrayOfRealItemsType)((FindItemResponseMessageType)firt.ResponseMessages.Items[0]).RootFolder.Item).Items[0].ItemId.Id; GetItemType git = new GetItemType(); ItemIdType iit = new ItemIdType(); iit.Id = itemID; git.ItemIds = new BaseItemIdType[] { iit }; git.ItemShape = new ItemResponseShapeType(); git.ItemShape.BaseShape = DefaultShapeNamesType.IdOnly; PathToUnindexedFieldType []propsToFetch = new PathToUnindexedFieldType[1]; propsToFetch[0] = new PathToUnindexedFieldType(); propsToFetch[0].FieldURI = UnindexedFieldURIType.itemBody; git.ItemShape.AdditionalProperties = propsToFetch; GetItemResponseType girt = esb.GetItem(git); ItemType itemOOF = ((ItemType)(((ItemInfoResponseMessageType)girt.ResponseMessages.Items[0]).Items.Items[0])); System.Xml.XmlDocument xDoc = new System.Xml.XmlDocument(); xDoc.LoadXml(itemOOF.Body.Value); Console.WriteLine("OOF State: {0}", xDoc.GetElementsByTagName("OofState")[0].InnerText); } } }
Happy Coding!!!
This is going to be a very simple sample of how you can send an email with custom properties set and also change the message class so that it render on outlook as Custom Form.
Prerequisites: A custom form must be published with same class name to render the email properly.
How it works…
Step 1) It drop an email in the drafts folder of user
Step 2) Patches the properties to set Message Class & other properties, even including with special characters in name like Spaces and ‘/’
Step 3) Drop the mail to DavMailSubmissionURL to send it
Code:
Imports System.Net
Imports System.IO
Imports System.Web
Module Module1
Const strServer As String = "Exchange_Server_Name"
Const strMailbox As String = "Target_Mailbox"
Const strFrom As String = "from@domain.com"
Const strTo As String = "to@domain.com"
Const strSubject As String = "Custom form email - sent using WebDAV"
Const strBody As String = "<B>Hello There,</B><BR> Hope you are doing good.<BR>Good Bye!!!"
Const strMessageClass As String = "IPM.Note.TestMessageClass"
Const strDomain As String = "DomainNameHere"
Const strUsername As String = "UsernameToLoginWith"
Const strPassword As String = "Password"
Dim objCDO As New CDO.Message
Dim strMIME As String
Dim sQuery As String = ""
Dim sUri As Uri = New Uri("http://" & strServer & "/Exchange/" + strMailbox & "/Drafts/" & Guid.NewGuid().ToString() & ".eml")
Dim sDavSubmissionURI As Uri = New Uri("http://" & strServer & "/Exchange/" + strMailbox & "/%23%23DavMailSubmissionURI%23%23/")
Dim DavRequest As HttpWebRequest = DirectCast(WebRequest.Create(sUri), HttpWebRequest)
Dim myCred As New NetworkCredential((strDomain & "\" & strUsername), strPassword)
Dim myCredentialCache As New CredentialCache()
Dim ByteQuery As Byte()
Dim QueryStream As Stream
Dim DavResponse As HttpWebResponse
Dim iStatCode As Integer
Dim sStatus As String
Dim strm As Stream
Dim sr As StreamReader
Dim sText As String
Sub Main()
Console.WriteLine("Preparing message...")
PrepairMessage()
Console.WriteLine("Creating message in draft folder...")
CreateMessageInDraft()
Console.WriteLine("Updating message class & other properties...")
SetMessageProperties()
Console.WriteLine("Sending message...")
SendMessage()
Console.WriteLine("Message Sent")
End Sub
Sub PrepairMessage()
With objCDO
.From = strFrom
.To = strTo
.Subject = strSubject
.HTMLBody = strBody
strMIME = .GetStream.ReadText
End With
sQuery = strMIME
Sub CreateMessageInDraft()
myCredentialCache.Add(sUri, "Basic", myCred)
DavRequest.Credentials = myCredentialCache
DavRequest.KeepAlive = False
DavRequest.Headers.Set("Translate", "f")
DavRequest.ContentType = "message/rfc822"
DavRequest.ContentLength = sQuery.Length
'Set the request timeout to 5 minutes.
DavRequest.Timeout = 300000
' Set the request method.
DavRequest.Method = "PUT"
' Store the data in a byte array.
ByteQuery = System.Text.Encoding.UTF8.GetBytes(sQuery)
DavRequest.ContentLength = ByteQuery.Length
QueryStream = DavRequest.GetRequestStream()
' write the data to be posted to the Request Stream
QueryStream.Write(ByteQuery, 0, ByteQuery.Length)
QueryStream.Close()
QueryStream = Nothing
' Send the request and get the response.
DavResponse = DirectCast(DavRequest.GetResponse(), HttpWebResponse)
' Get the Status code.
iStatCode = CInt(DavResponse.StatusCode)
sStatus = iStatCode.ToString()
Console.WriteLine("Status Code: " & sStatus.ToString())
' Read the response stream.
strm = DavResponse.GetResponseStream()
sr = New StreamReader(strm)
sText = sr.ReadToEnd()
Console.WriteLine("Response: " & sText)
' Close the stream.
strm.Close()
Sub SetMessageProperties()
Dim sPropPatch As String = "<?xml version=""1.0""?>" + _
"<g:propertyupdate xmlns:g=""DAV:"">" + _
"<g:set>" + _
"<g:prop>" + _
"<d:outlookmessageclass xmlns:d=""http://schemas.microsoft.com/exchange/"">" & strMessageClass & "</d:outlookmessageclass>" + _
"<NewCustomProperty>" & "CustomProperty1" & "</NewCustomProperty>" + _
"</g:prop>" + _
"</g:set>" + _
"</g:propertyupdate>"
DavRequest = Nothing
DavResponse = Nothing
DavRequest = DirectCast(WebRequest.Create(sUri), HttpWebRequest)
DavRequest.ContentType = "text/xml"
DavRequest.Method = "PROPPATCH"
ByteQuery = System.Text.Encoding.UTF8.GetBytes(sPropPatch)
Sub SendMessage()
DavRequest.Method = "MOVE"
DavRequest.Headers.Add("Destination", sDavSubmissionURI.ToString())
End Module
Note: I will update the sample to include custom properties with special characters soon… last edited: 5/23/09 4:19 AM