http://www.infinitec.de/InfiniTec - Henning Krauses Blog - Exchange articles2011-10-25T18:22:40+00:00Don't adjust your mind - it's reality that is malfunctioning Henning KrauseBlogEngine.Net Syndication Generatorhttp://www.infinitec.de/opml.axdHenning KrauseDon't adjust your mind - it's reality that is malfunctioning en-USInfiniTec - Henning Krauses Blog 0.0000000.000000http://www.infinitec.de/post/2011/10/25/Searching-the-Global-Address-List-C-Edition.aspxSearching the Global Address List - C# Edition2011-10-25T18:22:40+00:00hkrause<p>A long time ago, I wrote an article on <a href="http://www.infinitec.de/post/2005/02/27/How-to-get-the-Global-Address-List-programatically.aspx">How to get the Global Address List programatically</a>. The theory behind that article is still valid, but it only features a VBScript example. Since someone from the Microsoft Exchange Forum had trouble converting it to C#, I fired up Visual Studio and hacked something together. The result is somewhat more complete than the VBScript example, because it allows access to all address lists, not just the default global address list (GAL).</p> <p>Here we go:</p> <pre class="brush: csharp; auto-links: false;">using System;
using System.Collections.Generic;
using System.DirectoryServices;
using System.Linq;
namespace AddressListSample
{
public class ActiveDirectoryConnection
{
public DirectoryEntry GetLdapDirectoryEntry(string path)
{
return GetDirectoryEntry(path, "LDAP");
}
public DirectoryEntry GetGCDirectoryEntry(string path)
{
return GetDirectoryEntry(path, "GC");
}
private DirectoryEntry GetDirectoryEntry(string path, string protocol)
{
var ldapPath = string.IsNullOrEmpty(path) ? string.Format("{0}:", protocol) : string.Format("{0}://{1}", protocol, path);
return new DirectoryEntry(ldapPath);
}
}
public class ExchangeAddressListService
{
private readonly ActiveDirectoryConnection _Connection;
public ExchangeAddressListService(ActiveDirectoryConnection connection)
{
if (connection == null) throw new ArgumentNullException("connection");
_Connection = connection;
}
public IEnumerable<AddressList> GetGlobalAddressLists()
{
return GetAddressLists("CN=All Global Address Lists");
}
public IEnumerable<AddressList> GetAllAddressLists()
{
return GetAddressLists("CN=All Address Lists");
}
public IEnumerable<AddressList> GetSystemAddressLists()
{
return GetAddressLists("CN=All System Address Lists");
}
private IEnumerable<AddressList> GetAddressLists(string containerName)
{
string exchangeRootPath;
using (var root = _Connection.GetLdapDirectoryEntry("RootDSE"))
{
exchangeRootPath = string.Format("CN=Microsoft Exchange, CN=Services, {0}", root.Properties["configurationNamingContext"].Value);
}
string companyRoot;
using (var exchangeRoot = _Connection.GetLdapDirectoryEntry(exchangeRootPath))
using (var searcher = new DirectorySearcher(exchangeRoot, "(objectclass=msExchOrganizationContainer)"))
{
companyRoot = (string) searcher.FindOne().Properties["distinguishedName"][0];
}
var globalAddressListPath = string.Format(containerName + ",CN=Address Lists Container, {0}", companyRoot);
var addressListContainer = _Connection.GetLdapDirectoryEntry(globalAddressListPath);
using (var searcher = new DirectorySearcher(addressListContainer, "(objectClass=addressBookContainer)"))
{
searcher.SearchScope = SearchScope.OneLevel;
using (var searchResultCollection = searcher.FindAll())
{
foreach (SearchResult addressBook in searchResultCollection)
{
yield return
new AddressList((string) addressBook.Properties["distinguishedName"][0], _Connection);
}
}
}
}
}
public class AddressList
{
private readonly ActiveDirectoryConnection _Connection;
private readonly string _Path;
private DirectoryEntry _DirectoryEntry;
internal AddressList(string path, ActiveDirectoryConnection connection)
{
_Path = path;
_Connection = connection;
}
private DirectoryEntry DirectoryEntry
{
get
{
if (_DirectoryEntry == null)
{
_DirectoryEntry = _Connection.GetLdapDirectoryEntry(_Path);
}
return _DirectoryEntry;
}
}
public string Name
{
get { return (string) DirectoryEntry.Properties["name"].Value; }
}
public IEnumerable<SearchResult> GetMembers(params string[] propertiesToLoad)
{
var rootDse = _Connection.GetGCDirectoryEntry(string.Empty);
var searchRoot = rootDse.Children.Cast<DirectoryEntry>().First();
using (var searcher = new DirectorySearcher(searchRoot, string.Format("(showInAddressBook={0})", _Path)))
{
if (propertiesToLoad != null)
{
searcher.PropertiesToLoad.AddRange(propertiesToLoad);
}
searcher.SearchScope = SearchScope.Subtree;
searcher.PageSize = 512;
do
{
using (var result = searcher.FindAll())
{
foreach (SearchResult searchResult in result)
{
yield return searchResult;
}
if (result.Count < 512) break;
}
} while (true);
}
}
}
internal class Program
{
private static void Main()
{
var connection = new ActiveDirectoryConnection();
var service = new ExchangeAddressListService(connection);
foreach (var addressList in service.GetGlobalAddressLists())
{
Console.Out.WriteLine("addressList.Name = {0}", addressList.Name);
foreach (var searchResult in addressList.GetMembers())
{
Console.Out.WriteLine("\t{0}", searchResult.Properties["name"][0]);
}
}
foreach (var addressList in service.GetAllAddressLists())
{
Console.Out.WriteLine("addressList.Name = {0}", addressList.Name);
foreach (var searchResult in addressList.GetMembers())
{
Console.Out.WriteLine("\t{0}", searchResult.Properties["name"][0]);
}
}
foreach (var addressList in service.GetSystemAddressLists())
{
Console.Out.WriteLine("addressList.Name = {0}", addressList.Name);
foreach (var searchResult in addressList.GetMembers())
{
Console.Out.WriteLine("\t{0}", searchResult.Properties["name"][0]);
}
}
}
}
}</pre>
<p>The sample wraps the whole logic up into two classes: ExchangeAddressListService and AddressList. The first serves as some kind of entry point and the latter allows access to the members of a list.</p>
<p>Hope this helps…</p>2011-10-25T18:22:40+00:00hkrausehttp://www.infinitec.de/pingback.axdhttp://www.infinitec.de/post.aspx?id=de77b361-966d-4104-84b9-9f5935d5dd9e12http://www.infinitec.de/trackback.axd?id=de77b361-966d-4104-84b9-9f5935d5dd9ehttp://www.infinitec.de/post/2011/10/25/Searching-the-Global-Address-List-C-Edition.aspx#commenthttp://www.infinitec.de/syndication.axd?post=de77b361-966d-4104-84b9-9f5935d5dd9ehttp://www.infinitec.de/post/2011/10/05/Setting-the-Homepage-of-an-Exchange-folder-using-the-EWS-Managed-API.aspxSetting the Homepage of an Exchange folder using the EWS Managed API2011-10-05T17:30:43+00:00hkrause<p>A while ago, Glen posted an <a href="http://gsexdev.blogspot.com/2007/07/setting-homepage-on-outlook-folder-via.html">article</a> on his blog on how to set homepage of a folder using ADO and later he posted a version of that script which uses the EWS managed API to do this in this <a href="http://social.technet.microsoft.com/Forums/en/exchangesvrdevelopment/thread/d4516dca-34bb-4a9c-83df-f2b3df94cfc4">MSDN forum thread</a>. However, he wrote it for the first version of the API, and the EWS Managed API 1.1 has a slightly different object model. Since someone on the MSDN forums had difficulties to update the script to work with the EWS Managed API 1.1, I thought I just post an updated version here:</p> <pre class="brush: csharp; auto-links: false;">private static void SetFolderHomePage(IEnumerable<string> pathFragments, string url, ExchangeService service)
{
var folderWebviewinfoProperty = new ExtendedPropertyDefinition(14047, MapiPropertyType.Binary);
var root = Folder.Bind(service, WellKnownFolderName.MsgFolderRoot);
var targetFolder = root;
foreach (var fragment in pathFragments)
{
var result = service.FindFolders(targetFolder.Id, new SearchFilter.IsEqualTo(FolderSchema.DisplayName, fragment), new FolderView(1));
if (result.TotalCount == 0)
{
throw new InvalidOperationException(string.Format("Folder fragment {0} was not found.", fragment));
}
targetFolder = result.Folders[0];
}
targetFolder.SetExtendedProperty(folderWebviewinfoProperty, EncodeUrl(url));
targetFolder.Update();
}
private static byte[] EncodeUrl(string url)
{
var writer = new StringWriter();
var dataSize = ((ConvertToHex(url).Length / 2) + 2).ToString("X2");
writer.Write("02"); // Version
writer.Write("00000001"); // Type
writer.Write("00000001"); // Flags
writer.Write("00000000000000000000000000000000000000000000000000000000"); // unused
writer.Write("000000");
writer.Write(dataSize);
writer.Write("000000");
writer.Write(ConvertToHex(url));
writer.Write("0000");
var buffer = HexStringToByteArray(writer.ToString());
return buffer;
}
private static string ConvertToHex(string input)
{
return string.Join(string.Empty, input.Select(c => ((int) c).ToString("x2") + "00").ToArray());
}
private static byte[] HexStringToByteArray(string input)
{
return Enumerable
.Range(0, input.Length/2)
.Select(index => byte.Parse(input.Substring(index*2, 2), NumberStyles.AllowHexSpecifier)).ToArray();
}</pre>
<p>You can set the homepage of a folder by calling the SetFolderHomepage method:</p>
<pre class="brush: csharp; auto-links: false;">SetFolderHomePage(service, new[] {"InfiniTec blog"}, <a href="http://www.infinitec.de">http://www.infinitec.de</a>);</pre>2011-10-05T17:30:43+00:00hkrausehttp://www.infinitec.de/pingback.axdhttp://www.infinitec.de/post.aspx?id=8ac429f4-e883-4308-a87f-47a478f288e85http://www.infinitec.de/trackback.axd?id=8ac429f4-e883-4308-a87f-47a478f288e8http://www.infinitec.de/post/2011/10/05/Setting-the-Homepage-of-an-Exchange-folder-using-the-EWS-Managed-API.aspx#commenthttp://www.infinitec.de/syndication.axd?post=8ac429f4-e883-4308-a87f-47a478f288e8http://www.infinitec.de/post/2011/09/08/FindItems-Helper-method-for-the-Exchange-Managed-API.aspxFindItems Helper method for the Exchange Managed API2011-09-08T21:15:53+00:00hkrause<p>I’ve seen quite a few samples for using the <a href="http://msdn.microsoft.com/en-us/library/microsoft.exchange.webservices.data.exchangeservice.finditems(v=exchg.80).aspx">FindItems</a> method of the <a href="http://msdn.microsoft.com/en-us/library/dd633710(v=exchg.80).aspx">EWS Managed API</a>, either on <a href="http://stackoverflow.com/">StackOverflow</a> or in the <a href="http://social.technet.microsoft.com/Forums/en-US/exchangesvrdevelopment/threads/">Exchange development forum</a>. One of the most common error I see is that people disable paging by specifying creating an <a href="http://msdn.microsoft.com/en-us/library/microsoft.exchange.webservices.data.itemview(v=exchg.80).aspx">ItemView</a> like this:</p> <pre class="brush: csharp; auto-links: false;">var view = new ItemView(int.MaxValue);</pre>
<p>Don’t do that! A query using this ItemView will put a severe burden on the Exchange server if the folder being queried contains many items. The pageSize parameter is there for a reason.</p>
<p>Instead of querying all items at once, one should do a proper paging: Query, say, 512 items and process them. Then, query the next 512 items. Thanks to iterators in C#, the process of retrieving the items can be completely separated away from the processing.</p>
<p>If you are not familiar with C# iterators, have a look at this <a href="http://adventuresdotnet.blogspot.com/2010/06/understanding-cs-yield-keyword-and.html">article</a>. In essence, the yield operator allows for deferred execution, something you might heard from with regards to LINQ.</p>
<p>Here is a helper method which uses this technique to iterate over the contents of an Exchange folder, requesting 512 items per batch and returning them to the caller. When used properly, this method uses very little resources on the Exchange server as well as on the client. Additionally, it allows for querying the body of an item. In this case, instead of executing a FindItems request, it executes a FindItems request and a <a href="http://msdn.microsoft.com/en-us/library/microsoft.exchange.webservices.data.exchangeservice.loadpropertiesforitems(v=exchg.80).aspx">LoadPropertiesForItems</a> request per batch.</p>
<p>Due to the nature of the method, you should not put the items returned from the methods in a List, as this would consume a lot of memory on the client. Instead process the items one by one.</p>
<pre class="brush: csharp; auto-links: false;">public static class ExchangeServiceExtension
{
public static IEnumerable<Item> FindItems(this ExchangeService service, WellKnownFolderName folderName, PropertySet propertySet, SearchFilter searchFilter, ItemTraversal traversal = ItemTraversal.Shallow, params KeyValuePair<PropertyDefinition, SortDirection>[] orderBy)
{
return FindItems(service, new FolderId(folderName), propertySet, searchFilter, traversal, orderBy);
}
public static IEnumerable<Item> FindItems(this ExchangeService service, FolderId folderId, PropertySet propertySet, SearchFilter searchFilter = null, ItemTraversal traversal = ItemTraversal.Shallow, params KeyValuePair<PropertyDefinition, SortDirection>[] orderBy)
{
if (service == null) throw new ArgumentNullException("service");
if (folderId == null) throw new ArgumentNullException("folderId");
if (propertySet == null) throw new ArgumentNullException("propertySet");
PropertySet propertySetToQuery;
// If the body or unique body is requested, the FindItems method cannot be used to query the
// propertyset. Instead a GetItem operation is required. The propertyset IdOnly is used in this case
// for the FindItems operation.
if (propertySet.Contains(ItemSchema.Body) || propertySet.Contains(ItemSchema.UniqueBody))
{
propertySetToQuery = PropertySet.IdOnly;
}
else
{
propertySetToQuery = propertySet;
}
var itemView = new ItemView(512) { PropertySet = propertySetToQuery, Traversal = traversal };
if (orderBy != null)
{
foreach (var order in orderBy)
{
itemView.OrderBy.Add(order.Key, order.Value);
}
}
bool hasMoreItems;
do
{
var result = service.FindItems(folderId, searchFilter, itemView);
if (propertySetToQuery == PropertySet.IdOnly)
{
// Load the properties, including the body using a GetItem request.
service.LoadPropertiesForItems(result, propertySet);
}
foreach (var item in result)
{
yield return item;
}
hasMoreItems = result.MoreAvailable;
itemView.Offset += 512;
} while (hasMoreItems);
}
}</pre>
<p>As you can see, this method uses several .NET 4.0 features: Optional parameters and extension methods. So, if you are still using .NET 2.0, you’ll need to modify the code a little bit. </p>
<p>To use these methods, insert this code into your solution. In the class where you want to use the methods, add a using to the namespace containing the ExchangeServiceExtension. Both methods will then appear in the code completion window on instances of the <a href="http://msdn.microsoft.com/en-us/library/microsoft.exchange.webservices.data.exchangeservice(v=exchg.80).aspx">ExchangeService</a> class:</p>
<p><a href="http://www.infinitec.de/image.axd?picture=CodeCompletion.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="CodeCompletion" border="0" alt="CodeCompletion" src="http://www.infinitec.de/image.axd?picture=CodeCompletion_thumb.png" width="660" height="244" /></a></p>
<p>In the following example, the method is used to iterate over all items in the Inbox folder and printing the items to the console:</p>
<pre class="brush: csharp; auto-links: false;">var items = service.FindItems(WellKnownFolderName.Inbox, new PropertySet(BasePropertySet.IdOnly, ItemSchema.Subject));
foreach (var item in items)
{
Console.Out.WriteLine("Subject = {0}", item.Subject);
}</pre>
<p>Since the last parameters are optional, they can be omitted. This example adds a sort clause to the call:</p>
<pre class="brush: csharp; auto-links: false;">var items = service.FindItems(WellKnownFolderName.Inbox, new PropertySet(BasePropertySet.IdOnly, ItemSchema.Subject),
orderBy: new KeyValuePair<PropertyDefinition, SortDirection>(ItemSchema.Subject, SortDirection.Ascending));</pre>
<p>Of course, a <a href="http://msdn.microsoft.com/en-us/library/microsoft.exchange.webservices.data.searchfilter(v=exchg.80).aspx">SearchFilter</a> and an <a href="http://msdn.microsoft.com/en-us/library/microsoft.exchange.webservices.data.itemtraversal(v=exchg.80).aspx">ItemTraversal</a> can also be specified:</p>
<pre class="brush: csharp; auto-links: false;">var items = service.FindItems(WellKnownFolderName.Inbox, new PropertySet(BasePropertySet.IdOnly, ItemSchema.Subject),
new SearchFilter.ContainsSubstring(ItemSchema.Subject, "test"), ItemTraversal.Associated,
new KeyValuePair<PropertyDefinition, SortDirection>(ItemSchema.Subject, SortDirection.Ascending));</pre>2011-09-08T21:15:53+00:00hkrausehttp://www.infinitec.de/pingback.axdhttp://www.infinitec.de/post.aspx?id=3b503b7b-67d5-4ed3-8cc4-ac78257aed4412http://www.infinitec.de/trackback.axd?id=3b503b7b-67d5-4ed3-8cc4-ac78257aed44http://www.infinitec.de/post/2011/09/08/FindItems-Helper-method-for-the-Exchange-Managed-API.aspx#commenthttp://www.infinitec.de/syndication.axd?post=3b503b7b-67d5-4ed3-8cc4-ac78257aed44http://www.infinitec.de/post/2011/08/24/Exchange-WebService-ItemIds-are-case-sensitive.aspxExchange WebService ItemIds are case-sensitive2011-08-24T19:10:00+00:00hkrause<p>Every now and then people in the <a href="http://social.technet.microsoft.com/Forums/en-US/exchangesvrdevelopment/threads/">Exchange development forum</a> asks whether the <a href="http://msdn.microsoft.com/en-us/library/microsoft.exchange.webservices.data.itemid(v=exchg.80).aspx">ItemId</a> returned by a <a href="http://msdn.microsoft.com/en-us/library/dd634382(v=EXCHG.80).aspx">FindItems</a> call is unique or not, because they allegedly got duplicate ids for one folder. The short answer to this question is: Yes, ItemIds are unique. And you are seeing duplicate ids because you are probably performing an incase-sensitive comparison. </p> <p>Long answer:</p> <p>In the following example, I executed a FindItems call on one of my mailbox folders and got multiple of such “duplicates”. One example:</p> <p>AAMkAGY3OTBhZTFkLTAzNTgtNDM1Mi1hZjQ0LTg3YzUyOGRjM2I4NgBGAAAAAADssXJen7JoRp0FaJMBxQBjBwDTKvJ2qH1IS6bTjJryZwf0ACvTU4AKAADTKvJ2qH1IS6bTjJryZwf0ACvTWo5<font style="background-color: #ff0000" color="#ffffff"><strong>a</strong></font>AAA=</p> <p>AAMkAGY3OTBhZTFkLTAzNTgtNDM1Mi1hZjQ0LTg3YzUyOGRjM2I4NgBGAAAAAADssXJen7JoRp0FaJMBxQBjBwDTKvJ2qH1IS6bTjJryZwf0ACvTU4AKAADTKvJ2qH1IS6bTjJryZwf0ACvTWo5<font style="background-color: #ff0000" color="#ffffff"><strong>A</strong></font>AAA=</p> <p>These ids differ only in the 5th char from the right. The first one has a capital ‘A’ and the other has a small ‘a’ at that position. This can happen because the item id is <a href="http://en.wikipedia.org/wiki/Base64">base64</a> encoded. Base64 is way to represent binary data as ASCII text. A numerical value of 5 is encoded as a capital “F” and a value of 31 is also represented by an “f” - albeit a lower-case one. </p> <p>If you store an item id in a database (SQL Server for example) you’ll most likely have run into the problem that a select statement with a WHERE clause on the item id returns multiple hits. This is due to the fact that the SQL Server by default uses a incase-sensitive collation for columns. To change this, open the table in question with the designer, select the column containing the item id. The designer will then display the column properties, like in this example:</p> <p><a href="http://www.infinitec.de/image.axd?picture=Column%20Properties.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Column Properties" border="0" alt="Column Properties" src="http://www.infinitec.de/image.axd?picture=Column%20Properties_thumb.png" width="644" height="236" /></a></p> <p>Click on the Collation row and then on the button with the three full-stops. This will open the collation selection dialog:</p> <p><a href="http://www.infinitec.de/image.axd?picture=Collation%20Selection.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Collation Selection" border="0" alt="Collation Selection" src="http://www.infinitec.de/image.axd?picture=Collation%20Selection_thumb.png" width="367" height="498" /></a></p> <p>Ensure that the checkbox labeled “Case Sensitive” is checked. Click ok and then save the table.</p> <p>Note: If you do this via the SQL Server Management Studio, it will recreate the entire table (including data, indexes and constraints). Depending on the size of the table, this can take quite some time.</p> <p>Here is an SQL script which changes the column collation directly:</p> <pre class="brush: sql; auto-links: false;">ALTER TABLE Example
ALTER COLUMN ItemId VARCHAR(255)
COLLATE Latin1_General_CS_AS</pre>
<p>You need to adept the script to your environment. Albeit from the name of the table, you might have chosen a different data type for the ItemId column.</p>
<p>If you prefer not to change the table structure you can modify the query you are using to fetch the data from the database. Your query might now look like this:</p>
<pre class="brush: sql; auto-links: false;">SELECT * FROM Example
WHERE ItemId = 'AAMkAGY3OTBhZTFkLTAzNTgtNDM1Mi1hZjQ0LTg3YzUyOGRjM2I4NgBGAAAAAADssXJen7JoRp0FaJMBxQBjBwDTKvJ2qH1IS6bTjJryZwf0ACvTU4AKAADTKvJ2qH1IS6bTjJryZwf0ACvTWo5aAAA='</pre>
<p>Instead of this query, use this one:</p>
<pre class="brush: sql; auto-links: false;">SELECT * FROM Example
WHERE ItemId COLLATE Latin1_General_CS_AS = 'AAMkAGY3OTBhZTFkLTAzNTgtNDM1Mi1hZjQ0LTg3YzUyOGRjM2I4NgBGAAAAAADssXJen7JoRp0FaJMBxQBjBwDTKvJ2qH1IS6bTjJryZwf0ACvTU4AKAADTKvJ2qH1IS6bTjJryZwf0ACvTWo5aAAA='</pre>
<p>This select statement will perform a case-sensitive search on the table.</p>2011-08-24T19:10:00+00:00hkrausehttp://www.infinitec.de/pingback.axdhttp://www.infinitec.de/post.aspx?id=719eb5c3-a009-4a69-9231-1c2ed5318afb10http://www.infinitec.de/trackback.axd?id=719eb5c3-a009-4a69-9231-1c2ed5318afbhttp://www.infinitec.de/post/2011/08/24/Exchange-WebService-ItemIds-are-case-sensitive.aspx#commenthttp://www.infinitec.de/syndication.axd?post=719eb5c3-a009-4a69-9231-1c2ed5318afbhttp://www.infinitec.de/post/2011/08/09/Streaming-Subscription-Design-considerations.aspxStreaming Subscription - Design considerations2011-08-09T18:53:38+00:00hkrause<p>Commenter Mike had questions on some details of the <a href="http://msdn.microsoft.com/en-us/library/hh312849(EXCHG.140).aspx">article</a> I wrote about Exchange streaming notifications (See the comments in this <a href="http://www.infinitec.de/post/2011/07/15/Using-Streaming-Notifications-with-Exchange-2010.aspx#comment">blog post</a>). In the MSDN article, I wrote this:</p> <blockquote> <p>Streaming notifications do not work this way. Instead, you can use a combination of notifications and the <strong>ExchangeService.SyncFolderItems</strong> method. The <strong>SyncFolderItems</strong> method gives you a snapshot of the changes that occurred in a particular folder. This method also returns a small cookie that contains information about the synchronization state. You can pass this synchronization state to subsequent calls of the <strong>SyncFolderItems</strong> method to get all changes that have occurred since that synchronization cookie was first issued. You should persist this synchronization state somewhere (either on disk or in a database) so that the application does not need to process all of the items in the folder gain.</p> </blockquote> <p>I further outlined the steps an application should follow when using streaming subscriptions:</p> <blockquote> <ul> <li>After your application starts, use the <strong>SyncFolderItems</strong> method to process all unprocessed items in the folder. </li> <li>Create a streaming notification and connection as specified earlier in this article. </li> <li>Use the <strong>SyncFolderItems</strong> method again to process all events that occurred since the last synchronization and before the subscription was activated. </li> <li>On each <strong>OnNotification</strong> event, use the <strong>GetItem</strong> operation to get additional properties of the specified items. </li> <li>Call the <strong>SyncFolderItems</strong> method periodically to update the local synchronization cookie. </li> </ul> </blockquote> <p>This makes the application seemingly more complex than it needs to be because your application must be able to deal with different change notifications: Those from the streaming subscription and those from SyncFolderItems. Additionally, once a notification is received through the streaming subscription, the synchronization state from the last call to SyncFolderItems is stale. The application must now deal with the situation that the initial call of SyncFolderItems on an application restart might return changes which already have been processed by the application. The application needs to deal with this situation.</p> <p>Mike asks whether it’s ok to ignore the item ids specified in a notification and just use the SyncFolderItems method on each notification. Using this approach, the synchronization state returned by the SyncFolderItems method would always be current and the whole application design would be more simple.</p> <p>The answer is: It depends. If you have a low-volume application and your Exchange server is not used at full capacity, this might be ok. If you are writing an in-house application where you know everything about your infrastructure, this might be acceptable. But keep in mind that an application might run several years and the server load of your Exchange Server might go through the roof during the lifetime of your application. And if you are a software developer who sells his application to (hopefully) many customers, you don’t know anything about the performance situation on these servers. So it is best to conform to best practice and use the rules I outlined in the article.</p>2011-08-09T18:53:38+00:00hkrausehttp://www.infinitec.de/pingback.axdhttp://www.infinitec.de/post.aspx?id=b023a461-8272-479b-ab68-5822199d87883http://www.infinitec.de/trackback.axd?id=b023a461-8272-479b-ab68-5822199d8788http://www.infinitec.de/post/2011/08/09/Streaming-Subscription-Design-considerations.aspx#commenthttp://www.infinitec.de/syndication.axd?post=b023a461-8272-479b-ab68-5822199d8788http://www.infinitec.de/post/2011/08/01/Custom-Mail-headers-and-EWS.aspxCustom Mail headers and EWS2011-08-01T10:00:00+00:00hkrause<p>The mail headers are exposed on the <a href="http://msdn2.microsoft.com/en-us/dd635273">EmailMessage</a> as first class property: InternetMessageHeaders. However, Exchange also stores each mail header in its own property and defines a unique property set for it: PS_INTERNET_HEADERS.</p> <p>Here is a property definition for a hypothetical custom property:</p> <pre class="brush: csharp;">private static readonly ExtendedPropertyDefinition FrobProperty =
new ExtendedPropertyDefinition(DefaultExtendedPropertySet.InternetHeaders, "X-Frob", MapiPropertyType.String);</pre>
<p>If a mail is processed by Exchange with message header like this:</p>
<pre class="brush: plain; highlight: [2];">Subject: Test mail
X-Frob: Yes
From: "Henning Krause" <someone@infinitec.de>
To: "Someone <someone@example.local></pre>
<p>Exchange will parse the mail and set the value of the extended property defined above to “Yes”.</p>
<p>Retrieving the custom property is as simple as this:</p>
<pre class="brush: csharp;">var item = Item.Bind(service, itemId,
new PropertySet(BasePropertySet.FirstClassProperties, FrobProperty));</pre>
<p>The value of the property can then be accessed using this line:</p>
<pre class="brush: csharp;">string frobValue;
if (item.TryGetProperty(FrobProperty, out frobValue))
{
Console.Out.WriteLine("The item as a frob value of: {0}", frobValue);
}</pre>
<p>You can even search for messages which have the header “X-Frob” set to “Yes”:</p>
<pre class="brush: csharp;">var itemId = folder.FindItems(new SearchFilter.IsEqualTo(FrobProperty, "yes"),
new ItemView(10) {PropertySet = PropertySet.IdOnly});</pre>
<p>This query will return the first ten messages which have said header set to “Yes”.</p>
<p>Note that Exchange has a limit for named properties which are the result of custom mail headers. You may get one of these entries in your EventLog at some point:</p>
<blockquote>
<p>Event ID: 9666
<br />Type: Warning
<br />Category: General
<br />Source: msgidNamedPropsQuotaWarning
<br />Description: The number of named properties created for database "<<i>database name</i>>" is close to quota limit. Current number of named properties: <<i>number of named properties</i>>. Quota limit for named properties: <<i>configured quota</i>>. User attempting to create the named property: <<i>user name</i>>. Named property GUID: <<i>GUID of named property</i>>. Named property name/id: <<i>name of named property</i>>.</p>
</blockquote>
<p> </p>
<blockquote>
<p>Event ID: 9667
<br />Type: Error
<br />Category: General
<br />Source: msgidNamedPropsQuotaError
<br />Description: Failed to create a new named property for database "<<i>database name</i>>" because the number of named properties reached the quota limit (<<i>configured quota</i>>). User attempting to create the named property: <<i>user name</i>>. Named property GUID: <<i>GUID of named property</i>>. Named property name/id: <<i>name of named property</i>>.</p>
</blockquote>
<p> </p>
<p>See this blog post on how to deal with this issue: <a title="http://blogs.technet.com/b/exchange/archive/2010/07/29/3410545.aspx" href="http://blogs.technet.com/b/exchange/archive/2010/07/29/3410545.aspx">http://blogs.technet.com/b/exchange/archive/2010/07/29/3410545.aspx</a>.</p>2011-08-01T10:00:00+00:00hkrausehttp://www.infinitec.de/pingback.axdhttp://www.infinitec.de/post.aspx?id=d512c9ee-5297-43bb-9109-b57a195503c72http://www.infinitec.de/trackback.axd?id=d512c9ee-5297-43bb-9109-b57a195503c7http://www.infinitec.de/post/2011/08/01/Custom-Mail-headers-and-EWS.aspx#commenthttp://www.infinitec.de/syndication.axd?post=d512c9ee-5297-43bb-9109-b57a195503c7http://www.infinitec.de/post/2011/07/28/Working-with-the-Master-Category-List–EWS-edition.aspxWorking with the Master Category List–EWS edition2011-07-28T14:00:00+00:00hkrause<p>Back in 2008 I wrote an article about <a href="http://www.infinitec.de/post/2008/05/22/Working-with-the-MasterCategoryList-Via-WebDAV.aspx">accessing the Master Category List using WebDAV</a>. If you are not sure what the Master Category List is, read that article first…</p> <p>EWS could not be used at that time, since access to the Folder Associated Items via EWS is a Feature of Exchange 2010. So if you are on Exchange 2007, the old article still applies.</p> <p>The last article contained some code which simplified updating the list. I’ve updated the code and aligned the method naming with that of the EWS managed API.</p> <p>This is the class diagram for the updated code:</p> <p><a href="http://www.infinitec.de/image.axd?picture=ClassDiagram.png"><img title="ClassDiagram" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="ClassDiagram" src="http://www.infinitec.de/image.axd?picture=ClassDiagram_thumb.png" width="763" height="568" /></a></p> <p>The classes are really easy to use:</p> <pre class="brush: csharp; auto-links: false; highlight: [4];">var service = new ExchangeService(ExchangeVersion.Exchange2010_SP1) { Credentials = new NetworkCredential("someone@infinitec.de", "password") };
service.AutodiscoverUrl("someone@infinitec.de", url => true);
var list = MasterCategoryList.Bind(service);
foreach (var category in list.Categories)
{
Console.Out.WriteLine("category = {0}", category.Name);
}</pre>
<p>The only interesting line in the sample above is line 4. The call to MasterCategoryList.Bind() loads the MasterCategoryList from the users Exchange Mailbox. After that, the name of each console is written to the console.</p>
<p>Adding a new category is equally simple:</p>
<pre class="brush: csharp; auto-links: false;">var service = new ExchangeService(ExchangeVersion.Exchange2010_SP1) { Credentials = new NetworkCredential("someone@infinitec.de", "password") };
service.AutodiscoverUrl("someone@infinitec.de", url => true);
var list = MasterCategoryList.Bind(service);
list.Categories.Add(new Category("Vacation", CategoryColor.DarkMaroon, CategoryKeyboardShortcut.CtrlF10));
list.Update();</pre>
<p>This will add a new category named “Vacation” to the list.</p>
<p>So how does this work? The Master Category List is stored in a hidden message in the calendar folder of a mailbox. EWS in 2010 provides simple access to this message with the <a href="http://msdn2.microsoft.com/en-us/dd635344">UserConfiguration</a> class. This code show how the Master Category List is loaded:</p>
<pre class="brush: csharp; auto-links: false;">var item = UserConfiguration.Bind(service, "CategoryList", WellKnownFolderName.Calendar,
UserConfigurationProperties.XmlData);
var reader = new StreamReader(new MemoryStream(item.XmlData), Encoding.UTF8, true);</pre>
<p>The configuration data is stored in the XmlData property as UTF-8 encoded byte array. </p>
<p>Here is the new code:</p>
<div id="scid:fb3a1972-4489-4e52-abe7-25a00bb07fdf:ba5aeb4a-a891-4599-823b-6c51072cadf0" class="wlWriterEditableSmartContent" style="float: none; padding-bottom: 0px; padding-top: 0px; padding-left: 0px; margin: 0px; display: inline; padding-right: 0px"><p>Sourcecode <a href="http://www.infinitec.de/file.axd?file=MasterCategoryList_1.zip" target="_blank">Download</a></p></div>2011-07-28T14:00:00+00:00hkrausehttp://www.infinitec.de/pingback.axdhttp://www.infinitec.de/post.aspx?id=3fff28fd-88aa-44a7-9eda-d1fe3673818a5http://www.infinitec.de/trackback.axd?id=3fff28fd-88aa-44a7-9eda-d1fe3673818ahttp://www.infinitec.de/post/2011/07/28/Working-with-the-Master-Category-List–EWS-edition.aspx#commenthttp://www.infinitec.de/syndication.axd?post=3fff28fd-88aa-44a7-9eda-d1fe3673818ahttp://www.infinitec.de/post/2011/07/25/How-to-get-the-number-of-unread-mails-from-multiple-mailboxes-using-the-EWS-Managed-API-and-PowerShell.aspxHow to get the number of unread mails from multiple mailboxes using the EWS Managed API and PowerShell2011-07-25T17:56:03+00:00hkrause<p>Interesting question in the <a href="http://social.technet.microsoft.com/Forums/en-US/exchangesvrdevelopment/thread/d9e9d54a-b2f3-4184-ad69-469fa8035f1d">Exchange development forum</a> today: How do I get the number of unread messages in the inbox folder from a number of mailboxes? The questioner wants to send a text message to each owner of a mailbox notifying him of the number of unread mails in his inbox. The requirement was to do this with PowerShell. So, here is a quick solution for this problem:</p> <pre class="brush: ps; auto-links: false;">param ([string] $inputFile, [System.Management.Automation.PSCredential] $credential)
$ErrorActionPreference = "Stop"
if (($inputFile -eq [String]::Empty) -or (Test-Path $inputFile) -eq $false)
{
throw "Invalid file specified ({0})." -f $inputFile
}
[Reflection.Assembly]::LoadFrom("C:\Program Files\Microsoft\Exchange\Web Services\1.1\Microsoft.Exchange.WebServices.dll")
$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService -ArgumentList([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP1)
if ($credential -ne $null)
{
$service.Credentials = $credential.GetNetworkCredential()
}
else
{
$service.UseDefaultCredentials = $true;
}
function GetUnreadInboxMails([string] $emailAddress)
{
$service.AutodiscoverUrl($emailAddress, {$true});
$maibox = New-Object Microsoft.Exchange.WebServices.Data.Mailbox($emailAddress)
$folderId = New-Object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox, $mailbox)
$folder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service, $folderId);
$result = New-Object PSObject -Property @{
EmailAddress = $emailAddress
UnreadMailCount= $folder.UnreadCount;
}
return $result;
}
function ProcessResult($entry)
{
"Mailbox: {0}" -f $entry.EmailAddress
"Unread Mails: {0}" -f $entry.UnreadMailCount
"==============================================================================="
}
$addresses = Import-Csv $inputFile
$addresses | % {GetUnreadInboxMails($_.MailAddress)} | % {ProcessResult ($_)} </pre>
<p>Just paste this script into an editor and save it as ps1 file. </p>
<p>The script mainly consists of two function: GetUnreadInboxMails and ProcessResult. The former method retrieves the number of unread mails in the inbox of the mailbox of the specified user. The number of unread mails can be retrieved from a <a href="http://msdn2.microsoft.com/en-us/dd633809">Folder</a> instance: The UnreadCount property. The method returns the number of unread mails along with the mail address of the current mailbox. The other important function is the ProcessResult method. In this script it merely dumps the result to the console. The questioner in the post linked above can use this function to call his HTTP service to send a text message.</p>
<p>The script has two parameters:</p>
<ol>
<li>The name of a CSV file containing the list of mailboxes to process. The first line should contain the column name “MailAddress” somewhere. The following lines should contain the email address of the mailbox in this column.</li>
<li>A PSCredential object containing valid credentials to use for the Exchange access.</li>
</ol>
<p>The credential used for the script needs read access to the inbox folder of each mailbox specified in the file.</p>2011-07-25T17:56:03+00:00hkrausehttp://www.infinitec.de/pingback.axdhttp://www.infinitec.de/post.aspx?id=fa18b2b9-eacb-44e2-b590-e200b2e98e7f16http://www.infinitec.de/trackback.axd?id=fa18b2b9-eacb-44e2-b590-e200b2e98e7fhttp://www.infinitec.de/post/2011/07/25/How-to-get-the-number-of-unread-mails-from-multiple-mailboxes-using-the-EWS-Managed-API-and-PowerShell.aspx#commenthttp://www.infinitec.de/syndication.axd?post=fa18b2b9-eacb-44e2-b590-e200b2e98e7fhttp://www.infinitec.de/post/2011/07/22/Exchange-Managed-API-autodiscover-with-Powershell.aspxExchange Managed API autodiscover with Powershell2011-07-22T15:30:31+00:00hkrause<p>Powershell is a great tool to automate all sorts of things – including fiddling around with your Exchange mailbox. And the Autodiscover makes it really easy to connect to it – especially if you’re on Office 365 and don’t even know your CAS server. </p> <p>So first, we need to load the EWS Managed API dll into the current runspace:</p> <pre class="brush: powershell;">[Reflection.Assembly]::LoadFrom("C:\Program Files\Microsoft\Exchange\Web Services\1.1\Microsoft.Exchange.WebServices.dll")</pre>
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
<p>Then, create an ExchangeService instance and set its credentials:</p>
<pre class="brush: powershell;">$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService -ArgumentList([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP1)
$service.Credentials = New-Object System.Net.NetworkCredential("someone@infinitec.de", "password", "domain");</pre>
<p>Now we are ready to use AutoDiscover. But depending on your infrastructure, AutoDiscover might need to follow some redirections before it has discovered your CAS Server. Like in this case:</p>
<pre class="brush: powershell;">$service.AutodiscoverUrl("someone@infinitec.de");</pre>
<p><font color="#ff0000">Exception calling "AutodiscoverUrl" with "1" argument(s): "Autodiscover blocked a potentially insecure redirection to </font><a href="https://autodiscover-s.outlook.com/autodiscover/autodiscover.xml"><font color="#ff0000">https://autodiscover-s.outlook.com/autodiscover/autodiscover.xml</font></a><font color="#ff0000">. To allow Autodiscover to follow the redirection, use the AutodiscoverUrl(string, AutodiscoverRedirectionUrlValidationCallback) overload."
<br />At line:1 char:25
<br />+ $service.AutodiscoverUrl <<<< ("hkrause@infinitec.de");
<br />    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
<br />    + FullyQualifiedErrorId : DotNetMethodException</font></p>
<p><font color="#000000">This happens because the AutoDiscover process looks at autodiscover.infinitec.de and instead of an A record pointing to the AutoDiscover service, it finds a CNAME redirecting it to autodiscover.outlook.com. Because this might pose a security risk, the AutoDiscoverUrl method aborts  the discovery process and throws the Exception displayed above. The solution is also outlined: Instead of calling the method AutoDiscoverUrl(mailAddress) call the overload which expects a delegate as a second paramter. This delegate has a string as input and returns the $true if the discovery process should follow the redirection; false otherwise.</font></p>
<p>How can this overload be used with PowerShell? The answer is a ScriptBlock. If you simply want to allow the discovery process to follow all redirects, simply call it this way:</p>
<pre class="brush: powershell;">$service.AutodiscoverUrl("someone@infinitec.de", {$true})</pre>
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
<p>But if you want to verify the discovery process is redirected to the correct url, use this version:</p>
<pre class="brush: powershell;">$TestUrlCallback = {
param ([string] $url)
if ($url -eq "https://autodiscover-s.outlook.com/autodiscover/autodiscover.xml") {$true} else {$false}
}
$service.AutodiscoverUrl("someone@infinitec.de", $TestUrlCallback)</pre>
<p>You can embed whatever checks you need to verify the given url in the third line of the $TestUrlCallback method.<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style></p>2011-07-22T15:30:31+00:00hkrausehttp://www.infinitec.de/pingback.axdhttp://www.infinitec.de/post.aspx?id=3cf51106-6adc-499a-b002-6f8be062d16c2http://www.infinitec.de/trackback.axd?id=3cf51106-6adc-499a-b002-6f8be062d16chttp://www.infinitec.de/post/2011/07/22/Exchange-Managed-API-autodiscover-with-Powershell.aspx#commenthttp://www.infinitec.de/syndication.axd?post=3cf51106-6adc-499a-b002-6f8be062d16chttp://www.infinitec.de/post/2011/07/18/Replying-with-attachments-to-an-email-message-with-EWS.aspxReplying with attachments to an email message with EWS2011-07-18T18:04:48+00:00hkrause<p>The EWS Managed API makes some tasks really easy – like replying to an existing email. Given the unique id of an item, this can be done this way:</p> <pre class="brush: csharp;">var message = (EmailMessage) Item.Bind(service, new ItemId(uniqueId), PropertySet.FirstClassProperties);
var reply = message.CreateReply(false);
reply.BodyPrefix = "Response text goes here";
reply.SendAndSaveCopy();</pre>
<p>But what if you want to send an attachment along with the reply? This is tricky, because the the instance created by the <a href="http://msdn.microsoft.com/en-us/microsoft.exchange.webservices.data.emailmessage.createreply">EmailMessage.CreateReply()</a> method is of type <a href="http://msdn2.microsoft.com/en-us/dd636024">ResponseMessage</a>. Since its not an <a href="http://msdn2.microsoft.com/en-us/dd635273">EmailMessage</a> instance, it does not have an Attachment property. To add an attachment to this reply, it needs to be saved first. The Save method returns an EmailMessage instance. Attachments can be added to this message. Finally, the message can be sent to its destination.</p>
<pre class="brush: csharp;">var message = (EmailMessage) Item.Bind(service, new ItemId(uniqueId), PropertySet.FirstClassProperties);
var reply = message.CreateReply(false);
reply.BodyPrefix = "Response text goes here";
var replyMessage = reply.Save(WellKnownFolderName.Drafts);
replyMessage.Attachments.AddFileAttachment("d:\\inbox\\test.pdf");
replyMessage.Update(ConflictResolutionMode.AlwaysOverwrite);
replyMessage.SendAndSaveCopy();</pre>2011-07-18T18:04:48+00:00hkrausehttp://www.infinitec.de/pingback.axdhttp://www.infinitec.de/post.aspx?id=1a7cba55-670f-4189-8f43-13d4f453753c2http://www.infinitec.de/trackback.axd?id=1a7cba55-670f-4189-8f43-13d4f453753chttp://www.infinitec.de/post/2011/07/18/Replying-with-attachments-to-an-email-message-with-EWS.aspx#commenthttp://www.infinitec.de/syndication.axd?post=1a7cba55-670f-4189-8f43-13d4f453753chttp://www.infinitec.de/post/2011/07/15/Using-Streaming-Notifications-with-Exchange-2010.aspxUsing Streaming Notifications with Exchange 20102011-07-15T17:50:31+00:00hkrause<p>That is the title of an article I wrote for Microsoft. It has been published <a title="http://msdn.microsoft.com/en-us/library/hh312849(EXCHG.140).aspx" href="http://msdn.microsoft.com/en-us/library/hh312849(EXCHG.140).aspx">here</a> a few days ago:</p> <blockquote> <p>Summary: Streaming notifications, which combine the functionalities of push and pull notifications, are new in Microsoft Exchange Server 2010 Service Pack 1 (SP1). This article explains how streaming notifications work and when to use them.</p> </blockquote> <p>The code sample is missing, but that will be fixed in a few days.</p>2011-07-15T17:50:31+00:00hkrausehttp://www.infinitec.de/pingback.axdhttp://www.infinitec.de/post.aspx?id=c78ae3da-7550-4f0d-b2a3-bbb5f81bd66214http://www.infinitec.de/trackback.axd?id=c78ae3da-7550-4f0d-b2a3-bbb5f81bd662http://www.infinitec.de/post/2011/07/15/Using-Streaming-Notifications-with-Exchange-2010.aspx#commenthttp://www.infinitec.de/syndication.axd?post=c78ae3da-7550-4f0d-b2a3-bbb5f81bd662http://www.infinitec.de/post/2011/07/13/Enumerating-Sharepoint-Connections-in-a-mailbox-with-EWS.aspxEnumerating Sharepoint Connections in a mailbox with EWS2011-07-13T19:05:26+00:00hkrause<p>An interesting question on <a href="http://stackoverflow.com/questions/6529546/is-it-possible-to-programmatically-retrieve-the-sharepoint-contact-lists-that-a-u/6671181">StackOverflow</a> came up recently: Is it possible to get the SharePoint lists which are connected to an Exchange Mailbox? The data which is synchronized with Outlook is stored in a PST file on the local disk – so no interaction with Exchange on this end. But if a user logs on from another computer, the SharePoint list the user has subscribed to are synchronized there as well. So the configuration seems to be stored in the mailbox somewhere. And indeed, they are. Outlook creates a message item in the associated folder table in the users inbox. Associated items are not visible from Outlook, but they can be accessed using MAPI or EWS. It turns out that Outlook saves the SharePoint connections similar to the RSS feeds. So a good starting point is to have a look at the <a href="http://msdn.microsoft.com/en-us/library/cc433485(v=EXCHG.80).aspx">Sharing Message Object Protocol Specification</a> which lists the properties used for these items. </p> <p>The SharePoint configuration items have a MessageClass of <strong>IPM.Sharing.Index.In</strong>, and the property PidLidSharingProviderGuidProperty is set to <strong>{0006F0AD-0000-0000-C000-000000000046}</strong>.</p> <p>The configuration data is stored on a few properties. The following method lists all SharePoint connections connected to a mailbox:</p> <div class="csharpcode"> <pre><span class="lnum"> 1: </span><span class="kwrd">using</span> System;</pre>
<pre><span class="lnum"> 2: </span><span class="kwrd">using</span> System.Net;</pre>
<pre><span class="lnum"> 3: </span><span class="kwrd">using</span> Microsoft.Exchange.WebServices.Data;</pre>
<pre><span class="lnum"> 4: </span> </pre>
<pre><span class="lnum"> 5: </span><span class="kwrd">namespace</span> ExchangeTest</pre>
<pre><span class="lnum"> 6: </span>{</pre>
<pre><span class="lnum"> 7: </span> <span class="kwrd">internal</span> <span class="kwrd">class</span> Program</pre>
<pre><span class="lnum"> 8: </span> {</pre>
<pre><span class="lnum"> 9: </span> <span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">readonly</span> Guid PropertySetSharing = <span class="kwrd">new</span> Guid(<span class="str">"{00062040-0000-0000-C000-000000000046}"</span>);</pre>
<pre><span class="lnum"> 10: </span> </pre>
<pre><span class="lnum"> 11: </span> <span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">readonly</span> ExtendedPropertyDefinition PidLidSharingProviderGuidProperty =</pre>
<pre><span class="lnum"> 12: </span> <span class="kwrd">new</span> ExtendedPropertyDefinition(PropertySetSharing, 0x8A01, MapiPropertyType.CLSID);</pre>
<pre><span class="lnum"> 13: </span> </pre>
<pre><span class="lnum"> 14: </span> <span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">readonly</span> ExtendedPropertyDefinition SharingRemotePathProperty =</pre>
<pre><span class="lnum"> 15: </span> <span class="kwrd">new</span> ExtendedPropertyDefinition(PropertySetSharing, 0x8A04, MapiPropertyType.String);</pre>
<pre><span class="lnum"> 16: </span> </pre>
<pre><span class="lnum"> 17: </span> <span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">readonly</span> ExtendedPropertyDefinition SharingLocalNameProperty =</pre>
<pre><span class="lnum"> 18: </span> <span class="kwrd">new</span> ExtendedPropertyDefinition(PropertySetSharing, 0x8A0F, MapiPropertyType.String);</pre>
<pre><span class="lnum"> 19: </span> </pre>
<pre><span class="lnum"> 20: </span> <span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">readonly</span> ExtendedPropertyDefinition SharingRemoteNameProperty =</pre>
<pre><span class="lnum"> 21: </span> <span class="kwrd">new</span> ExtendedPropertyDefinition(PropertySetSharing, 0x8A05, MapiPropertyType.String);</pre>
<pre><span class="lnum"> 22: </span> </pre>
<pre><span class="lnum"> 23: </span> <span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">readonly</span> ExtendedPropertyDefinition SharingBrowseUrlProperty =</pre>
<pre><span class="lnum"> 24: </span> <span class="kwrd">new</span> ExtendedPropertyDefinition(PropertySetSharing, 0x8A51, MapiPropertyType.String);</pre>
<pre><span class="lnum"> 25: </span> </pre>
<pre><span class="lnum"> 26: </span> <span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">readonly</span> ExtendedPropertyDefinition SharingRemoteTypeProperty =</pre>
<pre><span class="lnum"> 27: </span> <span class="kwrd">new</span> ExtendedPropertyDefinition(PropertySetSharing, 0x8A1D, MapiPropertyType.String);</pre>
<pre><span class="lnum"> 28: </span> </pre>
<pre><span class="lnum"> 29: </span> <span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">readonly</span> Guid SharePointProviderId = <span class="kwrd">new</span> Guid(<span class="str">"{0006F0AD-0000-0000-C000-000000000046}"</span>);</pre>
<pre><span class="lnum"> 30: </span> </pre>
<pre><span class="lnum"> 31: </span> <span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">void</span> Main(<span class="kwrd">string</span>[] args)</pre>
<pre><span class="lnum"> 32: </span> {</pre>
<pre><span class="lnum"> 33: </span> var service = <span class="kwrd">new</span> ExchangeService(ExchangeVersion.Exchange2010)</pre>
<pre><span class="lnum"> 34: </span> {Credentials = <span class="kwrd">new</span> NetworkCredential(<span class="str"><a href="mailto:test@contoso.com">test@contoso.com</a></span>, <span class="str">"Password!"</span>)};</pre>
<pre><span class="lnum"> 35: </span> </pre>
<pre><span class="lnum"> 36: </span> service.AutodiscoverUrl(<span class="str"><a href="mailto:test@contoso.com">test@contoso.com</a></span>, url => <span class="kwrd">true</span>);</pre>
<pre><span class="lnum"> 37: </span> </pre>
<pre><span class="lnum"> 38: </span> var folder = Folder.Bind(service, WellKnownFolderName.Inbox);</pre>
<pre><span class="lnum"> 39: </span> var filter = <span class="kwrd">new</span> SearchFilter.SearchFilterCollection(LogicalOperator.And,</pre>
<pre><span class="lnum"> 40: </span> <span class="kwrd">new</span> SearchFilter.IsEqualTo(ItemSchema.ItemClass,</pre>
<pre><span class="lnum"> 41: </span> <span class="str">"IPM.Sharing.Index.In"</span>),</pre>
<pre><span class="lnum"> 42: </span> <span class="kwrd">new</span> SearchFilter.IsEqualTo(PidLidSharingProviderGuidProperty,</pre>
<pre><span class="lnum"> 43: </span> SharePointProviderId.ToString()));</pre>
<pre><span class="lnum"> 44: </span> var view = <span class="kwrd">new</span> ItemView(512)</pre>
<pre><span class="lnum"> 45: </span> {</pre>
<pre><span class="lnum"> 46: </span> Traversal = ItemTraversal.Associated,</pre>
<pre><span class="lnum"> 47: </span> PropertySet = <span class="kwrd">new</span> PropertySet(BasePropertySet.IdOnly,</pre>
<pre><span class="lnum"> 48: </span> SharingRemotePathProperty, SharingBrowseUrlProperty,</pre>
<pre><span class="lnum"> 49: </span> SharingLocalNameProperty, SharingRemoteNameProperty,</pre>
<pre><span class="lnum"> 50: </span> SharingRemoteTypeProperty)</pre>
<pre><span class="lnum"> 51: </span> };</pre>
<pre><span class="lnum"> 52: </span> </pre>
<pre><span class="lnum"> 53: </span> var items = folder.FindItems(filter, view);</pre>
<pre><span class="lnum"> 54: </span> <span class="kwrd">foreach</span> (var item <span class="kwrd">in</span> items)</pre>
<pre><span class="lnum"> 55: </span> {</pre>
<pre><span class="lnum"> 56: </span> Console.Out.WriteLine(<span class="str">"RemotePath = {0}"</span>, item.GetValueOrDefault<<span class="kwrd">string</span>>(SharingRemotePathProperty));</pre>
<pre><span class="lnum"> 57: </span> Console.Out.WriteLine(<span class="str">"BrowseUrl = {0}"</span>, item.GetValueOrDefault<<span class="kwrd">string</span>>(SharingBrowseUrlProperty));</pre>
<pre><span class="lnum"> 58: </span> Console.Out.WriteLine(<span class="str">"LocalName = {0}"</span>, item.GetValueOrDefault<<span class="kwrd">string</span>>(SharingLocalNameProperty));</pre>
<pre><span class="lnum"> 59: </span> Console.Out.WriteLine(<span class="str">"Remotename = {0}"</span>, item.GetValueOrDefault<<span class="kwrd">string</span>>(SharingLocalNameProperty));</pre>
<pre><span class="lnum"> 60: </span> Console.Out.WriteLine(<span class="str">"Type = {0}"</span>, item.GetValueOrDefault<<span class="kwrd">string</span>>(SharingRemoteTypeProperty));</pre>
<pre><span class="lnum"> 61: </span> Console.Out.WriteLine(<span class="kwrd">new</span> <span class="kwrd">string</span>(<span class="str">'='</span>, 80));</pre>
<pre><span class="lnum"> 62: </span> }</pre>
<pre><span class="lnum"> 63: </span> }</pre>
<pre><span class="lnum"> 64: </span> }</pre>
<pre><span class="lnum"> 65: </span> </pre>
<pre><span class="lnum"> 66: </span> <span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">class</span> ItemExtension</pre>
<pre><span class="lnum"> 67: </span> {</pre>
<pre><span class="lnum"> 68: </span> <span class="kwrd">public</span> <span class="kwrd">static</span> T GetValueOrDefault<T>(<span class="kwrd">this</span> Item item, PropertyDefinitionBase property, T defaultValue = <span class="kwrd">default</span>(T))</pre>
<pre><span class="lnum"> 69: </span> {</pre>
<pre><span class="lnum"> 70: </span> T result;</pre>
<pre><span class="lnum"> 71: </span> <span class="kwrd">return</span> item.TryGetProperty(property, <span class="kwrd">out</span> result) ? result : defaultValue;</pre>
<pre><span class="lnum"> 72: </span> }</pre>
<pre><span class="lnum"> 73: </span> }</pre>
<pre><span class="lnum"> 74: }</span></pre>
</div>
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
<p>This method dumps the configuration of all SharePoint connections to the console.</p>
<p>To use this method, you’ll need .NET 4. If you are running .NET 2.0, you’ll have to adapt it.</p>
<p>Additionally, this won't work with Exchange 2007, because EWS in that version does not allow a FindItems call on the associated items table. WebDAV is the API of choice in this case.</p>2011-07-13T19:05:26+00:00hkrausehttp://www.infinitec.de/pingback.axdhttp://www.infinitec.de/post.aspx?id=64ee7c12-8bd7-42a8-bfb8-63efb729b0d53http://www.infinitec.de/trackback.axd?id=64ee7c12-8bd7-42a8-bfb8-63efb729b0d5http://www.infinitec.de/post/2011/07/13/Enumerating-Sharepoint-Connections-in-a-mailbox-with-EWS.aspx#commenthttp://www.infinitec.de/syndication.axd?post=64ee7c12-8bd7-42a8-bfb8-63efb729b0d5http://www.infinitec.de/post/2011/06/27/Correlating-a-Non-Delivery-Notification-to-its-original-message-with-the-Exchange-Managed-API.aspxCorrelating a Non-Delivery-Notification to its original message with the Exchange Managed API2011-06-27T18:12:31+00:00hkrause<p>If you are automatically process emails in an Exchange Mailbox, you might also need to process non delivery reports (NDRs) and correlate these NDRs to their original values. Luckily, Exchange does most of the heavy lifting, as long as the NDR conforms to the <a href="http://tools.ietf.org/html/rfc3461">RFC 3461</a>, which defines the proper structure for an NDR that can be automatically parsed. Not all MTAs (Mail transfer agents) do generate these types of NDRs.</p> <p>First of all, you need to check whether the mail item in question is actually a non delivery report. This is done by examining the Item Class of the mail. An NDR has an item class of REPORT.IPM.Note.NDR. Next, you need to retrieve the property <a title="http://msdn.microsoft.com/en-us/library/ee160861(v=exchg.80).aspx" href="http://msdn.microsoft.com/en-us/library/ee160861(v=exchg.80).aspx">PidTagParentKey</a> from the item. This property contains the <a href="http://msdn.microsoft.com/en-us/library/cc815908.aspx">PidTagSearchKey</a> of the original mail. </p> <p>Unfortunately, the PidTagSearchKey cannot be used to bind to the item directly. Instead, you have to issue a FindItem operation to get it. Normally, sent items are all stored in the SentItems folder, so this narrows the search down.</p> <p>Here is a sample method which describes the process:</p> <p> </p> <div class="csharpcode"> <pre><span class="lnum"> 1: </span><span class="kwrd">class</span> Program</pre>
<pre><span class="lnum"> 2: </span>{</pre>
<pre><span class="lnum"> 3: </span> <span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">readonly</span> ExtendedPropertyDefinition PidTagParentKeyProperty = <span class="kwrd">new</span> ExtendedPropertyDefinition(0x25, MapiPropertyType.Binary);</pre>
<pre><span class="lnum"> 4: </span> <span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">readonly</span> ExtendedPropertyDefinition PidTagSeachKeyProperty = <span class="kwrd">new</span> ExtendedPropertyDefinition(0x300B, MapiPropertyType.Binary);</pre>
<pre><span class="lnum"> 5: </span> </pre>
<pre><span class="lnum"> 6: </span> </pre>
<pre><span class="lnum"> 7: </span> <span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">bool</span> TryGetOriginalMail(<span class="kwrd">string</span> ndrId, ExchangeService service, <span class="kwrd">out</span> Item originalItem)</pre>
<pre><span class="lnum"> 8: </span> {</pre>
<pre><span class="lnum"> 9: </span> <span class="kwrd">byte</span>[] <span class="kwrd">value</span>;</pre>
<pre><span class="lnum"> 10: </span> </pre>
<pre><span class="lnum"> 11: </span> var item = service.BindToItems(<span class="kwrd">new</span>[] {<span class="kwrd">new</span> ItemId(ndrId)},</pre>
<pre><span class="lnum"> 12: </span> <span class="kwrd">new</span> PropertySet(BasePropertySet.IdOnly,</pre>
<pre><span class="lnum"> 13: </span> PidTagParentKeyProperty, ItemSchema.Subject)).First().Item;</pre>
<pre><span class="lnum"> 14: </span> </pre>
<pre><span class="lnum"> 15: </span> <span class="kwrd">if</span> (!item.TryGetProperty(PidTagParentKeyProperty, <span class="kwrd">out</span> <span class="kwrd">value</span>))</pre>
<pre><span class="lnum"> 16: </span> {</pre>
<pre><span class="lnum"> 17: </span> Console.Out.WriteLine(<span class="str">"Correlationtoken not found."</span>);</pre>
<pre><span class="lnum"> 18: </span> originalItem = <span class="kwrd">null</span>;</pre>
<pre><span class="lnum"> 19: </span> <span class="kwrd">return</span> <span class="kwrd">false</span>;</pre>
<pre><span class="lnum"> 20: </span> }</pre>
<pre><span class="lnum"> 21: </span> </pre>
<pre><span class="lnum"> 22: </span> originalItem = service</pre>
<pre><span class="lnum"> 23: </span> .FindItems(WellKnownFolderName.SentItems,</pre>
<pre><span class="lnum"> 24: </span> <span class="kwrd">new</span> SearchFilter.IsEqualTo(PidTagSeachKeyProperty, Convert.ToBase64String(<span class="kwrd">value</span>)),</pre>
<pre><span class="lnum"> 25: </span> <span class="kwrd">new</span> ItemView(1) {PropertySet = PropertySet.FirstClassProperties})</pre>
<pre><span class="lnum"> 26: </span> .FirstOrDefault();</pre>
<pre><span class="lnum"> 27: </span> </pre>
<pre><span class="lnum"> 28: </span> <span class="kwrd">return</span> <span class="kwrd">true</span>;</pre>
<pre><span class="lnum"> 29: </span> }</pre>
<pre><span class="lnum"> 30: </span>}</pre>
</div>
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>2011-06-27T18:12:31+00:00hkrausehttp://www.infinitec.de/pingback.axdhttp://www.infinitec.de/post.aspx?id=b767c458-58e1-4aa5-8dd5-8df6b0a652eb8http://www.infinitec.de/trackback.axd?id=b767c458-58e1-4aa5-8dd5-8df6b0a652ebhttp://www.infinitec.de/post/2011/06/27/Correlating-a-Non-Delivery-Notification-to-its-original-message-with-the-Exchange-Managed-API.aspx#commenthttp://www.infinitec.de/syndication.axd?post=b767c458-58e1-4aa5-8dd5-8df6b0a652ebhttp://www.infinitec.de/post/2009/06/09/Getting-the-body-of-an-Email-with-a-FindItems-request.aspxGetting the body of an Email with a FindItems request2009-06-09T19:00:31+00:00hkrause<p>The <a href="http://msdn.microsoft.com/library/aa566107.aspx">FindItem</a> operation (or the corresponding ExchangeService.FindItems method) does not return the body of an email by default. And when trying to explicitly request them via a custom propertyset, the call fails. Consider this method, which uses the EWS Managed API to execute a FindItems method to get every message from the inbox folder of a mailbox, fetching only the item id and the body:</p> <div id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> <span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> GetAllItems(ExchangeService exchangeService)</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> {</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3"> 3:</span> var offset = 0;</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4"> 4:</span> <span style="color: #0000ff">const</span> <span style="color: #0000ff">int</span> pageSize = 100;</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5"> 5:</span>  </pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6"> 6:</span> FindItemsResults<Item> result;</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7"> 7:</span> <span style="color: #0000ff">do</span></pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum8"> 8:</span> {</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum9"> 9:</span> var view = <span style="color: #0000ff">new</span> ItemView(pageSize, offset)</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum10"> 10:</span> {</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum11"> 11:</span> PropertySet = <span style="color: #0000ff">new</span> PropertySet(BasePropertySet.IdOnly)</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum12"> 12:</span> {</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum13"> 13:</span> ItemSchema.Body</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum14"> 14:</span> }</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum15"> 15:</span> };</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum16"> 16:</span>  </pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum17"> 17:</span> result = exchangeService.FindItems(WellKnownFolderName.Inbox, view);</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum18"> 18:</span>  </pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum19"> 19:</span> <span style="color: #0000ff">foreach</span> (var item <span style="color: #0000ff">in</span> result)</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum20"> 20:</span> {</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum21"> 21:</span> ProcessItem(item);</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum22"> 22:</span> }</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum23"> 23:</span> offset += pageSize;</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum24"> 24:</span> } <span style="color: #0000ff">while</span> (result.MoreAvailable);</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum25"> 25:</span> }</pre>
<!--CRLF--></div>
</div>
<p>When executed, the ExchangeService instance throws a ServiceValidationException stating “The property Body cannot be used in FindItem requests”. The official workaround proposed by Microsoft is to use a FindItem request to get the item ids of the items in a folder and afterward issue a GetItem request containing all the item ids and request the body property. However, there is another solution: The body properties can be fetched by requesting the MAPI properties containing the body:</p>
<div id="codeSnippetWrapper">
<div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> <span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> ExtendedPropertyDefinition TextBodyProperty = <span style="color: #0000ff">new</span> ExtendedPropertyDefinition(0x1000, MapiPropertyType.String);</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> <span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> ExtendedPropertyDefinition HtmlBodyProperty = <span style="color: #0000ff">new</span> ExtendedPropertyDefinition(0x1013, MapiPropertyType.Binary);</pre>
<!--CRLF--></div>
</div>
<p>The first property definition can be used to fetch the text body of a mail. The second one fetches the Html body. The new GetAllItemsMethod now looks like this:</p>
<div id="codeSnippetWrapper">
<div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> <span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> GetAllItems(ExchangeService exchangeService)</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> {</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3"> 3:</span> var offset = 0;</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4"> 4:</span> <span style="color: #0000ff">const</span> <span style="color: #0000ff">int</span> pageSize = 100;</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5"> 5:</span>  </pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6"> 6:</span> FindItemsResults<Item> result;</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7"> 7:</span> <span style="color: #0000ff">do</span></pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum8"> 8:</span> {</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum9"> 9:</span> var view = <span style="color: #0000ff">new</span> ItemView(pageSize, offset)</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum10"> 10:</span> {</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum11"> 11:</span> PropertySet = <span style="color: #0000ff">new</span> PropertySet(BasePropertySet.IdOnly)</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum12"> 12:</span> {</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum13"> 13:</span> HtmlBodyProperty</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum14"> 14:</span> }</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum15"> 15:</span> };</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum16"> 16:</span>  </pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum17"> 17:</span> result = exchangeService.FindItems(WellKnownFolderName.Inbox, view);</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum18"> 18:</span>  </pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum19"> 19:</span> <span style="color: #0000ff">foreach</span> (var item <span style="color: #0000ff">in</span> result)</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum20"> 20:</span> {</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum21"> 21:</span> <span style="color: #0000ff">object</span> body;</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum22"> 22:</span> <span style="color: #0000ff">if</span> (item.ExtendedProperties.TryGetValue(HtmlBodyProperty, <span style="color: #0000ff">out</span> body))</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum23"> 23:</span> {</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum24"> 24:</span> Console.Out.WriteLine(<span style="color: #006080">"item.Body = {0}"</span>, Encoding.UTF8.GetString(Convert.FromBase64String((<span style="color: #0000ff">string</span>)body)));</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum25"> 25:</span> }</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum26"> 26:</span> }</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum27"> 27:</span> offset += pageSize;</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum28"> 28:</span> } <span style="color: #0000ff">while</span> (result.MoreAvailable);</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum29"> 29:</span> }</pre>
<!--CRLF--></div>
</div>
<p>The HtmlBody is requested with the addtion of the HtmlBodyProperty to the ItemView in line 13. Since the Html body is stored in binary form and returned in Base64 encoded format, it needs to be decoded before it can be displayed. This is done in line 24. If the plaintext body is requested, the value of the body property in line 24 can simply be converted to a string.</p>2009-06-09T19:00:31+00:00hkrausehttp://www.infinitec.de/pingback.axdhttp://www.infinitec.de/post.aspx?id=d72fd6cc-1106-4a01-9228-7c39da272d1213http://www.infinitec.de/trackback.axd?id=d72fd6cc-1106-4a01-9228-7c39da272d12http://www.infinitec.de/post/2009/06/09/Getting-the-body-of-an-Email-with-a-FindItems-request.aspx#commenthttp://www.infinitec.de/syndication.axd?post=d72fd6cc-1106-4a01-9228-7c39da272d12http://www.infinitec.de/post/2009/06/06/Getting-the-fullqualified-DNS-name-of-the-current-computer.aspxGetting the fullqualified DNS name of the current computer2009-06-06T16:23:34+00:00hkrause<p>Under certain circumstances a program needs to determine the name of the computer it’s running on. The first approach to get this name is to use the <a title="Environment..::.MachineName Property " href="http://msdn2.microsoft.com/kd4h3aad.aspx">System.Environment.MachineName</a> property. However, this name only reflects the NETBIOS name of the current machine. But in larger environments a full-qualified name including the DNS domain the computer belongs to. This can be something like computername.contoso.local. One example where this full qualified name might be needed are Exchange Push notification. I’ve published a component to <a href="http://www.codeplex.com/exchangenotification">CodePlex</a> makes it really easy to incorporate them in an application. However, for the notifications to reach the client the component needs to tell the Exchange server a correct callback address. In a very simple network environment, it is sufficient to specify the NETBIOS hostname. But in more complex environments, Exchange might not be able to send a notification because it cannot correctly resolve the unqualified hostname to an IP address.</p> <p>The full qualified domain name of the current host can be resolved with a call tot the <a title="IPGlobalProperties..::.GetIPGlobalProperties Method " href="http://msdn2.microsoft.com/7c7239a3.aspx">System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties</a> method. This method returns, among other things, the required information:</p> <div id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> var ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> <span style="color: #0000ff">string</span> fullQualifiedDomainName;</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3"> 3:</span>  </pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4"> 4:</span> <span style="color: #0000ff">if</span> (!<span style="color: #0000ff">string</span>.IsNullOrEmpty(ipGlobalProperties.DomainName))</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5"> 5:</span> {</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6"> 6:</span> fullQualifiedDomainName = <span style="color: #0000ff">string</span>.Format(<span style="color: #006080">"{0}.{1}"</span>, ipGlobalProperties.HostName, ipGlobalProperties.DomainName);</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7"> 7:</span> }</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum8"> 8:</span> <span style="color: #0000ff">else</span></pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum9"> 9:</span> {</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum10"> 10:</span> fullQualifiedDomainName = ipGlobalProperties.HostName;</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum11"> 11:</span> }</pre>
<!--CRLF--></div>
</div>
<p>I have updated the PushNotification component to reflect this new behavior. </p>2009-06-06T16:23:34+00:00hkrausehttp://www.infinitec.de/pingback.axdhttp://www.infinitec.de/post.aspx?id=677502cb-7e91-4273-8cae-8bb3af8a613c1http://www.infinitec.de/trackback.axd?id=677502cb-7e91-4273-8cae-8bb3af8a613chttp://www.infinitec.de/post/2009/06/06/Getting-the-fullqualified-DNS-name-of-the-current-computer.aspx#commenthttp://www.infinitec.de/syndication.axd?post=677502cb-7e91-4273-8cae-8bb3af8a613c