In November and December 2011, Exchange content made its debut on the Learn Open Specifications and Interoperability page in the Open Specifications Developer Center:
The updates include nine new Microsoft Exchange Learning Modules:
While you’re on the Learn tab exploring the new Exchange learning modules, don’t miss the Open Specifications Interactive Pivot, which also includes Exchange open specifications documents. We’re very excited about the Pivot, which makes it easy to find the open specifications documents you need in a visual, intuitive way. The Pivot uses Silverlight Deep zoom technology, which lets you visually search and filter the open specifications documents. Once you use it, you’ll see why we’re excited.
Are you ready? The EWS Managed API 1.2 documentation is now available, so let the preparation, planning, and architecting begin. The new EWS Managed API will have some updates that you may want to incorporate into your application. Take a look at the What’s New topic to learn more about the new content that is available to support the new EWS Managed API 1.2 functionality. Take a look at the Exchange Web Services Managed API 1.2 SDK topic to learn about the new EWS Managed API 1.2 functionality.
Did you say “Where is the API download?” It’s coming soon. We are releasing the documentation earlier than usual so that you can get a jump on your planning for the next update of your EWS client application. So go have a feature review, maybe update your design specs, and get ready to implement your next update to your EWS client application.
Exchange Web Services (EWS) is a robust API that exposes many Exchange client access features. Many popular clients use this API on many different platforms. What if you want to limit client access via EWS, however? You do have an option. In Exchange 2010, you can use the Set-CASMailbox command to modify EWS access.
Note: The Set-CASMailbox command in Exchange 2007 does not provide options for limiting EWS access.
The following options that the Set-CASMailbox command exposes enable you to change the settings on a per-user basis:
These options make use of the user agent header to filter access. While useful in many scenarios, user agent filtering has one inherent disadvantage: User agent strings can easily be written to represent agents on an allowed list, including Outlook, Mac Outlook, and Entourage. Of equal importance is the fact that specific EWS features can’t be blocked. EWS feature access is not segmented to allow access to particular EWS operations — it’s all or nothing. Turning off EWS will affect clients that use the OOF settings, availability, mail tips, and so on. It is important to take this into consideration when planning the client-server interaction part of your system architecture.
UPDATE: 8 November 2011, Thom Randolph - MSFT.
The following API reference information in this post applies to the Windows Extensible Storage Engine (ESE) APIs, that are available on MSDN at the following URL:
http://msdn.microsoft.com/en-us/library/windows/desktop/gg269259(v=EXCHG.10).aspx
The ESE APIs that ship in Windows should not be used with Exchange mailbox or public folder databases.
The JET_ERRINFOBASIC_W API includes a group of constants, a structure, and a function, as defined in the header file Esent.h. These are described in this blog post.
Note: This documentation is based on a preliminary release of the Extensible Storage Engine. This information is subject to change.
The JET_ERRCAT group of constants describes higher-level classifications or categories of errors. This group of constants enables applications to define default treatment for a classification of errors, rather than handling each error case individually. It also ensures that the application does not have to handle new error conditions that are included in existing classifications.
The JET_ERRCAT constants are arranged in a specific hierarchy of conditions and subconditions, as follows:
|--- Error |--- Operation(al) | |--- Fatal | |--- IO | |--- Resource | |--- Memory | |--- Quota | |--- Disk | |--- Data | |--- Corruption | |--- Inconsistent | |--- Fragmentation | |--- Api |--- Usage |--- State
The following table lists the JET_ERRCAT constants and provides a description and recovery information, as applicable.
Constant/value
Description
Recovery
JET_errcatUnknown 0
An invalid error category.
N/A.
JET_errcatError 1
The top level category (no errors should be of this class).
See the specific error constants.
JET_errcatOperation 2
Represents errors that can happen at any time due to uncontrollable conditions and are often temporary. See subcategories if specified
Retry and if the error continues, inform the operator.
JET_errcatFatal 3
Represents fatal errors that, when they occur, create a risk that ESE cannot continue in a safe (often transactional) way , and data may become corrupted.
Restart the instance or process. If the problem persists, inform the operator.
JET_errcatIO 4
Represents IO errors, which come from the operating system, and are out of ESE's control. This type of error may be temporary.
Retry, and if the error continues, ask the operator to check the disk.
JET_errcatResource 5
Represents a category of errors related to lack of resource conditions.
See subcategories.
JET_errcatMemory 6
Represents an error caused by lack of memory.
Retry after a period of time, free up memory, or quit.
JET_errcatQuota 7
Certain "specialty" resources are in pools of a certain size, making it easier to detect leaks of these resources.
The application should Assert() to detect these issues during development . However, in retail code , the application should treat this as a memory error.
JET_errcatDisk 8
Represents an error caused by lack of disk space.
Retry later to determine whether more disk space is available, or ask the operator to free some disk space.
JET_errcatData 9
Represents a top-level category for errors related to data.
JET_errcatCorruption 10
Represents a corruption issue, which is often permanent without corrective action.
Restore from backup by using the ESE utilities repair operation (this operation restores only the data that is left/lossy). Also when the recovery(JetInit) method is used, recovery can be performed by allowing data loss (for more information, see JET_bitReplayIgnoreLostLogs.
JET_errcatInconsistent 11
Represents an error in which the database and/or log files are in a state that is inconsistent and cannot be reconciled. This error might be caused by application/administrator mishandling.
Restore from backup by using the ESE utilities repair operation (which only restores the data that is left/lossy). Also in the case of the recovery(JetInit) operation, recovery can be performed by allowing data loss (for more information, see JET_bitReplayIgnoreLostLogs.
JET_errcatFragmentation 12
Represents a class of errors in which some persisted internal resource ran out.
For database errors, offline defragmentation will fix the problem. For the log files, first recover all attached databases to a clean shutdown , and then delete all the log files and the checkpoint.
JET_errcatApi 13
JET_errcatUsage 14
Represents a usage error. The client code did not pass the correct arguments to the JET API. This error will persist with retry.
Client code should use the Assert() method to ensure that this class of errors is not returned. so issues can be caught during development. In retail , the application should notify the operator about the error.
JET_errcatState 15
Represents a class of messages that the API can return to describe the state of the database. For example, the JetSeek() method might return JET_errRecordNotFound when the requested record was not found.
Varies based on the API.
JET_errcatObsolete 16
Represents errors that are from a previous version of the engine. These errors should not be returned by the current engine.
Unknown.
JET_errcatMax 17
A constant that indicates the end of the enumeration.
Client
Requires Windows 8.
Server
Requires Windows 8 Server.
Header
Declared in Esent.h.
The JET_ERRINFOBASIC_W structure defines the data that is returned from the JetGetErrorInfo() method when the JET_ErrorInfoSpecificErr InfoLevel [LG1] is passed in.
typedef struct { unsigned long cbStruct; JET_ERR errValue; JET_ERRCAT errcatMostSpecific; unsigned char rgCategoricalHierarchy[8]; unsigned long lSourceLine; WCHAR rgszSourceFile[64]; } JET_ERRINFOBASIC_W;
cbStruct The size of the structure, in bytes. It must be set to sizeof( JET_ERRINFOBASIC ).
errValue The error value that was evaluated, as passed in for the pvResult argument to JetGetErrorInfo().
errcatMostSpecific The lowest-level JET_errcat constant that is associated with the error; that is, the leaf-level category in the category hierarchy documented in JET_ERRCAT.
rgCategoricalHierarchy[8] The hierarchy of error categories that is associated with the error. Position 0 is the highest level in the hierarchy of JET_ERRCAT, and the rest are subcategories until the most specific category is set, after which all categories are JET_errcatUnknown.
lSourceLine Reserved.
rgszSourceFile[64] Reserved.
Requires 8.
Requires 8 Server.
The JetGetErrorInfoW function BAS_ of the database engine.
JET_ERR JET_API JetGetErrorInfoW( _In_opt_ void * pvContext, _Out_writes_bytes_( cbMax ) void * pvResult, _In_ unsigned long cbMax, _In_ unsigned long InfoLevel, _In_ JET_GRBIT grbit );
pvContext The context or error value for which the extended error information is needed. The value passed in depends on the InfoLevel parameter value.
pvResult A pointer to a buffer that will receive the information. The type of the buffer depends on the InfoLevel parameter value. The caller must be configured to align the buffer appropriately.
cbMax The maximum size of the pvResult structure that is passed in.
InfoLevel The type of information that will be retrieved for the error info/context is specified by the pvContext parameter. The format of the data that is stored in pvResult is dependent on InfoLevel.
The following table lists the possible values for this parameter.
Value
Meaning
JET_ErrorInfoSpecificErr
pvContext is interpreted as a JET_ERR/error code, pvResult is interpreted as a JET_ERRINFOBASIC_W, and the fields of the JET_ERRINFOBASIC_W structure are filled in appropriately.
grbit Reserved.
This function returns the JET_ERR data type with one of the return codes listed in the following table. For more information about the possible ESE errors, see Extensible Storage Engine Errors and Error Handling Parameters.
Return code
JET_errSuccess
The operation completed successfully.
JET_errInvalidParameter
One of the parameters provided contains an unexpected value or contains a value that does not make sense when combined with the value of another parameter.
This can happen for JetGetErrorInfo when the following occurs:
JET_errDisabledFunctionality
If this SKU of windows doesn’t support this function, this error will be returned.
On success, the output buffer that is appropriate for the requested error context/value will be set to the extended error info requested.
On failure, the state of the output buffers will be undefined.
The JET_ERRINFOBASIC_W function and JET_ERRCAT group of constants contain documentation about the extended error information that is returned for InfoLevel = JET_ErrorInfoSpecificErr.
Library
Use ESENT.lib.
DLL
Requires ESENT.dll.
Unicode
Note: Only the JetGetErrorInfoW (Unicode) is implemented. This API does not have an A (ANSI) version.
This post is part of an ongoing series that covers Microsoft Exchange ActiveSync for developers.
Microsoft Exchange ActiveSync policies are the primary tool by which IT administrators can manage devices that connect to Microsoft Exchange mailboxes. Administrators can create policy settings to manage security settings such as PIN length, data encryption, and so on. Policies define the terms by which a client can synchronize mailbox data. The provisioning process is a communication that occurs between the client and server that indicates whether the client can enforces the required policies.
In addition to policies, Microsoft Exchange Server 2010 introduces another tool for administrators, known as Allow/Block/Quarantine (ABQ). ABQ enables administrators to control which devices or families of devices can synchronize data with Exchange ActiveSync. Administrators can also use ABQ to block certain devices or all unknown devices from synchronizing data.
Both ABQ and policies help administrators control how and whether data is synchronized onto a device. Remote Wipe is another Exchange ActiveSync feature that is used to remove data from a device. This feature is important when, for example, individuals leave the company, or a device is lost or stolen.
If you are creating an enterprise-class Exchange ActiveSync client, it is important for you to understand and support provisioning and policies, ABQ, and remote wipe. This post provides the information you need to know about these features, in the following sections:
Note
The following information, covered in this blog post, is important for the Exchange ActiveSync Logo Program:
· Device manufacturer and model information
· Password-related policies
· MaxInactivityTimeDeviceLock policy
· MaxDevicePasswordFailedAttempts policy
· Remote Wipe
For more information about the logo program, see Exchange ActiveSync Logo Program on Microsoft TechNet.
The client’s goal in provisioning is to obtain a policy key from the Exchange server. This policy key enables the client to synchronize with a mailbox. Provisioning involves the following steps:
For a detailed description of this process, see [MS-ASPROV]: ActiveSync Provisioning Protocol Specification section 3.1.5.1.
The following figure shows the two-step provisioning process.
Figure 1: Two-step provisioning process
The policy exchange process involves a client Provision command request and a server Provision command response.
In its first request to the Exchange server, the client sends a Provision command request, as shown in the following example.
POST /Microsoft-Server-ActiveSync?User=deviceuser&DeviceId=6F24CAD599A5BF1A690246B8C68FAE8D&DeviceType=PocketPC&Cmd=Provision HTTP/1.1 Accept-Language: en-us MS-ASProtocolVersion: 14.0 Content-Type: application/vnd.ms-sync.wbxml X-MS-PolicyKey: 0 User-Agent: ASOM Host: EXCH-B-003 <?xml version="1.0" encoding="utf-8"?> <Provision xmlns="Provision:" xmlns:settings="Settings:"> <settings:DeviceInformation> <settings:Set> <settings:Model>… </settings:Model> <settings:IMEI>...</settings:IMEI> <settings:FriendlyName>...</settings:FriendlyName> <settings:OS>...</settings:OS> <settings:OSLanguage>...</settings:OSLanguage> <settings:PhoneNumber>...</settings:PhoneNumber> <settings:MobileOperator>...</settings:MobileOperator> <settings:UserAgent>...</settings:UserAgent> </settings:Set> </settings:DeviceInformation> <Policies> <Policy> <PolicyType>MS-EAS-Provisioning-WBXML</PolicyType> </Policy> </Policies> </Provision>
POST /Microsoft-Server-ActiveSync?User=deviceuser&DeviceId=6F24CAD599A5BF1A690246B8C68FAE8D&DeviceType=PocketPC&Cmd=Provision HTTP/1.1
Accept-Language: en-us
MS-ASProtocolVersion: 14.0
Content-Type: application/vnd.ms-sync.wbxml
X-MS-PolicyKey: 0
User-Agent: ASOM
Host: EXCH-B-003
<?xml version="1.0" encoding="utf-8"?>
<Provision xmlns="Provision:" xmlns:settings="Settings:">
<settings:DeviceInformation>
<settings:Set>
<settings:Model>… </settings:Model>
<settings:IMEI>...</settings:IMEI>
<settings:FriendlyName>...</settings:FriendlyName>
<settings:OS>...</settings:OS>
<settings:OSLanguage>...</settings:OSLanguage>
<settings:PhoneNumber>...</settings:PhoneNumber>
<settings:MobileOperator>...</settings:MobileOperator>
<settings:UserAgent>...</settings:UserAgent>
</settings:Set>
</settings:DeviceInformation>
<Policies>
<Policy>
<PolicyType>MS-EAS-Provisioning-WBXML</PolicyType>
</Policy>
</Policies>
</Provision>
The client Provision command request includes information contained within two parent elements:
I will discuss the settings.DeviceInformation element in more detail in the "ABQ" section later in this post.
In the Policies element section, the client indicates in the PolicyType element the format of the policy information that the client wants the server to use. The client should always send the “MS-EAS-Provisioning-WBXML” value, as described in [MS-ASPROV] section 2.2.2.42.
The use of the settings:DeviceInformation element in the provisioning request varies based on the version of the Exchange ActiveSync protocol the client is using, as described in the following table.
Exchange ActiveSync protocol version
Provision command request
Exchange ActiveSync version 12.1
The client should not include a settings:DeviceInformation element because this element is not supported.
Exchange ActiveSync version 14.0
The settings:DeviceInformation element is optional. However, in order to support ABQ, the client must submit the DeviceInformation element with the Provision command request or with a Settings command request, as described in [MS-ASCMD]: ActiveSync Command Reference Protocol Specification section 2.2.3.43.
Exchange ActiveSync version 14.1
The settings:DeviceInformation element is required. The settings:Set child element is also required and must contain the Model child element.
For more information about the differences between Exchange ActiveSync protocol versions in client provisioning requests, see [MS-ASPROV] section 6.
The following example shows a server response to a client provisioning request.
Note: The policies listed in this example do not represent all the possible policies that the server might send. For a complete list of policies, see [MS-ASPROV] section 2.2.2.
HTTP/1.1 200 OK Connection: Keep-Alive Content-Length: 1069 Date: Mon, 01 May 2006 20:15:15 GMT Content-Type: application/vnd.ms-sync.wbxml Server: Microsoft-IIS/6.0 X-Powered-By: ASP.NET X-AspNet-Version: 2.0.50727 MS-Server-ActiveSync: 8.0 Cache-Control: private <?xml version="1.0" encoding="utf-8"?> <Provision xmlns:A0="AirSync:" xmlns:A1="POOMCONTACTS:" xmlns:A2="POOMMAIL:" xmlns:A3="AirNotify:" xmlns:A4="POOMCAL:" xmlns:A5="Move:" xmlns:A6="GetItemEstimate:" xmlns:A7="FolderHierarchy:" xmlns:A8="MeetingResponse:" xmlns:A9="POOMTASKS:" xmlns:A10="ResolveRecipients:" xmlns:A11="ValidateCert:" xmlns:A12="POOMCONTACTS2:" xmlns:A13="Ping:" xmlns:A15="Search:" xmlns:A16="Gal:" xmlns:A17="AirSyncBase:" xmlns:A18="Settings:" xmlns:A19="DocumentLibrary:" xmlns:A20="ItemOperations:" xmlns:A21="ComposeMail:" xmlns:A22="POOMMAIL2:" xmlns:A23="Notes:" xmlns:A24="RightsManagement:" xmlns="Provision:"> <Status>1 Success</Status> <Policies> <Policy> <PolicyType>MS-EAS-Provisioning-WBXML</PolicyType> <Status>1 Success</Status> <PolicyKey>2488355417</PolicyKey> <Data> <eas-provisioningdoc> <DevicePasswordEnabled>1</DevicePasswordEnabled> <AlphanumericDevicePasswordRequired>0</AlphanumericDevicePasswordRequired> <PasswordRecoveryEnabled>0</PasswordRecoveryEnabled> <RequireStorageCardEncryption>0</RequireStorageCardEncryption> <AttachmentsEnabled>1</AttachmentsEnabled> <MinDevicePasswordLength>4</MinDevicePasswordLength> <MaxInactivityTimeDeviceLock>900</MaxInactivityTimeDeviceLock> <MaxDevicePasswordFailedAttempts>8</MaxDevicePasswordFailedAttempts> <MaxAttachmentSize/> <AllowSimpleDevicePassword>1</AllowSimpleDevicePassword> <DevicePasswordExpiration/> <DevicePasswordHistory>0</DevicePasswordHistory> <AllowStorageCard>1</AllowStorageCard> <AllowCamera>1</AllowCamera> <RequireDeviceEncryption>0</RequireDeviceEncryption> <AllowUnsignedApplications>1</AllowUnsignedApplications> <AllowUnsignedInstallationPackages>1</AllowUnsignedInstallationPackages> <MinDevicePasswordComplexCharacters>1</MinDevicePasswordComplexCharacters> <AllowWiFi>1</AllowWiFi> <AllowTextMessaging>1</AllowTextMessaging> <AllowPOPIMAPEmail>1</AllowPOPIMAPEmail> <AllowBluetooth>2</AllowBluetooth> <AllowIrDA>1</AllowIrDA> <RequireManualSyncWhenRoaming>0</RequireManualSyncWhenRoaming> <AllowDesktopSync>1</AllowDesktopSync> <MaxCalendarAgeFilter>0</MaxCalendarAgeFilter> <AllowHTMLEmail>1</AllowHTMLEmail> <MaxEmailAgeFilter>0</MaxEmailAgeFilter> <MaxEmailBodyTruncationSize>-1</MaxEmailBodyTruncationSize> <MaxEmailHTMLBodyTruncationSize>-1</MaxEmailHTMLBodyTruncationSize> <RequireSignedSMIMEMessages>0</RequireSignedSMIMEMessages> <RequireEncryptedSMIMEMessages>0</RequireEncryptedSMIMEMessages> <RequireSignedSMIMEAlgorithm>0</RequireSignedSMIMEAlgorithm> <RequireEncryptionSMIMEAlgorithm>0</RequireEncryptionSMIMEAlgorithm> <AllowSMIMEEncryptionAlgorithmNegotiation>2</AllowSMIMEEncryptionAlgorithmNegotiation> <AllowSMIMESoftCerts>1</AllowSMIMESoftCerts> <AllowBrowser>1</AllowBrowser> <AllowConsumerEmail>1</AllowConsumerEmail> <AllowRemoteDesktop>1</AllowRemoteDesktop> <AllowInternetSharing>1</AllowInternetSharing> <UnapprovedInROMApplicationList/> <ApprovedApplicationList/> </eas-provisioningdoc> </Data> </Policy> </Policies> </Provision>
HTTP/1.1 200 OK
Connection: Keep-Alive
Content-Length: 1069
Date: Mon, 01 May 2006 20:15:15 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
MS-Server-ActiveSync: 8.0
Cache-Control: private
<Provision xmlns:A0="AirSync:" xmlns:A1="POOMCONTACTS:" xmlns:A2="POOMMAIL:" xmlns:A3="AirNotify:" xmlns:A4="POOMCAL:" xmlns:A5="Move:" xmlns:A6="GetItemEstimate:" xmlns:A7="FolderHierarchy:" xmlns:A8="MeetingResponse:" xmlns:A9="POOMTASKS:" xmlns:A10="ResolveRecipients:" xmlns:A11="ValidateCert:" xmlns:A12="POOMCONTACTS2:" xmlns:A13="Ping:" xmlns:A15="Search:" xmlns:A16="Gal:" xmlns:A17="AirSyncBase:" xmlns:A18="Settings:" xmlns:A19="DocumentLibrary:" xmlns:A20="ItemOperations:" xmlns:A21="ComposeMail:" xmlns:A22="POOMMAIL2:" xmlns:A23="Notes:" xmlns:A24="RightsManagement:" xmlns="Provision:">
<Status>1 Success</Status>
<PolicyKey>2488355417</PolicyKey>
<Data>
<eas-provisioningdoc>
<DevicePasswordEnabled>1</DevicePasswordEnabled>
<AlphanumericDevicePasswordRequired>0</AlphanumericDevicePasswordRequired>
<PasswordRecoveryEnabled>0</PasswordRecoveryEnabled>
<RequireStorageCardEncryption>0</RequireStorageCardEncryption>
<AttachmentsEnabled>1</AttachmentsEnabled>
<MinDevicePasswordLength>4</MinDevicePasswordLength>
<MaxInactivityTimeDeviceLock>900</MaxInactivityTimeDeviceLock>
<MaxDevicePasswordFailedAttempts>8</MaxDevicePasswordFailedAttempts>
<MaxAttachmentSize/>
<AllowSimpleDevicePassword>1</AllowSimpleDevicePassword>
<DevicePasswordExpiration/>
<DevicePasswordHistory>0</DevicePasswordHistory>
<AllowStorageCard>1</AllowStorageCard>
<AllowCamera>1</AllowCamera>
<RequireDeviceEncryption>0</RequireDeviceEncryption>
<AllowUnsignedApplications>1</AllowUnsignedApplications>
<AllowUnsignedInstallationPackages>1</AllowUnsignedInstallationPackages>
<MinDevicePasswordComplexCharacters>1</MinDevicePasswordComplexCharacters>
<AllowWiFi>1</AllowWiFi>
<AllowTextMessaging>1</AllowTextMessaging>
<AllowPOPIMAPEmail>1</AllowPOPIMAPEmail>
<AllowBluetooth>2</AllowBluetooth>
<AllowIrDA>1</AllowIrDA>
<RequireManualSyncWhenRoaming>0</RequireManualSyncWhenRoaming>
<AllowDesktopSync>1</AllowDesktopSync>
<MaxCalendarAgeFilter>0</MaxCalendarAgeFilter>
<AllowHTMLEmail>1</AllowHTMLEmail>
<MaxEmailAgeFilter>0</MaxEmailAgeFilter>
<MaxEmailBodyTruncationSize>-1</MaxEmailBodyTruncationSize>
<MaxEmailHTMLBodyTruncationSize>-1</MaxEmailHTMLBodyTruncationSize>
<RequireSignedSMIMEMessages>0</RequireSignedSMIMEMessages>
<RequireEncryptedSMIMEMessages>0</RequireEncryptedSMIMEMessages>
<RequireSignedSMIMEAlgorithm>0</RequireSignedSMIMEAlgorithm>
<RequireEncryptionSMIMEAlgorithm>0</RequireEncryptionSMIMEAlgorithm>
<AllowSMIMEEncryptionAlgorithmNegotiation>2</AllowSMIMEEncryptionAlgorithmNegotiation>
<AllowSMIMESoftCerts>1</AllowSMIMESoftCerts>
<AllowBrowser>1</AllowBrowser>
<AllowConsumerEmail>1</AllowConsumerEmail>
<AllowRemoteDesktop>1</AllowRemoteDesktop>
<AllowInternetSharing>1</AllowInternetSharing>
<UnapprovedInROMApplicationList/>
<ApprovedApplicationList/>
</eas-provisioningdoc>
</Data>
The response includes the following:
Notice that the response contains two Status elements. The first Status element is a child of the Provision element and indicates the general status of the Exchange server’s ability to process the client’s request. The following table lists the possible values for the first Status element.
Status element value
1
Success
The Policies element contains the information about the security policies.
2
Protocol error
The request was malformed.
3
General server error
A transient error occurred. The client should retry the request over a period of time.
The second Status element is a child of the Policy element and indicates whether the policy settings were applied correctly. The following table lists the possible values for the Status element.
The Data element contains the policy settings to apply.
No policy
The server doesn't have a policy. The device doesn't need to submit a second request; it can proceed to sync data.
Unknown policy type
The device sent an invalid value for the PolicyType element. The only valid value for the PolicyType element is “MS-EAS-Provisioning-WBXML”.
4
Policy data is corrupt
The policy data on the server is corrupt. The device should suggest that the user contact the administrator.
5
Policy key mismatch
The policy key sent in the last request does not match the key stored on the server. Either the device sent the wrong policy key or the policy changed on the server since the first response. The device should re-initiate the provisioning process from the beginning.
At this point, the server relies on the client to apply the policies as requested. After applying the security policy settings, the client sends another Provision command request to the server to acknowledge the policies and indicate its ability to apply them on the device.
The following example shows the second Provision request that the client sends to the server.
POST /Microsoft-Server-ActiveSync?User=deviceuser&DeviceId=6F24CAD599A5BF1A690246B8C68FAE8D&DeviceType=PocketPC&Cmd=Provision HTTP/1.1 Accept-Language: en-us MS-ASProtocolVersion: 14.0 Content-Type: application/vnd.ms-sync.wbxml X-MS-PolicyKey: 1307199584 User-Agent: ASOM Host: EXCH-B-003 <?xml version="1.0" encoding="utf-8"?> <Provision xmlns="Provision:"> <Policies> <Policy> <PolicyType>MS-EAS-Provisioning-WBXML</PolicyType> <PolicyKey>1307199584</PolicyKey> <Status>1</Status> </Policy> </Policies> </Provision>
X-MS-PolicyKey: 1307199584
<Provision xmlns="Provision:">
<PolicyKey>1307199584</PolicyKey>
<Status>1</Status>
This request contains the policy key value that the server sent to the client in step 1. It also contains a Status element that indicates whether the client was able to apply the policy settings. The following table lists the possible values of the Status element.
The client was able to apply all the policy settings.
Partial success
The client was able to apply some of the policy settings but failed to apply others.
Failure
The client was not able to apply any of the policy settings.
Externally managed
The client was provisioned by a third party.
Note: If a Microsoft Exchange administrator sets the "Allow non-provisionable devices" option in the Exchange ActiveSync policy, the server will allow all clients to synchronize mailbox data regardless of whether the client asked for policy settings or applied them successfully. However, if the administrator chooses to disable the "Allow non-provisionable devices" option, only clients that respond with "Success" are allowed to connect to the mailbox.
Important: When the client indicates "partial success" in its second request to the server, this means that the client failed to apply at least one of the security policies that the server returned in its initial response. Note, however, that there is a distinction between policies that are not relevant to the device and policies that the device was not able to apply. The policies that “allow” and “disallow” certain features of the device do not have to be applied if they are not relevant to the device in order for the client to indicate "success" in its request. For example, if the device does not support Bluetooth, the client can safely ignore the AllowBluetooth policy and report back “success” instead of “partial success”. Conversely, if AllowBluetooth is set to false and the device supports Bluetooth but cannot disable it, the device can return “partial success”.
For any policy that requires a certain feature, the client must not return success if the policy cannot be applied. For example, the client should only indicate "success" for the RequireDeviceEncryption policy when the client supports device encryption. If the device doesn’t support encryption, the client should indicate "partial success" or "failure", depending on the status of the other policies. For more information about specific policies, see "Policies" later in this blog post.
Note: If the DevicePasswordEnabled policy is set to true, and the device is not able to enforce the password, it must return "failure" in response to the Provision command, regardless of whether it can enforce any other policy. The client can return "partial success" if it cannot enforce any other policies. For example, if the client enabled a password but failed to encrypt the device, it can return "partial success" rather than "failure".
The following example shows the server's response to the second client Provision request.
HTTP/1.1 200 OK Connection: Keep-Alive Content-Length: 63 Date: Mon, 01 May 2006 20:15:17 GMT Content-Type: application/vnd.ms-sync.wbxml Server: Microsoft-IIS/6.0 X-Powered-By: ASP.NET X-AspNet-Version: 2.0.50727 MS-Server-ActiveSync: 8.0 Cache-Control: private <?xml version="1.0" encoding="utf-8"?> <Provision xmlns="Provision:"> <Status>1</Status> <Policies> <Policy> <PolicyType> MS-EAS-Provisioning-WBXML </PolicyType> <Status>1</Status> <PolicyKey>3942919513</PolicyKey> </Policy> </Policies> </Provision>
Content-Length: 63
Date: Mon, 01 May 2006 20:15:17 GMT
<PolicyType> MS-EAS-Provisioning-WBXML </PolicyType>
<PolicyKey>3942919513</PolicyKey>
This response does not include a Data element that contains the list of policy settings. The server simply responds with a Status element (the values for which are listed in the "Server provisioning response" section) and a new policy key. This new policy key is the permanent key that the client should save and resubmit when it sends subsequent requests to the server.
The policy key represents the current security policy settings that are applied on the client. It can be up to 64 characters long and can contain any of the characters that are allowed in an HTTP header. The client should retain only the latest policy key that it has received from the server and submit it with all requests.
Note: Submitting the policy key is optional the Ping command and the HTTP OPTIONS commands.
The following example shows a client request that includes the policy key.
POST /Microsoft-Server-ActiveSync?User=deviceuser&DeviceId=6F24CAD599A5BF1A690246B8C68FAE8D&DeviceType=PocketPC&Cmd=FolderSync HTTP/1.1 Accept-Language: en-us MS-ASProtocolVersion: 14.0 Content-Type: application/vnd.ms-sync.wbxml X-MS-PolicyKey: 3942919513 User-Agent: ASOM Host: EXCH-B-003 <?xml version="1.0" encoding="utf-8"?> <FolderSync xmlns="FolderHierarchy:"> <SyncKey>0</SyncKey> </FolderSync>
POST /Microsoft-Server-ActiveSync?User=deviceuser&DeviceId=6F24CAD599A5BF1A690246B8C68FAE8D&DeviceType=PocketPC&Cmd=FolderSync HTTP/1.1
X-MS-PolicyKey: 3942919513
<FolderSync xmlns="FolderHierarchy:">
<SyncKey>0</SyncKey>
</FolderSync>
Clients should send a Provision command request when they first contact the server. In some scenarios, the server may require the client to provision again, after an initial provision sequence. The server indicates this by sending a 449 HTTP error response or a success response with one of the status codes listed in the following table in response to any client request. The client should immediately send a Provision command request after receiving one of these statuses in a response.
Status code
Name
139
DeviceNotFullyProvisionable
The device uses a protocol version that cannot send all the policy settings the administrator enabled. The client should retry its request once per hour to determine whether the policy has changed.
Important: This is status code indicates a condition that will not be resolved until the administrator changes the policy. The client should display a warning that it cannot synchronize due to current policy settings and recommend that the user contact their administrator
140
RemoteWipeRequested
The server requests that the client wipe all data. The client should send a Provision command request so that it can acknowledge the wipe request.
141
LegacyDeviceOnStrictPolicy
The client is not capable of provisioning and the administrator has decided to make the policy a strict requirement. The client cannot synchronize until the policy changes. The client should retry once per hour to determine whether the policy has changed.
Important: This is status indicates a condition that will not be resolved until the administrator changes the policy. The client should display a warning that it cannot synchronize due to current policy settings and recommend that the user contact their administrator.
142
DeviceNotProvisioned
The client has not provisioned yet and must send a Provision command request immediately.
143
PolicyRefresh
The server is configured to send the policy to the client every n hours and it is now time for the client to receive the policy again, regardless of whether the policy has changed. The client has to resend the Provision command request to obtain a new policy key.
144
InvalidPolicyKey
The policy key sent by the client is no longer valid. This occurs when the policy is changed on the server (a new policy key is generated each time the policy changes). The client has to resend the Provision command request to get the new policy.
145
ExternallyManagedDevicesNotAllowed
The client indicated that it was provisioned through another mechanism but the server is configured to require that the client have the server's policy applied. The client should retry once per hour to determine whether the policy has changed.
Important: This status indicates a condition that will not be resolved until the administrator changes the policy. The client should display a warning that it cannot synchronize due to current policy settings and recommend that the user contact their administrator.
In version 12.1 of the Exchange ActiveSync protocol, the server only sends an HTTP 449 response to inform the client that it needs to provision; it does not send the status codes listed in the previous table. Because this error response does not enable the client to distinguish between transient and potentially nontransient provisioning errors, the client should try to provision. If subsequent requests fail with additional HTTP 449 error respon ses, the client should suggest that the user contact their administrator. At that point, the client may choose to try to provision once per hour to determine whether the policy has changed.
Important: The client should compare existing device settings against policy updates to ensure that it is compliant with the updated policy. For example, if a password is set on the client, the client should compare the existing password (length, complexity, and so on) against the updated policy settings requested by the server. If the existing password does not conform to these updated policy settings or if the client cannot verify that the current password meets the requirements, the client should prompt the user to configure a new password.
Because it is up to the client to enforce policies, it is important to understand the effects that each policy will have on the device when applied. For a list of the elements that contain policy information, see [MS-ASPROV] section 2.2.2. This information will help you to determine acceptable values and expected results for each policy. For more information about policies in general, see Understanding Exchange ActiveSync Mailbox Policies on Microsoft TechNet.
This section lists and describes some of the policies that are available; it does not provide a comprehensive list of all policies. For more information about policies, see [MS-ASPROV].
The following table lists policies that clients can ignore and describes the conditions in which they can be ignored. If the conditions apply, the client can return "success" although the policy is not applied. Policies that are not listed in this table cannot be ignored under any conditions.
Policy name
Condition
AllowBluetooth
Ignored if the device does not support Bluetooth.
AllowCamera
Ignored if the device does not have a camera and a camera cannot be attached to the device.
AllowDesktopSync
Ignored if the device does not support connecting to a personal computer.
AllowInternetSharing
Ignored if the device does not support sharing its Internet connection with other devices.
AllowIrDA
Ignored if the device cannot transmit or receive infrared signals.
AllowRemoteDesktop
Ignored if the device does not support connecting remotely to a personal computer.
AllowStorageCard
Ignored if the device does not support storing data on removable storage.
AllowTextMessaging
Ignored if the device is not capable of using SMS messaging.
AllowWifi
Ignored if the device does not have Wi-Fi capability.
PasswordRecoveryEnabled
Ignored if the DevicePasswordEnabled element is set to FALSE (0) or if the client does not support recovery passwords.
RequireStorageCardEncryption
Ignored if the device does not support removable storage. If the device supports removable storage, it must reply to this policy request based on whether it is able to encrypt the storage card.
AllowSimpleDevicePassword,
AlphanumericDevicePasswordRequired,
DevicePasswordExpiration,
DevicePasswordHistory,
MinDevicePasswordComplexCharacters,
MaxDevicePasswordFailedAttempts,
MinDevicePasswordLength,
Ignored if the value of the DevicePasswordEnabled element is FALSE (0).
In addition, the MinDevicePasswordComplexCharacters policy can safely be ignored if the AlphanumericDevicePasswordRequired policy is set to false.
The following table lists additional policies and describes the expected behavior:
Expected behavior
AllowSimpleDevicePassword
The server does not define a simple password. In general, simple passwords can include sequential digits (1234), repeating digits (1111), letters in keyboard order (qwerty), and so on.
AlphanumericDevicePasswordRequired
If the device can only enforce a numeric PIN, the client must fail to apply this policy if it is enabled.
DeviceEncryptionEnabled
The client should encrypt any data received from the server, including email messages, contacts, attachments, and so on. The client is not required to encrypt other data, such as photos or music.
DevicePasswordEnabled
If this policy is enabled, the client must require that the user enter a password before accessing any data obtained from the server, including email messages, contacts, attachments, and so on.
MaxDevicePasswordFailedAttempts
Specifies the number of consecutive attempts a user can make to enter the correct password for the device. After this number of attempts, the device must wipe all data obtained from the server. The device can (and should) implement a mechanism to prevent accidental button presses from causing a device wipe.
MaxEmailBodyTruncationSize
Specifies the maximum size at which to truncate email messages when synchronized to the client. The value is in kilobytes (KBs). The client must not allow the user to choose a value larger than this setting. This value does not restrict the size of items returned by the ItemOperations command. The device can download the full items.
MaxEmailHTMLBodyTruncationSize
Specifies the maximum size at which to truncate HTML email messages when synchronized to the client. The value is in KBs. The device must not allow the user to choose a value larger than this setting. This value does not restrict the size of items returned by the ItemOperations command. The device can download the full items.
MaxInactivityTimeDeviceLock
Specifies the length of time (in seconds) that the device can be inactive before the password is required to reactivate it. The user can choose a value that is smaller than this, but cannot choose a value that is larger.
A recovery password is a second password that can be used to unlock the device if the user forgets their original password. When the user enters the recovery password, the client should prompt the user to create a new password immediately. The client should then create a new recovery password and send it to the server by using the Settings command as soon as possible.
This is not technically a policy, because the client can still synchronize even if the device does not send a recovery password to the server. The purpose of this setting is to indicate to the client whether the server is willing to store a recovery password for the client. If the value for this policy is zero, the client should not send a recovery password to the server.
The remote wipe process enables administrators to request that the client erase all data from a device. Remote wipe is used in scenarios in which a device is lost or stolen or when a user has left the company or no longer has permission to synchronize corporate data. Administrators can use the Exchange Management Shell or the Exchange Management Console (EMC) to request a remote wipe. For more information, see Understanding Remote Device Wipe on Microsoft TechNet.
After an administrator requests a remote wipe, the next time the client sends a request to the server, the server will respond with status code 140, RemoteWipeRequested. The client should then submit a Provision command request. If the server's response contains a RemoteWipe element, the client should send an acknowledgement that it is about to wipe the device first. Because the wipe will erase all data from memory and storage, the client sends the acknowledgement first because it will not have the information it needs to send requests after it wipes the device. For examples of the requests and responses that are sent during the remote wipe process, see [MS-ASPROV] section 4.2.
Note: In version 12.1 of the Exchange ActiveSync protocol, the server sends an HTTP 449 response instead of the 140 status code to request that the client send a Provision command to which the server will respond with a RemoteWipe element.
The following is an example of a server response to a Provision command request that includes a RemoteWipe element.
Content-Type: application/vnd.ms-sync.wbxml Date: Wed, 25 Mar 2009 01:23:58 GMT Content-Length: 14 <?xml version="1.0" encoding="utf-8"?> <Provision> <Status>1</Status> <RemoteWipe /> </Provision>
Date: Wed, 25 Mar 2009 01:23:58 GMT
Content-Length: 14
<Provision>
<RemoteWipe />
The following example shows a Provision command request from the client that contains the remote wipe status.
POST /Microsoft-Server-ActiveSync?Cmd=Provision&User=T0SyncUser1v14.0&DeviceId=Device1&DeviceType=PocketPC HTTP/1.1 Content-Type: application/vnd.ms-sync.wbxml MS-ASProtocolVersion: 14.0 X-MS-PolicyKey: 0 User-Agent: ASOM Host: EXCH-B-003 <?xml version="1.0" encoding="utf-8"?> <Provision xmlns="Provision:"> <RemoteWipe> <Status>1</Status> </RemoteWipe> </Provision>
POST /Microsoft-Server-ActiveSync?Cmd=Provision&User=T0SyncUser1v14.0&DeviceId=Device1&DeviceType=PocketPC HTTP/1.1
<RemoteWipe>
</RemoteWipe>
The client should include one of the following values in the Status element:
Important: Wiping the device resets the device to factory default conditions, including removing all data on the device and any data on the storage card if one is included.
Allow/Block/Quarantine (ABQ) is a new feature introduced in Exchange 2010 that enables administrators to control device access to mailboxes based on device type. While provisioning and policies focus on managing device features such as passwords, cameras, encryption, and so on, ABQ simply controls access to the mailbox. Administrators use ABQ along with policies to manage Exchange ActiveSync clients. For more information, see Controlling Exchange ActiveSync device access using the Allow/Block/Quarantine list on the Exchange Team Blog.
Microsoft Exchange manages access to the mailbox through ABQ by using device information that it relies on the client to provide. The client sends this information in the Provision command request or as part of the Settings command, as shown in the following example.
<?xml version="1.0" encoding="utf-8"?> <Settings xmlns="Settings:"> <DeviceInformation> <Set> <Model>CONTOSO</Model> <IMEI>123456789012345</IMEI> <FriendlyName>Matt's Phone</FriendlyName> <OS>Contoso Phone1.0.1234</OS> <OSLanguage>English</OSLanguage> <PhoneNumber>555-555-1234</PhoneNumber> <MobileOperator>ContosoTelecom</MobileOperator> <UserAgent>ContosoPhone1</UserAgent> <EnableOutboundSMS>1</EnableOutboundSMS> </Set> </DeviceInformation> </Settings>
<Settings xmlns="Settings:">
<DeviceInformation>
<Set>
<Model>CONTOSO</Model>
<IMEI>123456789012345</IMEI>
<FriendlyName>Matt's Phone</FriendlyName>
<OS>Contoso Phone1.0.1234</OS>
<OSLanguage>English</OSLanguage>
<PhoneNumber>555-555-1234</PhoneNumber>
<MobileOperator>ContosoTelecom</MobileOperator>
<UserAgent>ContosoPhone1</UserAgent>
<EnableOutboundSMS>1</EnableOutboundSMS>
</Set>
</DeviceInformation>
</Settings>
The elements set by the client are listed in the following table:
Element name
Model
Indicates the manufacturer and model name or number of the device.
FriendlyName
Describes the device in a way that is meaningful to a user.
IMEI
Uniquely identifies the device.
OS
Precisely specifies the operating system version that the client is running. The OS element value is structured as follows: <Operating System Name> <Operating System Major Version> <Operating System Minor Version>.
OSLanguage
Indicates the language used by the client. The server displays this information when it lists device properties.
PhoneNumber
Can be provided to help with troubleshooting or device management. This element is optional unless the EnableOutboundSMS element is set to 1, in which case the server returns a status code 5 because a phone number is required in order for the server to try to send SMS messages.
MobileOperator
Indicates the name of the operator that a mobile device is connected to.
UserAgent
The value of this element should match the User-Agent header values that are submitted with each request.
EnableOutboundSMS
This element should have a value of either 1 or 0 to indicate whether the client can be used to send outbound SMS messages composed by the server.
Note: Clients that support versions 12.1 and 14.0 of the Exchange ActiveSync protocol should use the Settings command to send device information. The client should send the Settings command as soon as possible after provisioning and before sending the first FolderSync command.
[MS-ASCMD]: ActiveSync Command Reference Protocol Specification
[MS-ASPROV]: ActiveSync Provisioning Protocol Specification
Understanding Exchange ActiveSync Mailbox Policies
Understanding Remote Device Wipe
Controlling Exchange ActiveSync device access using the Allow/Block/Quarantine list
Post authored by: Matt Stehle, Microsoft Corporation
This post is part of an ongoing series that covers Microsoft Exchange ActiveSync for developers. This post applies to Exchange ActiveSync protocol version 14.1. Where applicable, differences between protocol versions are noted.
The ability to respond to meeting requests is an important aspect of collaboration and communication for Microsoft Exchange users. Responses to meeting requests inform meeting organizers of invitees' attendance status and automatically book the time on attendees' Calendars. This post provides information for developers about working with meeting responses, including the following topics:
For information about working with meeting requests, see the blog post Working with Meeting Requests in Exchange ActiveSync.
Note: Other topics related to calendaring with Exchange ActiveSync, such as recurring meetings; delegation; and meeting responses, updates, and cancellations, will be covered in future blog posts.
The following figure shows an overview of the meeting response process and the two key scenarios involved. In this example, Exchange ActiveSync user Bob has received a meeting invitation from the organizer, Alice, on his Exchange ActiveSync client. Bob responds to the meeting request using his Exchange ActiveSync device and Alice can verify his response status using her device.
Figure 1: Meeting response process
This post does not cover adding the meeting request email message to the invitee's Inbox and a creating tentative placeholder item on the invitee's Calendar. For information about the meeting request process, see Working with Meeting Requests in Exchange ActiveSync.
In our example, an invitee, Bob, finds a meeting request from Alice waiting in his Inbox, and a placeholder Calendar item tentatively marking the time of the meeting on his Calendar. Bob can choose to accept, tentatively accept, or decline the meeting and send his response to the organizer from either the meeting invitation in his Inbox or the Calendar placeholder item. Bob accepts the meeting request by using the options provided by the meeting request email displayed on his Exchange ActiveSync client. The Exchange server then deletes the meeting request from his Inbox and changes the status of the placeholder Calendar item from tentative to busy. In addition, the Exchange ActiveSync client sends a meeting acceptance notification to the organizer. A copy of this message appears in Bob's Sent Items folder.
The following figure shows the Exchange ActiveSync client meeting response process.
Figure 2: Exchange ActiveSync client meeting response process
Responding to meeting requests involves the following steps:
Note: If Bob's Exchange server is not configured to process incoming meeting requests automatically, a tentative meeting placeholder item does not appear on his Calendar. In this case, the server does not delete any Calendar item, and the MeetingResponse command cannot be sent from the Calendar folder; it can be used on the meeting request in the Inbox only.
Note: If Bob syncs his Deleted Items folder, a copy of the original meeting item is added to that folder. (This step is not shown in Figure 2 and is not described in this blog post.)
When the ResponseRequested element is set to 1, the Exchange ActiveSync client allows the user to act on the meeting request from both the Inbox and the Calendar item.
When the client displays a meeting request message in a user's Inbox, the user has the option to accept, tentatively accept, or decline the meeting invitation. After the user selects a response, the client sends a MeetingResponse command to the server.
The following example shows a MeetingResponse command request.
POST /Microsoft-Server-ActiveSync?Cmd=MeetingResponse&User=Bob&DeviceId=ABCDEF&DeviceType=SmartPhone HTTP/1.1 Content-Type: application/vnd.ms-sync.wbxml MS-ASProtocolVersion: 14.1 User-Agent: ASOM Host: mail.contoso.com <?xml version="1.0" encoding="utf-8"?> <MeetingResponse xmlns="MeetingResponse:"> <Request> <UserResponse>1</UserResponse> <CollectionId>6</CollectionId> <RequestId>6:17</RequestId> </Request> </MeetingResponse>
POST /Microsoft-Server-ActiveSync?Cmd=MeetingResponse&User=Bob&DeviceId=ABCDEF&DeviceType=SmartPhone HTTP/1.1
MS-ASProtocolVersion: 14.1
Host: mail.contoso.com
<MeetingResponse xmlns="MeetingResponse:">
<Request>
<UserResponse>1</UserResponse>
<CollectionId>6</CollectionId>
<RequestId>6:17</RequestId>
</Request>
</MeetingResponse>
The RequestId element specifies the server ID of the meeting request in the Inbox collection. The UserResponse element can contain one of the values listed in the following table.
UserResponse element value
Invitee response
Server action
Accepted
The server deletes the corresponding Calendar entry and creates a new Calendar entry with the "Accepted" status.
Tentative
The server deletes the corresponding Calendar entry and creates a new Calendar entry with the "TentativelyAccepted" status.
Declined
The server deletes the corresponding Calendar entry.
After the MeetingResponse command has finished, the server automatically deletes the meeting request item from the Inbox. The following example shows the server response.
HTTP/1.1 200 OK MS-Server-ActiveSync: 14.0 <?xml version="1.0" encoding="utf-8" ?> <MeetingResponse xmlns="MeetingResponse:"> <Result> <RequestId>6:17</RequestId> <Status>1</Status> <CalendarId>2:25</CalendarId> </Result> </MeetingResponse>
MS-Server-ActiveSync: 14.0
<?xml version="1.0" encoding="utf-8" ?>
<Result>
<CalendarId>2:25</CalendarId>
</Result>
The RequestId element specifies the meeting request that the client is responding to. If the meeting invitation is accepted or tentatively accepted, the server adds or updates the corresponding Calendar item and returns the item's server ID in the CalendarId element of the response.
The following table lists the possible values for the Status element.
Server response
Client action
The request succeeded.
InvalidMeetingRequest
This response indicates that the request is invalid. The client should not retry the request, as it is unlikely to succeed.
The server sends this response if the item sent to the server is not a valid meeting.
ErrorOccurredOnMailbox
This error is returned when client sync state is missing or corrupt on the server. The client can retry once right away, but should retry slowly after that, about once an hour. If the request still fails after an extended period, the client should stop retrying.
ErrorOccurredOnExchangeServer
This error indicates that the meeting request can't be processed. The meeting request may be missing, the meeting may have been canceled, or this may be a delegate meeting to which the user can't respond. If the client retries the request, it is unlikely to succeed.
Note: The Exchange ActiveSync client should handle the response to the MeetingResponse command in the same way that it handles the status responses to email commands.
When an invitee responds from the Inbox item, the Exchange server deletes the meeting invitation from the Inbox. The invitee can, however, change their response to the meeting request from the Calendar item with new MeetingResponse command. If the user declines the meeting, the server deletes the Calendar item, and it can no longer be used to respond to the meeting request.
The Exchange server automatically deletes the email invitation from the Inbox after the user has responded to the request. When the Exchange ActiveSync client syncs the Deleted Items folder, the deleted item is automatically added to the Deleted Items folder on the client.
Users respond to a meeting request from the Calendar folder in the same way that they respond to the request from the Inbox. The client uses the MeetingResponse command, but in this case, the RequestId element value indicates the Calendar item. This option is only available in Exchange ActiveSync version 14.0 and later versions. Just like when the user responds from the Inbox, the meeting request item in the Inbox is automatically deleted by the server when the user responds from the Calendar item.
When the user responds to the meeting request, the original tentative Calendar item is deleted. If the user declines the meeting request, the server does not add a new item to the Calendar. If the user accepts or tentatively accepts the meeting request, the server creates a new Calendar item with the status as indicated by the user. The following example shows the sync process for the Calendar collection, after the user has accepted the meeting request. The original meeting item is deleted, and new item with a status of Accepted is added in its place. The UID element value of the new accepted item is identical to the value of the tentative placeholder item.
HTTP/1.1 200 OK Content-Type: application/vnd.ms-sync.wbxml <?xml version="1.0" encoding="utf-8"?> <Sync > <Collections> <Collection> <SyncKey>1598194209</SyncKey> <CollectionId>2</CollectionId> <Status>1</Status> <Commands> <Add> <ServerId>2:25</ServerId> <ApplicationData> <calendar:TimeZone>4AEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsAAAABAA IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAACAAIAAA AAAAAAxP///w==</calendar:TimeZone> <calendar:DtStamp>20110510T185139Z</calendar:DtStamp> <calendar:StartTime>20110510T170000Z</calendar:StartTime> <calendar:Subject>Quarterly Planning</calendar:Subject> <calendar:UID>A3561BDAAE8E4B30AC255FD3F31A3AD7000000000000000000000 00000000000</calendar:UID> <calendar:OrganizerName>Alice </calendar:OrganizerName> <calendar:OrganizerEmail>alice@contoso.com</calendar:OrganizerEmail> <calendar:Attendees> <calendar:Attendee> <calendar:Email>bob@contoso.com</calendar:Email> <calendar:Name>Bob </calendar:Name> <calendar:AttendeeType>1</calendar:AttendeeType> </calendar:Attendee> </calendar:Attendees> <calendar:Location>Office</calendar:Location> <calendar:EndTime>20110510T180000Z</calendar:EndTime> <airsyncbase:Body> <airsyncbase:Type>1</airsyncbase:Type> <airsyncbase:EstimatedDataSize>127</airsyncbase:EstimatedDataSize> <airsyncbase:Truncated>1</airsyncbase:Truncated> </airsyncbase:Body> <calendar:Sensitivity>0</calendar:Sensitivity> <calendar:BusyStatus>2</calendar:BusyStatus> <calendar:AllDayEvent>0</calendar:AllDayEvent> <calendar:Reminder>15</calendar:Reminder> <calendar:MeetingStatus>3</calendar:MeetingStatus> <airsyncbase:NativeBodyType>3</airsyncbase:NativeBodyType> <calendar:ResponseRequested>1</calendar:ResponseRequested> <calendar:AppointmentReplyTime>20110506T165252Z</AppointmentReplyTime> <calendar:ResponseType>3</calendar:ResponseType> </ApplicationData> </Add> <Delete> <ServerId>2:24</ServerId> </Delete> </Commands> </Collection> </Collections> </Sync>
<Sync >
<Collections>
<Collection>
<SyncKey>1598194209</SyncKey>
<CollectionId>2</CollectionId>
<Commands>
<Add>
<ServerId>2:25</ServerId>
<ApplicationData>
<calendar:TimeZone>4AEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsAAAABAA
IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAACAAIAAA
AAAAAAxP///w==</calendar:TimeZone>
<calendar:DtStamp>20110510T185139Z</calendar:DtStamp>
<calendar:StartTime>20110510T170000Z</calendar:StartTime>
<calendar:Subject>Quarterly Planning</calendar:Subject>
<calendar:UID>A3561BDAAE8E4B30AC255FD3F31A3AD7000000000000000000000
00000000000</calendar:UID>
<calendar:OrganizerName>Alice </calendar:OrganizerName>
<calendar:OrganizerEmail>alice@contoso.com</calendar:OrganizerEmail>
<calendar:Attendees>
<calendar:Attendee>
<calendar:Email>bob@contoso.com</calendar:Email>
<calendar:Name>Bob </calendar:Name>
<calendar:AttendeeType>1</calendar:AttendeeType>
</calendar:Attendee>
</calendar:Attendees>
<calendar:Location>Office</calendar:Location>
<calendar:EndTime>20110510T180000Z</calendar:EndTime>
<airsyncbase:Body>
<airsyncbase:Type>1</airsyncbase:Type>
<airsyncbase:EstimatedDataSize>127</airsyncbase:EstimatedDataSize>
<airsyncbase:Truncated>1</airsyncbase:Truncated>
</airsyncbase:Body>
<calendar:Sensitivity>0</calendar:Sensitivity>
<calendar:BusyStatus>2</calendar:BusyStatus>
<calendar:AllDayEvent>0</calendar:AllDayEvent>
<calendar:Reminder>15</calendar:Reminder>
<calendar:MeetingStatus>3</calendar:MeetingStatus>
<airsyncbase:NativeBodyType>3</airsyncbase:NativeBodyType>
<calendar:ResponseRequested>1</calendar:ResponseRequested>
<calendar:AppointmentReplyTime>20110506T165252Z</AppointmentReplyTime>
<calendar:ResponseType>3</calendar:ResponseType>
</ApplicationData>
</Add>
<Delete>
<ServerId>2:24</ServerId>
</Delete>
</Commands>
</Collection>
</Collections>
</Sync>
The client has to sync the Calendar folder after the user accepts or tentatively accepts a meeting request in order for the new Calendar item to appear on the user's Calendar.
If the user declines the meeting, the Exchange server automatically deletes the corresponding Calendar item. The client must not delete the Calendar item on behalf of the user.
When a user declines a meeting request, the response does not contain a meetingresponse:CalendarId element because the server deletes the corresponding Calendar item.
The client sends a notification to the meeting organizer if the user chooses to send a response. The client uses the SendMail command to send the notification. The client should send the email notification only after the MeetingResponse command finishes successfully; otherwise, the invitee's Calendar and the status information that the invitee reports to the organizer will be in conflict. If the ResponseRequested element is set to 0 (false) on the meeting request, the client does not expose an option to the user to send a response notification to the organizer.
The client indicates its response in the subject of the email message, as well by using an iCalendar reply command, as shown in the following example.
POST /Microsoft-Server-ActiveSync?Cmd=SendMail&User=Bob&DeviceId=ABCDEF&DeviceType=SmartPhone HTTP/1.1 Content-Type: application/vnd.ms-sync.wbxml MS-ASProtocolVersion: 14.0 Host: mail.contoso.com <?xml version="1.0" encoding="utf-8" ?> <SendMail xmlns="ComposeMail:"> <ClientId>13554</ClientId> <SaveInSentItems/> <Mime> Subject: Accepted: Quarterly Planning From: Bob@contoso.com Content-Type: multipart/alternative; boundary=NextPart To: Alice <Alice@contoso.com> --NextPart Content-Type: text/plain; charset=us-ascii Sure, I will be there! --NextPart Content-Type: text/calendar; charset=utf-8; name=meeting.ics; method=REPLY Content-Transfer-Encoding: quoted-printable BEGIN:VCALENDAR…<more iCalendar content follows> </Mime> </SendMail>
POST /Microsoft-Server-ActiveSync?Cmd=SendMail&User=Bob&DeviceId=ABCDEF&DeviceType=SmartPhone HTTP/1.1
<SendMail xmlns="ComposeMail:">
<ClientId>13554</ClientId>
<SaveInSentItems/>
<Mime>
Subject: Accepted: Quarterly Planning
From: Bob@contoso.com
Content-Type: multipart/alternative;
boundary=NextPart
To: Alice <Alice@contoso.com>
--NextPart
Content-Type: text/plain;
charset=us-ascii
Sure, I will be there!
Content-Type: text/calendar;
charset=utf-8;
name=meeting.ics;
method=REPLY
Content-Transfer-Encoding: quoted-printable
BEGIN:VCALENDAR…<more iCalendar content follows>
</Mime>
</SendMail>
The following table lists the possible response types.
Response type
Email /subject
iCalendar reply method
Accepted: <meeting request subject>
ATTENDEE;PARTSTAT=ACCEPTED:MAILTO:<organizer>
TenativelyAccepted
Tenative: <meeting request subject>
ATTENDEE;PARTSTAT=TENTATIVE:MAILTO:<organizer>
Declined: <meeting request subject>
ATTENDEE;PARTSTAT=DECLINED:MAILTO:<organizer>
If the organizer makes updates to the meeting, the Exchange ActiveSync client might receive multiple meeting notification email messages. All mail items that are related to the same meeting have the same GlobalObjId element value (for the email notification) and the same UID element value (for the Calendar item). If the Exchange ActiveSync client receives multiple updates that share the same ID, it is important for the client to enable the user to respond to the most recent item only based on the DtStamp value.
After the invitees have responded to the meeting request, the organizer might want to determine the status of the responses. The organizer can view the responses in the Inbox as they arrive from individual invitees. In addition, the Exchange server automatically parses the invitee responses and updates the Calendar item accordingly. The organizer can view the response status on the Calendar item based on updates from the server to the Exchange ActiveSync client.
As invitees respond to the meeting request, the organizer's Exchange ActiveSync client runs a Sync command on the Inbox folder to discover the responses, as shown in the following example.
HTTP/1.1 200 OK Content-Type: application/vnd.ms-sync.wbxml <?xml version="1.0" encoding="utf-8"?> <Sync> <Collections> <Collection> <SyncKey>378940377</SyncKey> <CollectionId>6</CollectionId> <Status>1</Status> <Commands> <Add> <ServerId>6:22</ServerId> <ApplicationData> <email:To>"Alice" <alice@contoso.com></email:To> <email:From>"Bob" <bob@contoso.com></email:From> <email:Subject>Accepted: Quarterly Planning</email:Subject> <email:DateReceived>20110506T165454Z</email:DateReceived> <email:DisplayTo>Alice </email:DisplayTo> <email:ThreadTopic>Quarterly Planning</email:ThreadTopic> <email:Importance>1</email:Importance> <email:Read>0</email:Read> <airsyncbase:Body> <airsyncbase:Type>1</airsyncbase:Type> <airsyncbase:EstimatedDataSize>0</airsyncbase:EstimatedDataSize> <airsyncbase:Truncated>1</airsyncbase:Truncated> </airsyncbase:Body> <email:MessageClass>IPM.Schedule.Meeting.Resp.Pos</email:MessageClass> <email:MeetingRequest> <email:AllDayEvent>0</email:AllDayEvent> <email:StartTime>20110510T17000000Z</email:StartTime> <email:DtStamp>20110506T165252Z </email:DtStamp> <email:EndTime>20110510T180000Z</email:EndTime> <email:InstanceType>0</email:InstanceType> <email:Location>Office</email:Location> <email:Organizer>"Bob " <bob@contoso.com></email:Organizer> <email:Sensitivity>0</email:Sensitivity> <email:TimeZone>4AEAACgAVQBUAEMALQAwADgAOgAwADAAKQAgAFAAYQBjAGkAZgBpAGM AIABUAGkAbQBlACAAKABVAFMAIAAmACAAQwAAAAsAAAABAAIAAAAAAAAAAAAAACgAV QBUAEMALQAwADgAOgAwADAAKQAgAFAAYQBjAGkAZgBpAGMAIABUAGkAbQBlACAAKABVAF MAIAAmACAAQwAAAAMAAAACAAIAAAAAAAAAxP///w==</email:TimeZone> <email:GlobalObjId> BAAAAIIA4AB0xbcQGoLgCAAAAAAAAAAAAAAAAAAAAAAAAAAATQAAAHZD YWwtVWlkAQAAAEEzNTYxQkRBQUU4RTRCMzBBQzI1NUZEM0YzMUEzQUQ3MDAwMDAwMDA wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAA</email:GlobalObjId> </email:MeetingRequest> <email:InternetCPID>20127</email:InternetCPID> <email:Flag /> <email:ContentClass>urn:content-classes:calendarmessage</email:ContentClass> <airsyncbase:NativeBodyType>1</airsyncbase:NativeBodyType> <email2:ConversationId>(Uí©E¯*O»F n Ô</email2:ConversationId> <email2:ConversationIndex>Ì1ë¯��4E</email2:ConversationIndex> <email:Categories /> </ApplicationData> </Add> </Commands> </Collection> </Collections> </Sync>
<Sync>
<SyncKey>378940377</SyncKey>
<ServerId>6:22</ServerId>
<email:To>"Alice" <alice@contoso.com></email:To>
<email:From>"Bob" <bob@contoso.com></email:From>
<email:Subject>Accepted: Quarterly Planning</email:Subject>
<email:DateReceived>20110506T165454Z</email:DateReceived>
<email:DisplayTo>Alice </email:DisplayTo>
<email:ThreadTopic>Quarterly Planning</email:ThreadTopic>
<email:Importance>1</email:Importance>
<email:Read>0</email:Read>
<airsyncbase:EstimatedDataSize>0</airsyncbase:EstimatedDataSize>
<email:MessageClass>IPM.Schedule.Meeting.Resp.Pos</email:MessageClass>
<email:MeetingRequest>
<email:AllDayEvent>0</email:AllDayEvent>
<email:StartTime>20110510T17000000Z</email:StartTime>
<email:DtStamp>20110506T165252Z </email:DtStamp>
<email:EndTime>20110510T180000Z</email:EndTime>
<email:InstanceType>0</email:InstanceType>
<email:Location>Office</email:Location>
<email:Organizer>"Bob " <bob@contoso.com></email:Organizer>
<email:Sensitivity>0</email:Sensitivity>
<email:TimeZone>4AEAACgAVQBUAEMALQAwADgAOgAwADAAKQAgAFAAYQBjAGkAZgBpAGM
AIABUAGkAbQBlACAAKABVAFMAIAAmACAAQwAAAAsAAAABAAIAAAAAAAAAAAAAACgAV
QBUAEMALQAwADgAOgAwADAAKQAgAFAAYQBjAGkAZgBpAGMAIABUAGkAbQBlACAAKABVAF
MAIAAmACAAQwAAAAMAAAACAAIAAAAAAAAAxP///w==</email:TimeZone>
<email:GlobalObjId> BAAAAIIA4AB0xbcQGoLgCAAAAAAAAAAAAAAAAAAAAAAAAAAATQAAAHZD
YWwtVWlkAQAAAEEzNTYxQkRBQUU4RTRCMzBBQzI1NUZEM0YzMUEzQUQ3MDAwMDAwMDA
wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAA</email:GlobalObjId>
</email:MeetingRequest>
<email:InternetCPID>20127</email:InternetCPID>
<email:Flag />
<email:ContentClass>urn:content-classes:calendarmessage</email:ContentClass>
<airsyncbase:NativeBodyType>1</airsyncbase:NativeBodyType>
<email2:ConversationId>(Uí©E¯*O»F n Ô</email2:ConversationId>
<email2:ConversationIndex>Ì1ë¯��4E</email2:ConversationIndex>
<email:Categories />
Note that the ApplicationData container of the response that is synced to the organizer's Inbox contains To and From fields however, the values of these elements are different than the values in the original meeting request. In the response message, the To field indicates the organizer, because the organizer is the recipient of the response, while the From field indicates the invitee.
The MessageClass and Subject elements indicate the invitee's response to the request, as set by the client. The following are the possible values for the MessageClass element:
· IPM.Schedule.Meeting.Resp.Pos
· IPM.Schedule.Meeting.Resp.Tent
· IPM.Schedule.Meeting.Resp.Neg.
Important: The organizer's Exchange ActiveSync client must sync the Calendar folder in order to receive the meeting responses from meeting invitees. The organizer's mailbox uses the Calendar item to reconcile responses to a meeting request with the Calendar event.
When the Exchange ActiveSync client syncs the organizer's Calendar folder, the original meeting item is updated to reflect any new or updated invitee responses. The client can then display the invitee status to the organizer. The following example shows a change in an attendee, Bob's, status after he accepts the meeting invitation. Note that the Calendar item shows a value of 3 for the AttendeeStatus element, rather than 0, which was the value when the request was created and before a response was received.
HTTP/1.1 200 OK Content-Type: application/vnd.ms-sync.wbxml <?xml version="1.0" encoding="utf-8"?> <Sync> <Collections> <Collection> <SyncKey>124536913</SyncKey> <CollectionId>2</CollectionId> <Status>1</Status> <Commands> <Change> <ServerId>2:9</ServerId> <ApplicationData> <calendar:Attendees> <calendar:Attendee> <calendar:Email>bob@contoso.com</calendar:Email> <calendar:Name>Bob </calendar:Name> <calendar:AttendeeStatus>3</calendar:AttendeeStatus> <calendar:AttendeeType>1</calendar:AttendeeType> </calendar:Attendee> </calendar:Attendees> </ApplicationData> </Change> </Commands> </Collection> </Collections> </Sync>
<SyncKey>124536913</SyncKey>
<Change>
<ServerId>2:9</ServerId>
<calendar:AttendeeStatus>3</calendar:AttendeeStatus>
</Change>
The following table lists the possible values for the AttendeeStatus element.
AttendeeStatus element value
0
No response
Accept
Decline
Other
When the organizer creates the meeting request, the AttendeeStatus element is set to 0 because no invitees have yet responded. As the response notifications arrive, the organizer’s Exchange server interprets the iCalendar content in the response messages and updates the AttendeeStatus value for each attendee accordingly. An AttendeeStatus value of 5 indicates a problem with interpreting the invitee response.
Exchange ActiveSync does not handle responses involving new time proposals. New time proposals appear as tentative or decline responses to the Exchange ActiveSync client. The new time proposal may be indicated in the subject line or the body of the message, depending on the client that the invitee uses to send the proposal.
Note: After an invitee responds to a request, the Exchange server deletes the meeting request from the invitee's mailbox. This helps to ensure that the invitee does not send multiple responses to the same meeting request that might conflict with one another. If the invitee does send multiple responses to the meeting request (for example, by responding from the Calendar item rather than the meeting invitation), the Exchange server automatically updates the organizer's Calendar item to reflect the most recent meeting response status.
The ability to respond to meeting requests is a critical element of a successful calendaring experience for Exchange ActiveSync client users. When you develop your Exchange ActiveSync client applications, make sure that you handle iCalendar meeting responses correctly. Keep in mind that your applications should not process incoming iCalendar meeting requests on the client; meeting requests should be processed by the Exchange server.
[MS-ASEMAIL]: ActiveSync Email Class Protocol Specification
[MS-ASCAL]: ActiveSync Calendar Class Protocol Specification
[MS-ASCMD]: ActiveSync Email Command Reference Protocol Specification
[MS-ASDTYPE]: ActiveSync Data Types
[MS-OXGLOS]: Exchange Server Protocols Master Glossary
[MS-OXCICAL]: iCalendar to Appointment Object Conversion Protocol Specification
Post authored by: Katarzyna Puchala, Microsoft Corporation
In this post, we are using Exchange ActiveSync protocol version 14.1. Where applicable, we note differences between protocol versions.
Meeting requests are important for information workers who use Microsoft Exchange. Meeting requests inform attendees of a meeting, automatically book meeting time on the organizer's and attendees' calendars, provide reminders for meetings, and enable the booking of conference rooms. This post provides information for developers about working with meeting requests, including the following topics:
The following figure shows an overview of the meeting request process and the two key scenarios involved. In this example, Exchange ActiveSync user Alice requests a meeting with Bob from her Exchange ActiveSync client. Bob sees the meeting request on his Exchange ActiveSync device.
Figure 1: Meeting request process
A meeting starts out as a meeting request. The meeting organizer requests that attendees agree to participate in the meeting at a specified date, time, and location. Meeting requests are composed of the following two elements:
1. A calendar item that reflects the proposed meeting on the organizer's and invitees' calendars.
2. An invitation email sent by the organizer to invitees to notify them of the proposed meeting and solicit their responses.
In order for a user to create meeting requests, an Exchange ActiveSync client must do the following:
After the Exchange ActiveSync client sends an email message that includes the meeting invitation, the Exchange server sends the invitation and saves a copy in the Sent Items folder. The following figure shows the client requests and server responses when a user, Alice, creates a meeting request from her Exchange ActiveSync client. The syncing of the Sent Items folder is optional.
Figure 2: Sending a meeting request from an Exchange ActiveSync client
Important: The client must sync the Calendar folder before the user can create meeting requests. This adds the calendar item to the organizer's calendar. The organizer's mailbox requires the calendar item to reconcile responses to the meeting request.
When a user organizes a new meeting on the Exchange ActiveSync client, the client must create a meeting item on the organizer's calendar. The client adds the new calendar item to the Calendar collection. The calendar item contains all the meeting details, including meeting attendees. The following example shows an Exchange ActiveSync Sync command XML request that adds a meeting to Alice's calendar when she organizes a meeting and invites Bob.
<? xml version="1.0" encoding="utf-8"?>
< Collections>
<SyncKey>85086007 </SyncKey>
<ClientId>1574070035</ClientId>
<calendar:TimeZone>4AEAAFAAYQBjAGkAZgBpAGMAIABTAHQAYQBuAGQAYQByAGQAIABUAGkAbQBlAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAsAAAABAA
IAAAAAAAAAAAAAAFAAYQBjAGkAZgBpAGMAIABEAGEAeQBsAGkAZwBoAHQAIABUAGkAbQBlAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAMAAAACAAIAA AAAAAAAxP///w==</calendar:TimeZone>
<calendar:DtStamp>20110504T152200Z</calendar:DtStamp>
<calendar:UID>A3561BDAAE8E4B30AC255FD3F31A3AD700000000000000000000000000000000</calendar:UID>
<calendar:Name>Bob</calendar:Name>
<calendar:AttendeeStatus>0</calendar:AttendeeStatus>
<airsyncbase:Type>3</airsyncbase:Type>
<airsyncbase:Data>Let's meet to plan the budget for the next quarter.
</airsyncbase:Data>
<calendar:Reminder>5</calendar:Reminder>
<calendar:MeetingStatus>1</calendar:MeetingStatus>
For a list of and information about the Calendar schema elements for Exchange ActiveSync, see [MS-ASCAL]: ActiveSync Calendar Class Protocol Specification section 2.2.2.
In the meeting request, the Exchange ActiveSync client must specify the start time and end time of the proposed event; this information is included in the StartTime and EndTime elements. Both dates have to be valid values of the dateTime type, as described in [MS-ASDTYPE]: ActiveSync Data Types section 2.3. All dates must be specified in Coordinated Universal Time (UTC), without any punctuation separators. Optionally, the client can use the DtStamp element to specify when the calendar item was created.
The client should specify the time zone in the request. If the time zone is not specified, the Exchange server uses its current time zone for the meeting. For more information about the format of the time zone, see [MS-ASDTYPE] section 2.6.4.
Optionally, the client can mark the organizer's calendar by specifying the BusyStatus element. The following are the possible values for the BusyStatus element:
· 0 – Free
· 1 – Tentative
· 2 – Busy
· 3 – Out of office
If the organizer did not explicitly specify his or her attendance status, the client should use a value of 2 for the BusyStatus element to mark the meeting status as busy. If the client does not provide this value, the server uses a busy status by default.
Important: As a best practice, the client should always provide a value for the optional UID element. The UID element value is a random hexadecimal ID that the client generates when it creates the calendar item. The maximum length of the UID element value is 300 characters. We strongly recommend that the Exchange ActiveSync client include the UID element because it helps to map the calendar item to the email notifications sent for the meeting. This enables the organizer to track meeting updates and responses to the meeting request.
The client should provide a MeetingStatus element for meetings. When the client saves a meeting to the organizer's calendar, it should set the value of this element to 1, which indicates that the item is a meeting.
A meeting must include the Attendees element, which contains a collection of Attendee elements. Each Attendee element must include at least one Email and one Name element; these contain the name and email address of the attendee. Optionally, the Attendee element can include values for the AttendeeStatus and AttendeeType elements. When the meeting is created, the AttendeeStatus element contains a value of 0. This value changes when attendees respond to the meeting request. If present, the AttendeeType element must be set to one of the following values:
· 1 – Required
· 2 – Optional
· 3 – Resource
The Exchange server sends a response to the Exchange ActiveSync client's request. The response indicates the status of the Calendar Sync command operation as well as the status of the individual meeting request. If the item was added correctly (as indicated by a Status element value of 1 in the response for both the item and the collection), the server issues a ServerId element value for the item in lieu of the temporary ClientId element value that the client assigned to it, as shown in the following example.
< Sync>
<SyncKey>1042177286 </SyncKey>
<Responses>
</Responses>
The client has to associate the newly issued ServerId value with this calendar item. For more information about status response values, see [MS-ASCMD]: ActiveSync Command Reference Protocol Specification.
Note: Exchange ActiveSync clients should not allow the organizer to respond to meetings that he or she organized
The email notification must make it clear to the recipients that its purpose is to inform them of the meeting request. It can also optionally solicit invitee responses to the request, and automatically block the meeting time on prospective attendees' calendars.
Exchange ActiveSync clients use the SendMail command to send MIME-formatted email messages to the server, including calendaring information structured according to a known calendaring format.
The iCalendar format is the most common calendaring format; this format is supported by a variety of clients. The following example shows the Exchange ActiveSync SendMail request that Alice's Exchange ActiveSync client sends.
POST /Microsoft-Server-ActiveSync/default.eas?Cmd=SendMail&User=Alice&DeviceId=ABCDEFGH&DeviceType=SmartPhone HTTP/1.1
Content-Length: 2100
User-Agent: SmartPhone
RequestBody :
<SendMail xmlns="ComposeMail:" >
<ClientId>1248</ClientId>
<Mime>MIME-Version: 1.0
Subject: Quarterly Planning
Thread-Topic: Quarterly Planning
To: Bob <bob@contoso.com>
boundary="---Next Part---"
-----Next Part---
Content-Type: text/plain; charset="utf-8"
Let's discuss the budget for the next quarter.
Content-Type: text/calendar; charset="utf-8"; method=REQUEST
Content-Transfer-Encoding: base64
QkVHSU46VkNBTEVOREFSDQpNRVRIT0Q6UkVRVUVTVA0K… <Abbreviated>
The email message contains multiple parts. The message may contain a plain text part, which includes the body text of the meeting request. Several different calendar request formats are available for meeting request messages. Microsoft Exchange supports the iCalendar and TNEF formats. Each of these formats are included in a separate MIME part in the meeting request message. (For more information about MIME, see RFC 2045, RFC 2046, and RFC 2047.) Most clients use the iCalendar format for the meeting request, encoded in base64. Meeting requests have a content type of text/calendar with the method parameter set to “REQUEST”. The following section provides more detail about the iCalendar format.
The iCalendar format is a file format (extension .ics, .ical) that represents calendaring information such as meeting requests, meeting responses, and free/busy information. For more information about this format, see RFC 2445, RFC 5546, and [MS-OXCICAL]: iCalendar to Appointment Object Conversion Protocol Specification.
This standard enables users of different calendaring systems (including clients and servers) to exchange calendaring information. iCalendar information is transported across the Internet in MIME format. The MIME body that contains the iCalendar information has a content type of text/calendar. The following example shows a typical iCalendar meeting request.
BEGIN:VCALENDAR
METHOD:REQUEST
PRODID: SmartPhone
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Pacific Standard Time
BEGIN:STANDARD
DTSTART:20000101T020000
TZOFFSETFROM:-0700
TZOFFSETTO:-0800
RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=1SU;BYMONTH=11
END:STANDARD
BEGIN:DAYLIGHT
TZOFFSETFROM:-0800
TZOFFSETTO:-0700
RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=2SU;BYMONTH=3
END:DAYLIGHT
END:VTIMEZONE
BEGIN:VEVENT
UID:A3561BDAAE8E4B30AC255FD3F31A3AD700000000000000000000000000000000
ORGANIZER:MAILTO:alice@contoso.com
ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION:MAILTO:bob@contoso.com
STATUS:CONFIRMED
X-MICROSOFT-CDO-ALLDAYEVENT:FALSE
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER:-PT15M
END:VALARM
SUMMARY: Quarterly Planning
LOCATION:
DTSTART;TZID=Pacific Standard Time:20110510T100000
DTEND;TZID=Pacific Standard Time:20110510T110000
DTSTAMP: 20110504T152200Z
LAST-MODIFIED: 20110504T152200Z
CLASS:PUBLIC
END:VEVENT
END:VCALENDAR
Important: The UID element value that is included in the iCalendar request email message must match the UID value that is saved with the meeting item on the organizer's calendar.
The response to SendMail command has no XML body (Content-Length = 0) if the SendMail command finishes successfully, as shown in the following example.
MS-Server-ActiveSync: 14.1
The server first responds to the SendMail request from the organizer's Exchange ActiveSync client, and then tries to send the message to the attendees. For this reason, a positive response to the SendMail request does not guarantee that the message was sent out successfully. The Exchange ActiveSync client can still receive a non-delivery report notification if the mail recipients are not found. For more information about the SendMail status values, see [MS-ASCMD] section 2.2.3.152.13. Non-delivery report responses should be handled in the same way that email responses are handled.
Before the Exchange server sends the email message, it interprets the iCalendar information and structures the message to the attendees to reflect that it is a meeting request.
Note: Exchange ActiveSync clients should not save meeting request messages directly to the local Sent Items folder; instead, clients should use the SaveInSentItems element in the SendMail request to automatically save the messages on the server. It is not possible to reconcile the local Sent Items folder with the server's Sent Items folder by using the Sync command. Items in the server's Sent Items folder can be added to the client by using the Sync command, but items that are in the Exchange ActiveSync client's local Sent Items folder cannot be added to the server.
After the Exchange ActiveSync client submits the meeting request email to the server, the Exchange server sends the email message to all the invited attendees. In addition, the Exchange server parses the iCalendar information that is embedded in the email. This way, it adds the email message to the Sent Items folder as the appropriate type; that is, a meeting request. The next time the Exchange ActiveSync client syncs the Sent Items folder, the meeting request email message will be added to the Sent Items folder on the client.
The client syncs the Sent Items folder as shown in the following example.
POST /Microsoft-Server-ActiveSync?Cmd=Sync &User=alice&DeviceId=ABCDEFGH&DeviceType =SmartPhone HTTP/1.1
<Sync xmlns="AirSync:">
<SyncKey>612092836</SyncKey>
<CollectionId>10</CollectionId>
<DeletesAsMoves>1</DeletesAsMoves>
<GetChanges>1</GetChanges>
<WindowSize>512</WindowSize>
The server adds a new item with the MessageClass element set to IPM.Schedule.Meeting.Request, as shown in the following example. This item contains all the meeting details.
<? xml version="1.0" encoding="utf-8" ?>
<SyncKey>333054644</SyncKey>
<ServerId>10:20</ServerId>
<email:To>"Bob" <bob@contoso.com></email:To>
<email:From>"Alice" <alice@contoso.com></ email:From>
<email:Subject>Quarterly Planning</email:Subject>
<email:DateReceived>2011-05-10T18:52:57.298Z</A2:DateReceived>
<email:DisplayTo>”Bob”</ email:DisplayTo>
<email:Read>1</email:Read>
<airsyncbase:EstimatedDataSize>117</airsyncbase:EstimatedDataSize>
<email:MessageClass>IPM.Schedule.Meeting.Request</email:MessageClass>
<email:StartTime>2011-05-10T19:00:00.000Z</email:StartTime>
<email:DtStamp>2011-05-10T18:52:58.770Z</email:DtStamp>
<email:EndTime>2011-05-10T20:00:00.000Z</email:EndTime>
<email:Organizer>"Alice" <alice@contoso.com></ email:Organizer>
<email:TimeZone>4AEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsAAAABAAIAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAACAAIAAAAAAAAAxP///w==</email:TimeZone>
<email:GlobalObjId> BAAAAIIA4AB0xbcQGoLgCAAAAAAAAAAAAAAAAAAAAAAAAAAATQA
AAHZDYWwtVWlkAQAAAEEzNTYxQkRBQUU4RTRCMzBBQzI1NUZEM0YzMUEzQUQ3MDAw
MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAA</email:GlobalObjId>
<email:MeetingMessageType>1</email:MeetingMessageType>
<email:InternetCPID>20127</email:InternetCPID >
<email2:ConversationId>A0B01C50859A444590FE77CF0568F16E</email:ConversationId>
<email2:ConversationIndex>01CC0F437A</email:ConversationIndex>
<email2:Sender>"Alice" <alice@contoso.com></ email:Sender>
The meeting request email that is sent to the attendees is of type IPM.Schedule.MeetingRequest and contains a MeetingRequest container. (For more information about the MeetingRequest container, see [MS-ASEMAIL]: ActiveSync E-Mail Class Protocol Specification section 2.2.2.14). This container describes the properties of the meeting. In addition, it now contains the GlobalObjId element value that was assigned to the meeting item by the server.
The GlobalObjId element value identifies the meeting request and allows the client to determine whether it corresponds to an existing object in the Calendar. For more information about the GlobalObjId element, see [MS-ASEMAIL] section 2.2.2.14.15. The UID element value assigned to the calendar item by the Exchange ActiveSync client is included in the GlobalObjId element value that the server returns. The GlobalObjId element value does not change when the meeting is updated. This enables the client to identify which meeting a particular notification corresponds to.
This meeting request message that is added to the organizer's Sent Items folder should not expose any response options to the user because it is in the organizer's mailbox.
When an organizer sends a meeting request, the invitees' Exchange ActiveSync client must be able to receive the request, interpret it, and present it to the invitee as a meeting invitation. The meeting request should appear in the invitee's Inbox, and a placeholder Calendar item for the meeting should appear on the invitee's Calendar. The invitee should be able to accept, tentatively accept, or decline the meeting request, either from the meeting invitation or from the Calendar placeholder item, and send his or her response the meeting organizer.
The following figure shows the operations involved in sending a meeting request to an Exchange ActiveSync client. In this example, Bob is the meeting invitee.
Figure 3: Sending a meeting request to an Exchange ActiveSync client
When the meeting invitation first arrives in the invitee's mailbox, it is in the form of a meeting request in the Inbox.
The Exchange ActiveSync client receives the meeting request upon issuing a Sync command request for the invitee's Inbox. We recommend that Exchange ActiveSync clients request body items in HTML format by setting the BodyPreference element to 2. HTML provides rich content formatting that the client can then render. The meeting request is shown in the following example.
POST /Microsoft-Server-ActiveSync?Cmd=Sync&User =bob&DeviceId=HGFEDCBA &DeviceType=SmartPhone HTTP/1.1
<SyncKey>1530765051</SyncKey>
<Options>
<airsyncbase:BodyPreference>
<airsyncbase:Type>2</airsyncbase:Type>
</airsyncbase:BodyPreference>
</Options>
The organizer's Exchange server converts the item's iCalendar information and parses it into a message class of IPM.Schedule.Meeting.Request, which is then synced to the invitee's Inbox, as shown in the following example.
Note: The Exchange ActiveSync client should not attempt any iCalendar content conversion. The Exchange server converts the iCalendar format into the appropriate message class. If the message cannot be converted, it will be delivered as an attachment.
<SyncKey>1473331151</SyncKey>
<ServerId>6:17</ServerId>
<email:To>"Bob" <bob@contoso.com></ email:To>
<email:From>"Alice" <alice@contoso.com></email:From>
<email:DateReceived>20110504T152300Z</email:DateReceived>
<email:DisplayTo>Bob </A2:DisplayTo>
<email:ThreadTopic>Quarterly Planning</A2:ThreadTopic>
<email:Importance>1</A2:Importance>
<email:Read>0</A2:Read>
<airsyncbase:EstimatedDataSize>800</airsyncbase:EstimatedDataSize>
<airsyncbase:Data>
< html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="Generator" content="Microsoft Exchange Server">
<!-- converted from rtf -->
<style><!-- .EmailQuote { margin-left: 1pt; padding-left: 4pt; border-left: #800000 2px
solid; } --
></style>
</head>
<body>
<font face="Times New Roman" size="3"><><a
name="BM_BEGIN"></a>
<div><font face="Courier New">[When]: Tuesday,May 10, 2011 9:00 PM-10:00 PM.
[(UTC-08:00) Pacific
Time (US &amp; Canada)]<br>
[Where]: Office<br>
<br>
*~*~*~*~*~*~*~*~*~*<br>
</font></div>
<div><font face="Tahoma" size="2"><>Let's meet to
plan the budget for the next quarter.<></font></div>
<></font>
</body>
</html>
<email:StartTime>20110510T170000Z</email:StartTime>
<email:DtStamp>20110504T152200Z </email:DtStamp>
<email:Organizer>"Alice " <alice@contoso.com></ email:Organizer>
<email:ResponseRequested>1</email:ResponseRequested>
<email:BusyStatus>2</email:BusyStatus>
<email:TimeZone>4AEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsAAAABAAIAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAMAAAACAAIAAAAAAAAAxP///w==</email:TimeZone>
<email:GlobalObjId> BAAAAIIA4AB0xbcQGoLgCAAAAAAAAAAAAAAAAAAAAAAAAAAATQAAAHZDYWwtV
WlkAQAAAEEzNTYxQkRBQUU4RTRCMzBBQzI1NUZEM0YzMUEzQUQ3MDAwMDAwMDA
<email:InternetCPID>28591</A2:InternetCPID>
<email2:ConversationId>AF47F6E22518E64C800FFEA6B901B139</email2:ConversationId>
<email2:ConversationIndex>CC0F434BDC</email2:ConversationIndex>
The MeetingRequest element is an optional container element. The MeetingRequest element is included when the message is a meeting request and the Exchange ActiveSync client's user is an attendee. The MeetingRequest element is not included in the message content of calendar items in the Calendar folder or in regular email messages. If a message contains the MeetingRequest element, the client can respond to the meeting request by using the MeetingResponse command. For more information about this command, see [MS-ASCMD] section 2.2.2.9.
The GlobalObjId element is a required child element of the MeetingRequest element. GlobalObjId is defined as an element in the Email namespace. Clients that need to determine whether the GlobalObjId element for a meeting request corresponds to an existing Calendar object in the Calendar folder have to convert the GlobalObjId element value to a UID element value to make the comparison. For information about how this conversion is done, see [MS-ASEMAIL] section 2.2.2.14.15.
MeetingMessageType is a new element that was added in version 14.1 of the Exchange ActiveSync protocol. The MeetingMessageType element further defines the type of the meeting request. For information about this element, see [MS-ASEMAIL] section 2.2.2.14.17.
The invitee's (Bob's) Exchange ActiveSync client issues a Sync request for the Calendar folder, similar to the one shown in the following example.
POST /Microsoft-Server-ActiveSync?Cmd=Sync&User =bob &DeviceId=HGFEDCBA&DeviceType=SmartPhone HTTP/1.1
<SyncKey>1085571025</SyncKey>
In Microsoft Exchange Server 2007 (which corresponds to Exchange ActiveSync protocol version 12.0) and later versions, the server parses the meeting request received in the invitee's Inbox and adds a tentative meeting to the invitee's calendar to mark the time of the proposed meeting. This tentative meeting is synced to the client.
Based on the meeting request that the Exchange server received, the server created a meeting item in Bob's Calendar folder with the UID element value previously specified by the organizer. Syncing the Calendar collection adds the meeting to the invitee's calendar.
Note: By default, Microsoft Exchange processes meeting requests and automatically add tentative meetings to the invitee's calendar. The Exchange ActiveSync client should not try to create the meeting item, as that will lead to conflicts between the calendar on the device and the calendar on the server. The administrator can disable tentative meeting creation by running the following Windows PowerShell command:
Set-CalendarProcessing -AddNewRequestsTentatively $false -Identity '<domain>/<user>'
In addition, by default, Microsoft Exchange only processes internal meeting requests . The Exchange administrator can allow external meetings to be processed by running the following Windows PowerShell command:
Set-CalendarProcessing -ProcessExternalMeetingMessages $true -Identity '<domain>/<user>'
If the administrator or the user has not changed the default behavior, any meetings received from senders outside the organization will not be processed and will not automatically be added as tentative meetings to the invitee's calendar.
The calendar item contains a UID element value that the organizer's client had set, which correlates to the meeting request in the Inbox via the GlobalObjId element.
<SyncKey>665677459</SyncKey>
<calendar:TimeZone>4AEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsAAAABAAIAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAACAAIAAAAAAA
AAxP///w==</calendar:TimeZone>
<calendar:DtStamp>20110504T152200Z </calendar:DtStamp>
<calendar:StartTime>20110510T180000Z</calendar:StartTime>
<calendar:UID>A3561BDAAE8E4B30AC255FD3F31A3AD700000000000000000
000000000000000</calendar:UID>
<calendar:EndTime>20110510T190000Z</calendar:EndTime>
<airsyncbase:EstimatedDataSize>585</airsyncbase:EstimatedDataSize>
<div> <font face="Tahoma" size="2"><>Let's meet to
<calendar:ResponseType>5</calendar:ResponseType>
The meeting that is added to the invitee's Calendar collection contains all the properties of the calendar item on the organizer's Calendar, as well as the following additional elements:
· OrganizerName
· OrganizerEmail
· ResponseRequested
· MeetingStatus
· ResponseType
The value of the ResponseRequested element comes from the PARTSTAT parameter value of "NEEDS-ACTION" in the original iCalendar meeting request.
When the invitee receives the meeting request, the MeetingStatus element is set to 3, which indicates that the meeting was received, and the ResponseType element is set to 5, to indicate that the invitee has not yet responded to the meeting request. After the invitee responds, the server updates these values to reflect the new status. Stay tuned for our next blog post, "Working with meeting responses in Exchange ActiveSync", for more information about meeting responses.
Creating meeting requests and interpreting them from an Exchange ActiveSync client is critical to ensuring a successful calendaring experience for Exchange ActiveSync client users. It is important to use the correct iCalendar format to create meeting requests and to remember not to try to process incoming iCalendar requests on the client, but instead to allow the Exchange server to process the requests.
[MS-ASEMAIL]: ActiveSync E-Mail Class Protocol Specification
RFC 2045, "Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies"
RFC 2046, "Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types"
RFC 2047, "MIME (Multipurpose Internet Mail Extensions) Part Three: Message Header Extensions for Non-ASCII Text"
RFC 2445, "Internet Calendaring and Scheduling Core Object Specification"
RFC 5546, "iCalendar Transport-Independent Interoperability Protocol (iTIP)"
Network load balancing for Microsoft Exchange Online as part of Microsoft Office 365 ensures that tenant client access loads are properly balanced. Network load balancing also has implications for Client Access server affinity. Some stateful client features require Client Access server affinity. This is because some state information is cached on Client Access servers. Both Exchange Web Services (EWS) and MAPI clients include ways to maintain Client Access server affinity through the network load balancers.
Client Access server affinity is important for EWS. Using the Client Access server that services a mailbox improves both performance and function. Using a Client Access server that does not service the particular mailbox to handle a request can negatively affect performance, and in some cases, the request might fail. Requests for features such as event notification subscriptions require stateful information, and state information is maintained on the Client Access server that services the mailbox. Client Access server affinity is required to maintain state information about which notifications have been delivered to the client. For example, if the notification request is not sent to the correct Client Access server, the server will respond with the ErrorSubscriptionNotFound error.
The key to maintaining Client Access server affinity for EWS is the exchangecookie cookie. The exchangecookie cookie associates a client with a specific Client Access server — specifically, the Client Access server that services the target mailbox. The network load balancer uses the exchangecookie cookie to maintain Client Access server affinity for a client. The first response that the client receives from the server will contain the exchangecookie cookie. For all subsequent EWS client requests for that mailbox, the exchangecookie cookie must persist, in order to maintain Client Access server affinity. The client should preserve the cookie after each response, because in some cases the cookie might change mid-session. The exchangecookie cookie should persist for use in all future requests.
Clients that use the EWS Managed API 1.1 and the EWS Java API 1.1 do not have to manage the exchangecookie cookie as this is done automatically. If you create a custom client, make sure that the exchangecookie cookie persists for each mailbox you are accessing.
MAPI Client Access server affinity is maintained through the network load balancer by the OutlookSession session. You can maintain Client Access server affinity for a client by using a single OutlookSession session for the client. The client cannot rely on state information maintained on the Client Access server if subsequent sessions are opened since different sessions are not necessarily handled by the same Client Access server that handled a previous session.
Autodiscover is a process by which a Microsoft Exchange Server client can determine the URL of the Microsoft Exchange ActiveSync endpoint by using only a mailbox SMTP address and user credentials. During the Autodiscover process, the client uses the mailbox SMTP address to determine the Autodiscover service endpoint URL and sends a request to the Autodiscover service that includes the mailbox SMTP address. A successful call to the Autodiscover service results in a response that contains the Exchange ActiveSync endpoint URL that the client will use to access the mailbox. This not only simplifies initial client configuration for the end user, but also gives the client a mechanism by which to recover from errors and respond to changes in the Microsoft Exchange environment automatically.
In this blog post, I describe the Autodiscover process from the perspective of an Exchange ActiveSync client developer, including the following:
· Full implementation of the Autodiscover algorithm
· The use of Autodiscover to recover from transient connection errors
· The handling of the X-MS-Location header in 451 redirect responses
· The handling of 302 redirect responses
A client needs only an email address and user credentials to successfully find and call the Autodiscover service. The client should parse the email address to get the domain information, which is everything to the right of the “@” character.
In the following procedure, woodgrovebank.com is the domain from the email address chris@woodgrovebank.com. If the domain information includes a subdomain, such as sales.woodgrovebank.com, the client should use the sales.woodgrovebank.com subdomain first and then, if the procedure fails, try again using the domain woodgrovebank.com. The client uses this domain to construct the Autodiscover service endpoint URLs.
The following procedure describes the Autodiscover process for Exchange ActiveSync clients.
Tip
A client can minimize the user input needed by only asking for the email address and password in step 1. If the user account is not provisioned for a UPN logon, more input may be required. In this case, a 401 error response will be returned, and the client should collect the domain and user name from the user and resubmit the request.
1. The client sends an Autodiscover request to https://woodgrovebank.com/autodiscover/autodiscover.xml and does one of the following:
2. The client sends an Autodiscover request to https://autodiscover.woodgrovebank.com/autodiscover/autodiscover.xml, and does one of the following:
3. The client sends an unauthenticated GET method request to http://autodiscover.woodgrovebank.com/autodiscover/autodiscover.xml. (Note that this is a non-SSL endpoint).The client does one of the following:
4. The client performs a DNS query for an SRV record for _autodiscover._tcp.woodgrovebank.com. The query might return multiple records. The client selects only records that point to an SSL endpoint and that have the highest priority and weight. One of the following occurs:
5. When a valid Autodiscover request succeeds, the following takes place:
6. If the client cannot contact the Autodiscover service, the client should ask the user for the Exchange server name and use it to construct an Exchange ActiveSync URL, similar to the following: http://servername/Microsoft-Server-ActiveSync. The client should try to use this URL for future requests.
The client can perform steps 1-4 in any order or in parallel to expedite the process, but it must wait for responses to finish at each step before proceeding. Given that many organizations prefer to use the URL in step 2 to set up Autodiscover, the client might try this step first.
The preceding procedure mentions Autodiscover requests and responses. Microsoft Exchange publishes a "plain old XML" (POX) endpoint for the Autodiscover service. (For more information, see Autodiscover Reference (POX) on MSDN.) These responses can be quite large. Because Exchange ActiveSync is a mobile protocol, a more concise Autodiscover schema called "mobilesync" is defined specifically for Exchange ActiveSync clients.
The following is an example of an Exchange ActiveSync Autodiscover request.
<?xml version="1.0" encoding="utf-8"?> <Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/mobilesync/requestschema/2006"> <Request> <EMailAddress>chris@woodgrovebank.com</EMailAddress> <AcceptableResponseSchema> http://schemas.microsoft.com/exchange/autodiscover/mobilesync/ responseschema/2006 </AcceptableResponseSchema> </Request> </Autodiscover>
<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/mobilesync/requestschema/2006">
<EMailAddress>chris@woodgrovebank.com</EMailAddress>
<AcceptableResponseSchema>
http://schemas.microsoft.com/exchange/autodiscover/mobilesync/
responseschema/2006
</AcceptableResponseSchema>
</Autodiscover>
A successful Exchange ActiveSync response contains URL settings for Exchange ActiveSync. Settings in the Exchange ActiveSync Autodiscover response can contain two server sections: one with the type “MobileSync”, which is the Exchange ActiveSync endpoint URL, and one with the type “CertEnroll”, which is used to obtain a client certificate for SSL negotiation. (For more information about this response, see [MS-ASCMD] ActiveSync Command Reference Protocol Specification section 4.2.4.)
<?xml version="1.0" encoding="utf-8"?> <Autodiscover xmlns:autodiscover="http://schemas.microsoft.com/exchange/autodiscover/mobilesync/responseschema/2006"> <autodiscover:Response> <autodiscover:Culture>en:us</autodiscover:Culture> <autodiscover:User> <autodiscover:DisplayName>Chris Gray</autodiscover:DisplayName> <autodiscover:EMailAddress>chris@woodgrovebank.com</autodiscover:EMailAddress> </autodiscover:User> <autodiscover:Action> <autodiscover:Settings> <autodiscover:Server> <autodiscover:Type>MobileSync</autodiscover:Type> <autodiscover:Url> https://loandept.woodgrovebank.com/Microsoft-Server-ActiveSync </autodiscover:Url> <autodiscover:Name> https://loandept.woodgrovebank.com/Microsoft-Server-ActiveSync </autodiscover:Name> </autodiscover:Server> <autodiscover:Server> <autodiscover:Type>CertEnroll</autodiscover:Type> <autodiscover:Url>https://cert.woodgrovebank.com/CertEnroll</autodiscover:Url> <autodiscover:Name /> <autodiscover:ServerData>CertEnrollTemplate</autodiscover:ServerData> </autodiscover:Server> </autodiscover:Settings> </autodiscover:Action> </autodiscover:Response> </Autodiscover>
<Autodiscover
xmlns:autodiscover="http://schemas.microsoft.com/exchange/autodiscover/mobilesync/responseschema/2006">
<autodiscover:Response>
<autodiscover:Culture>en:us</autodiscover:Culture>
<autodiscover:User>
<autodiscover:DisplayName>Chris Gray</autodiscover:DisplayName>
<autodiscover:EMailAddress>chris@woodgrovebank.com</autodiscover:EMailAddress>
</autodiscover:User>
<autodiscover:Action>
<autodiscover:Settings>
<autodiscover:Server>
<autodiscover:Type>MobileSync</autodiscover:Type>
<autodiscover:Url>
https://loandept.woodgrovebank.com/Microsoft-Server-ActiveSync
</autodiscover:Url>
<autodiscover:Name>
</autodiscover:Name>
</autodiscover:Server>
<autodiscover:Type>CertEnroll</autodiscover:Type>
<autodiscover:Url>https://cert.woodgrovebank.com/CertEnroll</autodiscover:Url>
<autodiscover:Name />
<autodiscover:ServerData>CertEnrollTemplate</autodiscover:ServerData>
</autodiscover:Settings>
</autodiscover:Action>
</autodiscover:Response>
Redirection to a different URL can be in the form of an HTTP 302 response. In the following example, an Autodiscover request is being redirected to a different URL. The client should try to send an Autodiscover request to the URL in the response. If the request sent to the redirect location fails, the client should stop and inform the user that Autodiscover has failed.
HTTP/1.1 302 Found Location: https://autodiscover.us.woodgrovebank .com/autodiscover/autodiscover.xml
HTTP/1.1 302 Found
Location: https://autodiscover.us.woodgrovebank .com/autodiscover/autodiscover.xml
Important
The client should always validate the URL received in the redirect response to ensure that it does not redirect to non-SSL endpoints or SSL endpoints with invalid certificates.
Steps 3 and 4 in the procedure in the section "Finding and calling the Autodiscover service" describe an unauthenticated, non-SSL, GET request and a DNS lookup, respectively. Because both of these redirection mechanisms can be spoofed, it is important for the Exchange ActiveSync client to properly validate the redirection. Beyond the validation described, in this case the client should also prompt the user to validate the service provider and name on the certificate of the endpoint.
For more information, see Implementing an Autodiscover Client in Microsoft Exchange on MSDN.
Redirects can also come from within the details of an Autodiscover response, as shown in the following example. In this case, the client is being directed to start the Autodiscover process over with a new email address.
<?xml version="1.0" encoding="utf-8"?> <Autodiscover xmlns:autodiscover="http://schemas.microsoft.com/exchange/autodiscover/mobilesync/responseschema/2006"> <autodiscover:Response> <autodiscover:Culture>en:us</autodiscover:Culture> <autodiscover:User> <autodiscover:DisplayName>Chris Gray</autodiscover:DisplayName> <autodiscover:EMailAddress>chris@woodgrovebank.com</autodiscover:EMailAddress> </autodiscover:User> <autodiscover:Action> <autodiscover:Redirect>chris@loandept.woodgrovebank.com </autodiscover:Redirect> </autodiscover:Action> </autodiscover:Response> </Autodiscover>
<Autodiscover xmlns:autodiscover="http://schemas.microsoft.com/exchange/autodiscover/mobilesync/responseschema/2006">
<autodiscover:Redirect>chris@loandept.woodgrovebank.com </autodiscover:Redirect>
The client should start from step 1 in the procedure with the email address from the redirect response, chris@loandept.woodgrovebank.com.
The client should look out for redirections to the same email or URL that it is already using – also known as “circular” redirections. If a circular redirection is detected, the client should not follow it and instead should move to the next step. To avoid getting into an infinite “redirection loop”, the client should also track the total number of redirections and fail after 10.
Errors can come in the form of HTTP 403 or 404 error responses, or in the Error section of an Autodiscover response. The client should consider these errors permanent and move on to the next step in the Autodiscover URL location process. An HTTP 401 response indicates that authentication failed. The client can choose to present the user an opportunity to enter credentials again.
Error responses from Autodiscover can indicate a problem with the request the client sent or a problem on the server side. In the following example, there was a problem contacting the directory service on the server side. Because this error is on the server side, the client should continue on to the next step in the Autodiscover URL location process. The client can also choose to retry this request, as the error might be transient.
<?xml version="1.0" encoding="utf-8"?> <Autodiscover xmlns:autodiscover="http://schemas.microsoft.com/exchange/autodiscover/mobilesync/responseschema/2006"> <autodiscover:Response> <autodiscover:Culture>en:us</autodiscover:Culture> <autodiscover:User> <autodiscover:EMailAddress>chris@woodgrovebank.com</autodiscover:EMailAddress> </autodiscover:User> <autodiscover:Action> <autodiscover:Error> <Status>1</Status> <Message>The directory service could not be reached</Message> <DebugData>MailUser</DebugData> </autodiscover:Error> </autodiscover:Action> </autodiscover:Response> </Autodiscover>
<autodiscover:Error>
<Message>The directory service could not be reached</Message>
<DebugData>MailUser</DebugData>
</autodiscover:Error>
Error responses can also indicate problems with the Autodiscover request sent by the client. The following example shows an error code 600 response, which indicates an invalid request. A 601 response would indicate that the requested schema version is not supported by the server.
<?xml version="1.0" encoding="utf-8"?> <Autodiscover xmlns:autodiscover="http://schemas.microsoft.com/exchange/autodiscover/mobilesync/responseschema/2006"> <autodiscover:Response> <autodiscover:Error Time="16:56:32.6164027" Id="1054084152"> <autodiscover:ErrorCode>600</autodiscover:ErrorCode> <autodiscover:Message>Invalid Request</autodiscover:Message> <autodiscover:DebugData /> </autodiscover:Error> </autodiscover:Response> </Autodiscover>
<autodiscover:Error Time="16:56:32.6164027" Id="1054084152">
<autodiscover:ErrorCode>600</autodiscover:ErrorCode>
<autodiscover:Message>Invalid Request</autodiscover:Message>
<autodiscover:DebugData />
Because Autodiscover requires only an email address and password, using Autodiscover can make the initial configuration of an email account easy for a user. After performing Autodiscover in an initial account configuration, the device should cache the Exchange ActiveSync URL that is returned in the successful response.
While the client should cache the Exchange ActiveSync URL that is retrieved through the Autodiscover process, we recommend that, regardless of any error responses, the URL be refreshed once every 24 hours. Performing Autodiscover periodically ensures that the client is using the most efficient Microsoft Exchange URL for a given mailbox.
Autodiscover is equally important after the initial configuration of the email client as a method for recovering from transient errors. If the client receives HTTP 401, 403, 404, or 500 responses, timeouts, or any response that indicates a DNS lookup failure, it should run Autodiscover to see if it gets a new URL. For more information, see [MS-ASHTTP] ActiveSync HTTP Protocol Specification section 3.1.5.2.1.
The client can also receive an HTTP 451 redirect response, as specified in [MS-ASHTTP] ActiveSync HTTP Protocol Specification section 3.1.4.2.2. This response indicates that the client sent a request to a URL that is no longer the optimum endpoint URL for the mailbox the client is trying to access. This can occur when a mailbox moves from one Active Directory site to another. For more information, see Understanding Proxying and Redirection on Microsoft TechNet. The client will continue to receive the 451 error until it sends requests to the new endpoint.
Typically, the 451 response contains an X-MS-Location header that indicates the new Exchange ActiveSync URL for the client to use. When this header is present, the client does not need to use Autodiscover to get the new URL; it can use the URL from the header. However, the X-MS-Location header is optional. If the header is not present, the client should perform Autodiscover to get a new Exchange ActiveSync URL. The following example shows a 451 error response.
HTTP/1.1 451 Date: Tue, 08 Dec 2009 19:43:24 GMT Server: Microsoft-IIS/7.0 X-Powered-By: ASP.NET X-AspNet-Version: 2.0.50727 X-MS-Location: https://mail.woodgrovebank .com/Microsoft-Server-ActiveSync Cache-Control: private Content-Length: 0
HTTP/1.1 451
Date: Tue, 08 Dec 2009 19:43:24 GMT
Server: Microsoft-IIS/7.0
X-MS-Location: https://mail.woodgrovebank .com/Microsoft-Server-ActiveSync
Content-Length: 0
A 302 redirect response is expected and should be followed only during the Autodiscover process. If the client receives a 302 redirect in response to a command, such as FolderSync, it should not follow the redirect. Instead, the client should go through the Autodiscover process again to get a new URL.
When the client performs Autodiscover to attempt to recover from a transient error condition, it should not discard the original Exchange ActiveSync URL that is stored in the cache until it confirms that the new URL works. We recommend that the client perform Autodiscover, determine whether the URL that is retrieved is different than the URL that was cached before the error, try the new URL if it is different, and if the URL works, replace the cached URL with the new URL. This ensures that the client maintains a URL to retry in the event that Autodiscover fails.
[MS-ASHTTP]: ActiveSync HTTP Protocol Specification
Understanding Proxying and Redirection
Understanding the Autodiscover Service
Understanding Exchange ActiveSync Autodiscover
Autodiscover and Exchange 2007
Post written by: Matt Stehle, Microsoft Corporation
The Exchange Interoperability documentation team is pleased to announce the launch of Exchange Server Interoperability Guidance that supplements the information available in the Microsoft Exchange Server protocol documentation and the Microsoft Exchange Server and Outlook Standards documentation. Whether you’re an Exchange interoperability expert, just getting started, or somewhere in between, we’re confident that this supplemental information will be a valuable resource for you.
In the first article, Exploring the Microsoft Exchange Server Open Specifications, Kim Brandl reviews the types of protocols, structures, algorithms, and standards that the Microsoft Exchange Server Open Specifications define, discusses how to get started using the specifications, explores the kinds of content that you’ll find in the various types of specifications, and addresses some key points to help you derive the maximize benefit from the specifications. Check out Exploring the Microsoft Exchange Server Open Specifications now, and stay tuned for additional technical articles coming soon!
Kim Brandl Exchange Interoperability Microsoft Corporation
We are specifically focused on throttling of Exchange Web Services (EWS) and MAPI with RPC over HTTP (as used by Microsoft Outlook) and with hard limits set by the Exchange Online system. Any mention of specific setting values were obtained for the service version 14.0.100.0. You will want to have your tenant admin obtain and confirm setting values.
Note An on-premise Microsoft Exchange deployment may have a different throttling policy. Administrators can modify throttling settings for Microsoft Exchange on-premises. Administrators cannot configure throttling policies for Exchange Online.
What is the impact of exceeding throttling budgets?
Exchange throttling is based on the amount of Active Directory, Exchange store, and other resources a client consumes. A budget is allocated to each client to limit the resources a particular user consumes. This budget is recharged every minute.
EWS clients can exceed their budgets by sending too many concurrent requests, or by requesting too many resources on the server. When this occurs, additional requests are queued until one of two things happen:
When MAPI clients exceed their budgets, additional requests are returned with an error, until the application is under budget. There is no queuing of requests.
How do I get throttling settings?
Tenant administrators can view throttling settings by using Remote PowerShell and the Get-ThrottlingPolicy cmdlet. For information about how to connect Remote PowerShell for your tenant, see Install and Configure Windows PowerShell and Connect Windows PowerShell to the Service on Microsoft TechNet.
Use the Get-ThrottlingPolicy cmdlet (without arguments) to get all the throttling policy settings. Throttling policies might change to enhance service performance, so you should confirm throttling policies. We suggest that you make your client applications configurable to adjust for potential changes in throttling policy for Exchange Online. Additionally, because Exchange Online and Exchange on-premises might have different throttling policies, you may want to account for this when you design your client applications.
What are the common throttling settings?
The following throttling settings are common to both EWS and MAPI (RPC over HTTP) clients:
What are the MAPI with RPC over HTTP throttling settings?
The prefix RCA in the MAPI RPC/HTTP settings represents RPC Client Access. The following throttling settings are specific to MAPI RPC over HTTP:
What are the Exchange Web Services throttling settings?
The following throttling settings are specific to Exchange Web Services:
For more information about EWS throttling policy, see EWS Best Practices: Understanding Throttling Policies.
What are the specific Exchange Web Services limits?
The following are the specific EWS throttling limits:
Note The values for this limit differ for an on-premise Exchange 2010 deployment. In the initial release version of Exchange 2010, the message size limit is 10 MB. In Exchange 2010 Service Pack 1 (SP1), the message size limit is 35 MB.
We are pleased to announce the availability of the Microsoft Office 2010 Developer Map. Whether you are new to developing with Microsoft Exchange, or a seasoned veteran, this map will guide you through the tools, applications, platforms, and services you can use to develop your application. The interactive map is a living document that provides links to MSDN Library documentation. You can also download the poster and print it out to hang on your wall.
Start visualizing the applications, services like Exchange Online, client/server data-access technologies like Exchange Web Services, on-premise servers, platform products and technologies, and tools that can help you build multiple line-of-business solutions.
Bob Bunn Exchange Developer Documentation Microsoft Corporation
Microsoft Exchange Online as part of Microsoft Office 365 provides many of the same app-development capabilities that are available for Microsoft Exchange Server running on-site. The Exchange Developer Documentation team is pleased to announce the release of a new Exchange Online Developer Center page that will be your portal for information about Exchange Online development.
If you’re not quite up to the rock-star level as an Exchange programmer, or if Exchange Online is the only flavor of Exchange you’ve ever known, this is the place for you! And even if you’re already an experienced Exchange developer, we want to make it really easy to use that Exchange knowledge as you create apps for the Cloud.
Along with the new Exchange Online page, we have an article to help you get started writing apps that use Exchange Web Services (EWS) and EWS Managed API. This article explains the important first steps to get things running smoothly and quickly.
We have more articles coming in the near future, including one about configuring and using Exchange Autodiscover, so come back to the site often to find new information. We plan to provide great information for programming with Exchange Online for all types of developers, from experienced corporate and ISV developers to total newbies.
A bunch of articles, of course, can’t tell the whole story. As the Office 365 Beta progresses, and as the service officially becomes available, we’ll continue posting articles, blog posts, podcasts, and even videos. Because we know you’ll have questions, the writing team will also be helping out in the forums.
We look forward to hearing from you more than ever, and to helping your Exchange development projects succeed.
Best regards to our new and current readers,
Thom Randolph Exchange Developer Documentation Microsoft Corporation
Interested in learning more about the Exchange Server RPC protocols? The Exchange Server Interoperability team is pleased to announce that presentations from the Exchange RPC Protocols Plugfest event (January 2011) are now available on Channel 9. Plugfest events are part of the Microsoft Open Specifications Program which helps developers create solutions by providing open access to technical specifications and support through a variety of channels.
If you’re working with the Microsoft Exchange protocols, check out the Exchange RPC Protocols Plugfest January 2011 series on Channel 9 for valuable information about the following topics:
The Exchange Interoperability Team is excited to announce the initial release of the Microsoft Exchange RPC Extractor (RPX). RPX is a command-line tool that can parse network captures and interpret remote procedure calls (RPCs) made from a client to Microsoft Exchange Server. RPX uses the information provided in the Microsoft Exchange Server protocol documentation to parse RPCs, remote operations (ROPs) and the parameters for each ROP.
The goal for RPX is to assist developers who are implementing the Microsoft Exchange protocols by allowing them to view and compare the RPC traffic between clients and servers. Network capture files are transformed into text files that detail RPC requests and responses, including parameters and return codes.
If you are working with the Microsoft Exchange protocols, follow the link below to download RPX today and try it out!
Microsoft Exchange RPC Extractor 1.0
Microsoft Exchange Server 2010 Service Pack 1 (SP1) introduces streaming notifications, a new feature that combines push and pull notifications. For those of you who are not too familiar with notifications, I’ll give some background information. Pull notifications require your application to create a subscription and every now and then request an update from the server. This can create quite a bit of traffic between the client and server if you want to keep up-to-date with events on the server. Push notifications require you to write your own listener application. You create a push subscription with the server and when an event fires, it pushes the notification to your listener application. This works well because you don’t have to keep asking the server for updates, but it does require that you create a separate application to receive the notifications. Now, we have the best of both worlds with streaming notifications. After you have established your notification subscription, the connection remains open to allow the server to push notifications back to your application. You don’t have to request updates as for the pull subscription, and you don’t have to create a listener application as for the push notifications.
We wrote a console example for creating the subscription and handling notification responses. The first step in your application is to create a service binding to your Exchange mailbox. Because this is a pretty common routine in Microsoft Exchange Web Services (EWS) Managed API, I don’t want to go over it in detail here, but if you need a refresher check out the topic Connecting to EWS in the EWS Managed API SDK.
After the service binding is completed, call the SetStreamingNotifications function and pass in the service binding. In this example, a subscription is made to the Inbox and the notifications will be sent for new e-mail messages and for items that have been created or deleted in the Inbox. Because this is just an example, the timeout is set to one minute, but you can adjust this as necessary for your application. This example will also recognize the OnDisconnect event and ask if the connection should remain open. You can see that after the subscription is created, it’s very easy to reopen the connection. If you don’t want to reopen the connection, the code will close the connection object.
When a notification is sent back, the OnEvent function is called and a message is output to the console. When you get the notification, you also get the itemID that you can use to bind to the item and get additional information about that item.
The following code shows the console application…
static void SetStreamingNotifications(ExchangeService service) { // Subscribe to streaming notifications on the Inbox folder, and listen // for "NewMail", "Created", and "Deleted" events. StreamingSubscription streamingsubscription = service.SubscribeToStreamingNotifications( new FolderId[] { WellKnownFolderName.Inbox }, EventType.NewMail, EventType.Created, EventType.Deleted);
StreamingSubscriptionConnection connection = new StreamingSubscriptionConnection(service, 1);
connection.AddSubscription(streamingsubscription); // Delegate event handlers. connection.OnNotificationEvent += new StreamingSubscriptionConnection.NotificationEventDelegate(OnEvent); connection.OnSubscriptionError += new StreamingSubscriptionConnection.SubscriptionErrorDelegate(OnError); connection.OnDisconnect += new StreamingSubscriptionConnection.SubscriptionErrorDelegate(OnDisconnect); connection.Open();
Console.WriteLine("--------- StreamSubscription event -------"); }
static private void OnDisconnect(object sender, SubscriptionErrorEventArgs args) { // Cast the sender as a StreamingSubscriptionConnection object. StreamingSubscriptionConnection connection = (StreamingSubscriptionConnection)sender; // Ask the user if they want to reconnect or close the subscription. ConsoleKeyInfo cki; Console.WriteLine("The connection to the subscription is disconnected."); Console.WriteLine("Do you want to reconnect to the subscription? Y/N"); while (true) { cki = Console.ReadKey(true); { if (cki.Key == ConsoleKey.Y) { connection.Open(); Console.WriteLine("Connection open."); break; } else if (cki.Key == ConsoleKey.N) { // The ReadKey in the Main() consumes the E. Console.WriteLine("\n\nPress E to exit"); break; } } } }
static void OnEvent(object sender, NotificationEventArgs args) { StreamingSubscription subscription = args.Subscription;
// Loop through all item-related events. foreach (NotificationEvent notification in args.Events) {
switch (notification.EventType) { case EventType.NewMail: Console.WriteLine("\n-------------Mail created:-------------"); break; case EventType.Created: Console.WriteLine("\n-------------Item or folder created:-------------"); break; case EventType.Deleted: Console.WriteLine("\n-------------Item or folder deleted:-------------"); break; } // Display the notification identifier. if (notification is ItemEvent) { // The NotificationEvent for an e-mail message is an ItemEvent. ItemEvent itemEvent = (ItemEvent)notification; Console.WriteLine("\nItemId: " + itemEvent.ItemId.UniqueId); } else { // The NotificationEvent for a folder is an FolderEvent. FolderEvent folderEvent = (FolderEvent)notification; Console.WriteLine("\nFolderId: " + folderEvent.FolderId.UniqueId); } } } static void OnError(object sender, SubscriptionErrorEventArgs args) { // Handle error conditions. Exception e = args.Exception; Console.WriteLine("\n-------------Error ---" + e.Message + "-------------"); }
To make this application work properly, bind it to your Exchange mailbox and call the SetStreamingNotifications function. Then send a message to this mailbox from an e-mail client of your choice — just do it before the one minute timeout occurs. You will then get a message that an item was created and you have a new e-mail message in your Inbox.
Hi Everyone,
I’m pleased to announce the public availability of the Microsoft Exchange Web Services (EWS) Java API 1.1. The final package was posted this past weekend for download. This package offers the same functionality that our EWS Managed API 1.1 for the Microsoft .NET Framework offers. During the course of development, we’ve had internal and external users working with beta drops of this API. There is a lot of excitement about it, and now we’re happy to finally offer it to everyone.
This API was developed in order to facilitate Exchange development on other platforms. It has been over a year in development, and it is our first release of a package that includes source code. Although the source is viewable, our licensing for this iteration does not allow for modification of the source code. It can be used to build against a particular JRE or JDK, but the license agreement only allows the object code to be shared in your application. We took this approach because we’re keeping the releases in sync with our Exchange versions. The 1.1 release corresponds to Exchange 2010 SP1.
We’re looking forward to what the future holds for client development on other platforms.
We encourage you to develop your Exchange client on other platforms now, and would like to hear about your projects.
Michael MainerExchange SDK and InteroperabilityMicrosoft Corporation
We know you’ve been waiting to see the new Exchange Web Services features in Exchange 2010 SP1 exposed in the EWS Managed API, and I’m here to tell you that your wait is over. The Exchange Web Services Managed API 1.1 is now available for download. The EWS Managed API 1.1 exposes the following features that were introduced in Exchange 2010 SP1:
· Archive mailbox – Access to archive folders and items. Everything you can do with mailbox items and folders is available for your archived information. Equal access for all items and folders!
· Conversations – Emails are social and so is your application, so try the new Conversations feature exposed by EWS to easily manage email conversations.
· Inbox Rules – Would you like to tell your Exchange server where to store it (emails)? Server-side Inbox rules are now available as a programmatic interface for your Exchange client applications. For more information, see Working with Inbox Rules.
· Streaming Notifications – Want your cake and eat it too? Now you can with streaming notifications. Streaming notifications provide you with the benefits of both push and pull event notification models.
For a convenient chart that lists applicable features by server and API versions, see Introduction to the EWS Managed API.
And before I forget, make sure you visit the important companion to the EWS Managed API 1.1, the Exchange Web Services Managed API 1.1 SDK.
It’s time to rev your application!
The Exchange Developer Documentation Team is happy to announce the October 2010 release of the Exchange Server 2010 Service Pack 1 (SP1) SDKs. If you’ve been keeping up with our SDK releases, then you know that we already released a lot of new information about Exchange 2010 SP1 back in June. The updates for October cover the released version of SP1, with additional information and updates to the preliminary release. Check out the What’s New topics for these SDKs to get more details:
The Exchange 2010 Management Shell SDK will be released in the near future as well; for now, you can still check out the June release, which includes preliminary information about SP1. The Exchange Web Services Managed API 1.1 SDK is also available with updates for October, and includes several new conceptual topics that include more information about how to use this API.
We hope the release of the documentation help you achieve your organizational goals for Exchange connectivity and interoperability.
Bob Bunn Microsoft Corporation
How to use CHKSGFILES multi-threaded for faster consistency checks
One of the questions that we sometimes get here, and that we’ve never really been able to answer is: do I HAVE to run the database consistency check (the CHKSGFILES API) in single-threaded fashion? Doing things multi-threaded could be so much faster! Well the answer is some parts no, but some parts yes.
If you don’t already know, CHKSGFILES is used by applications that back up Exchange databases, to ensure that the database to be stored is actually in good health and not corrupted. With Exchange 2010, it’s much less likely there will be a corruption problem, but it's safer for your backup and restore application to verify the data before making the backup.
Well, after some extensive archeology, we’ve determined that, if you do it right, you actually CAN run parts of CHKSGFILES multi-threaded. We’ll be adding this information into the SDK for October 2010, but wanted to get the word out now for those of you who are interested.
The general, using CHKSGFILES to check database consistency in a multi-threaded application runs like in the following example. Remember, this is just an EXAMPLE, and is only intended to show which parts of CHKSGFILES must be handled in what way.
This example application uses two main processes, and a set of worker threads. The first (orange) process handles the overall backup job, while the second (blue) handles queue requests by creating worker threads to verify the database pages and log files. Central to the system is a request and completion-status queue.
Backup job-engine (the single-threaded part)
The Backup Job-engine process block (orange) in the diagram indicates the parts of the database consistency check that must be run single-threaded.
IMPORTANT Your application must never allow more than one Backup Job-engine block to operate at the same time. The CHKSGFILES APIs shown in that block should never be called in parallel. Your application should ONLY call CHKSGFILES consistency checks in sequence. The CHKSGFILES DLL does not support out-of-sequence or simultaneous calls to New(), ErrInit(), ErrCheckDbHeaders(), ErrTerm() and Delete(). Your application should call those APIs only once for each consistency check. After the sequence shown in the Backup Job-engine block has been completed, only then can that sequence be restarted.
When the Backup Job-engine section starts, it should initialize whatever request queuing mechanism is being used. In this example, it’s a queue that includes the requests, the return status of those requests, and a separate process that scans for entries in the request queue. Because the intention of running a database consistency checks is to find errors, the queue needs to return that success / failure information to the main part of the program.
After the queue is initialized, the backup job can use Windows VSS to take the snapshot. After the snapshot is successfully made and available, the backup application can call the CHKSGFILES New() function to obtain an instance of the API. The backup job must then call ErrInit(), indicating which databases are to be checked, the log-file path, and other parameters.
Then the backup job process calls the ErrCheckDbHeaders() function, to verify that all the databases have the proper header information. It is very important that ErrCheckDbHeaders() be called only once to check ALL the databases that were specified in ErrInit(). For Exchange 2007, this will likely be all the databases in a storage groups. For Exchange 2010, this will probably be only a single database, because ErrInit() accepts only a single log file path.
In this example, the single-threaded Backup Job-engine then adds requests into the queue for the database pages in each database, and a single request to check the log files.
In this example, the backup job-engine then waits until the request queue contains completion status for all the requests. Then the backup job-engine calls the ErrTerm() function. Like ErrCheckDbHeaders(), your application must call ErrTerm() only once. It is up to the application to ensure that it has tried to check all the database pages and log files. Do not try to use ErrTerm() to keep track of the progress: if you call ErrTerm() and all the pages and logs have not been checked, it will return an error and invalidate all checks that had been done on those databases. In this example, the backup job-engine process uses the queue entries to keep track of which database pages have been checked.
Finally, the backup job engine can call the Delete() function, to dispose of the CHKSGFILES instance. Then, based on the results, the backup application can copy the snapshot contents to the backup media, and continue processing the backup job.
Implication of storage groups
At this point a short discussion about the parameters passed to ErrInit() is appropriate. In Exchange 2007, when CHKSGFILES was introduced, the Exchange storage architecture includes Storage Groups, which are collections of databases that can be managed together as a unit. So, with Exchange 2007 servers, you will probably pass a list of the databases in a storage group to the ErrInit() function. But, Exchange 2010 doesn’t have storage groups. Indeed, typically each database and log file set is kept separate. So, for checking Exchange 2010 databases, you will very likely pass a single-element array with one database and log file path to ErrInit(). Remember, ErrInit() requires the databases to be specified in an array, even when there is only one database to be checked.
You might wonder: if the application typically only sends a single database through the CHKSGFILES APIs at a time, what good is multi-threading? Good question! For that individual database, the page checks can be run in parallel, which will certainly speed up the process. But if you need to check multiple Exchange 2010 databases, your application will need to separately call New() and ErrInit() for each database, and separately handle the different instances of the CHKSGFILES API. Just like with a single set of databases sent to ErrInit(), the single-threading and sequencing rules for the API have to be followed for each instance.
Queue Servicing process (the multi-threaded part)
As you can tell, nearly the whole CHKSGFILES API needs to be run in a single thread, and there can be no out-of-sequence calls made. In the example application, the CHKSGFILES parts that can be run multi-threaded are shown as the Queue Servicing process (blue), and the Database Page and log file worker threads (green).
IMPORTANT The CHKSGFILES API does support checking the log files [using the ErrCheckLogs() API] parallel to checking the database pages [using the ErrCheckDbPages() API]. However, your application must call ErrCheckLogs() only ONCE for each set of databases that were passed to ErrInit(). If ErrCheckLogs() is called more than once, an error will be returned, and the entire consistency check will have failed, even if no actual database or log file errors exist.
When the queue servicing process starts, it begins checking for new entries in the request queue. When it sees a new request, it can start a new worker thread to service that request.
When it starts, the worker thread (green) should obtain the request information from the queue (or directly from the request queue servicing process), and then perform the check. In this example application, it is up to the worker thread to process the request appropriately: database page requests use ErrCheckDbPages(), while log file requests use ErrCheckLogs(). If the backup job-engine process is running properly, there should never be more than one request for log file checks for each set of databases passed to ErrInit(). When the check has completed, the worker thread should update the request status information in the queue, and then the thread should exit.
When all the dispatched threads have exited, the queue processing service can signal the backup job-engine process via the queue. Alternatively, the backup job-engine process can detect when there are no more unprocessed requests in the queue.
So, that’s all there is. It’s not terribly complicated, but your application must follow these rules:
Using a combination of single- and multi-threading, and obeying the rules described in this blog post, your backup application can more quickly check Exchange databases than in a purely single-threaded manner.
Thom Randolph
Documentation Manager
Exchange Developer Documentation
Microsoft Corporation
We’re excited to announce that we have released updates to the Exchange 2010 SDKs for Microsoft Exchange Server 2010 Service Pack 1 (SP1). Exchange 2010 SP1 introduces many new programmability features that will help you create robust applications. Here is an overview of what has changed for Exchange programmability documentation for this release:
· Exchange 2010 SP1 Beta Web Services SDK – We added documentation in support of the many new features for Exchange Web Services. This includes a new EmptyFolder operation to simplify the deletion of folder content, bulk transfer to support the import/export of information in a mailbox, conversation operations to help manage items in a conversation, and the Inbox rules operations to enable you to programmatically use Inbox rules. We have also made small changes to existing API features
· Exchange 2010 SP1 Beta Transport Agents SDK & Exchange 2010 SP1 Beta Outlook Web App Customization SDK – We have included new documentation for new types and members that were added to the APIs, and updates to existing types and members.
· Exchange 2010 SP1 Beta Backup and Restore SDK – We updated information about running consistency checks on databases in a Database Availability Group (DAG).
Check out the What’s New pages for the SDKs for more details about the exciting changes to your favorite Exchange API.
We hope the new features and documentation help you achieve your organizational goals for Exchange connectivity and interoperability. And while you are reading this, if you’d like to provide input for future Exchange programmability features and improvements, submit your feedback to our very own David Claux on the Exchange Server Development forum.
Happy coding!
Michael Mainer
When studying the event log over a steaming hot cup of coffee, have you ever seen the following directory event (2914)?
Process w3wp.exe (UNKNOWN) (PID=15780). Deleted throttling policy was referenced. Id: 'Org: SomeOrg…/Configuration, Id: CN=ThrottlingPolicy-DefaultMailboxPlan\0ADEL:4d73d344-d66f-4eed-85f9-b6c95dcd2a13,CN=Deleted Objects,CN=Configuration,DC=…,DC=com'.
This one does require some action. In the case of this event log, a throttling policy was deleted from Active Directory, but because *someone* did not use Remove-ThrottlingPolicy to do so, the links from the associated mailboxes did not get updated properly. The fix is relatively easy – you just need to reassign the affected mailboxes to a valid throttling policy. Now, I highlighted the “\0ADEL” wording in the event log for a reason. That is a very reliable way to determine whether we are dealing with a deleted object in Active Directory. We can use that to our advantage in the Exchange Management Shell.
[PS] D:\Windows\system32>get-mailbox | ? {$_.ThrottlingPolicy -ilike "*`nDEL*"} | fl Name, ThrottlingPolicy
Name : JohnDoeThrottlingPolicy : SomeDomain/Configuration/Deleted Objects/SomePolicy DEL:3fb98144-b317-413b-9a19-78003fd5a633
The key is in the “*`nDEL*” string. The value “`n” is the Exchange Management Shell’s way of escaping the new-line sequence.
Now that we have discovered the mailbox that is having the issue, we can assign that mailbox to another policy. In my case, I just want JohnDoe to use the default policy, so I will just null out the ThrottlingPolicy parameter.
get-mailbox | ? {$_.ThrottlingPolicy -ilike "*`nDEL*"} | set-Mailbox –ThrottlingPolicy $null
Even with this problem present, the throttling policy framework was behaving properly and “falling back” to the default throttling policy governing John Doe. However, it is a good idea to clean up these issues in the directory if you encounter them and make your throttling policy association links explicit rather than relying on the fallback logic to do the “right thing”.
David SterlingExchange Web ServicesInside Microsoft Exchange Server 2007 Web Services
When you use the FindItems method or the FindAppointments method in Exchange Web Services (EWS), it’s important to realize that neither of these methods returns all properties for the items returned by the query. For example, FindItems will not return the Body property for a message item, and FindAppointments will not return the RequiredAttendees property for a calendar item. Therefore, if you are interested in additional properties that cannot be returned by FindItems or FindAppointments, you must explicitly load the additional properties to the items that are returned by the query.
Fortunately, the EWS Managed API provides an easy way to load additional properties for multiple items with a single call to EWS. The following code example shows you how to search the Inbox folder for items that match the specified search criteria, and then use the LoadPropertiesForItems method to load the Subject property and Body property for the items returned by FindItems.
// Specify the IdOnly response shape, and specify that // FindItem results should be requested in batches of 25. ItemView view = new ItemView(25); view.PropertySet = new PropertySet(BasePropertySet.IdOnly); view.Offset = 0; view.OffsetBasePoint = OffsetBasePoint.Beginning; // Specify search criteria. SearchFilter searchFilter = new SearchFilter.ContainsSubstring(ItemSchema.Subject, "Message #"); // Declare findResults. FindItemsResults<Item> findResults; do { // Call FindItems to search the Inbox folder. findResults = service.FindItems(WellKnownFolderName.Inbox, searchFilter, view); // Load additional properties for the current batch of items. service.LoadPropertiesForItems(findResults, new PropertySet(ItemSchema.Subject, ItemSchema.Body)); // TODO: Process the current batch of items. // If more items are available, update the offset value so that the next // batch of items is returned by the next call to FindItems. if (findResults.NextPageOffset.HasValue) { view.Offset = findResults.NextPageOffset.Value; } } while (findResults.MoreAvailable);
Note: By specifying a page size of 25 when ItemView is instantiated, this example requests FindItems results (and subsequently calls LoadPropertiesForItems) for a maximum of 25 items at a time. Processing items in batches like this is helpful in that it reduces the likelihood that the server will be overloaded when the number of search results is large.
The following is the XML response that is returned by from FindItems in the above code example. A total of five messages that match the search criteria were found in the Inbox folder. Item identifiers and change keys have been shortened for readability.
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <m:FindItemResponse xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"> <m:ResponseMessages> <m:FindItemResponseMessage ResponseClass="Success"> <m:ResponseCode>NoError</m:ResponseCode> <m:RootFolder IndexedPagingOffset="5" TotalItemsInView="5" IncludesLastItemInRange="true"> <t:Items> <t:Message> <t:ItemId Id="AAT5QA=" ChangeKey="CQAAA" /> </t:Message> <t:Message> <t:ItemId Id="AAT5QB=" ChangeKey="CQAAB" /> </t:Message> <t:Message> <t:ItemId Id="AAT5QC=" ChangeKey="CQAAC" /> </t:Message> <t:Message> <t:ItemId Id="AAT5QD=" ChangeKey="CQAAD" /> </t:Message> <t:Message> <t:ItemId Id="AAT5QE=" ChangeKey="CQAAE" /> </t:Message> </t:Items> </m:RootFolder> </m:FindItemResponseMessage> </m:ResponseMessages> </m:FindItemResponse> </s:Body>
Note: In this example, the number of items that matched the specified search criteria was fewer than our specified paging size of 25; therefore, all items were returned by the first call to FindItems. If more than 25 items (the specified paging size) had matched the specified search criteria, FindItems (and LoadPropertiesForItems) would have executed multiple times — once for each batch of 25 items that matched the specified search criteria.
The following is the XML request that is generated by calling LoadPropertiesForItems in the above code example. As this XML request shows, LoadPropertiesForItems translates to a batch GetItem call under the covers — the Subject and Body property for all five items in findResults are requested in a single call GetItem call to EWS.
<m:GetItem> <m:ItemShape> <t:BaseShape>IdOnly</t:BaseShape> <t:AdditionalProperties> <t:FieldURI FieldURI="item:Subject" /> <t:FieldURI FieldURI="item:Body" /> </t:AdditionalProperties> </m:ItemShape> <m:ItemIds> <t:ItemId Id="AAT5QA=" ChangeKey="CQAAA" /> <t:ItemId Id="AAT5QB=" ChangeKey="CQAAB" /> <t:ItemId Id="AAT5QC=" ChangeKey="CQAAC" /> <t:ItemId Id="AAT5QD=" ChangeKey="CQAAD" /> <t:ItemId Id="AAT5QE=" ChangeKey="CQAAE" /> </m:ItemIds> </m:GetItem>
Now, you might assume that the same simple call to LoadPropertiesForItems can also be used to load properties for calendar items that are returned by FindAppointments. And it will work, with one small caveat: LoadPropertiesForItems takes an argument of type IEnumerable<Item>, whereas FindAppointments returns IEnumerable<Appointment> — so you must find a way to pass the results from FindAppointments to LoadPropertiesForItems as IEnumerable<Item>. Fortunately, this is easily accomplished by using Linq. The following code example shows you how search the Calendar folder for appointments that match the specified search criteria, and then use the LoadPropertiesForItems method to load the Subject property, the RequiredAttendees property, and the OptionalAttendees property for the calendar items returned by FindAppointments.
// Define search parameters and maximum number of items to return. CalendarView calView = new CalendarView(DateTime.Now, DateTime.Now.AddDays(3), 25); // Specify the IdOnly shape. PropertySet props = new PropertySet(BasePropertySet.IdOnly); calView.PropertySet = props; // Call FindAppointments to search the Calendar folder. FindItemsResults<Appointment> findResults = service.FindAppointments(WellKnownFolderName.Calendar, calView); if (findResults.TotalCount > iMaxItemsReturned) { string sMsg = "Total number of items that match search criteria exceeds specified maximum number of results to return."; sMsg += " To find all items that match the specified search criteria, either narrow the date range "; sMsg += "or increase the specified maximum number of items to return in CalendarView."; Exception e = new Exception(sMsg); throw e; } else { // Call LoadPropertiesForItems to load the Subject, RequiredAttendees, and OptionalAttendees properties. service.LoadPropertiesForItems(from Item item in findResults select item, new PropertySet(BasePropertySet.IdOnly, AppointmentSchema.Subject, AppointmentSchema.RequiredAttendees, AppointmentSchema.OptionalAttendees)); }
Note: To use Linq as shown in the above example, you must include the following directive in your program: using System.Linq;
Want to learn more about working with the EWS Managed API? Check out the code examples that are available in the Working with the EWS Managed API section of the Microsoft Exchange Web Services Managed API 1.0 SDK.
Have you ever seen event 2917 in your Client Access server’s event log? It might look something like this:
Process w3wp.exe (PID=1234). A budget charge was encountered that exceeded the limit of '2.768900000' minutes. Budget Owner: 'SomeUser', Component: 'EWS, CostType: 'CAS'.
Sounds scary, doesn’t it? The wording is a bit odd (feel free to blame me) and can lead one to assume that there is some strange throttling limit of 2.7689 minutes (or some other equally non-integer-like number) lurking inside Exchange. There is no such limit – that value indicates when the condition was discovered, not what the limit is. This is really more of a warning message, but is completely un-actionable and will be removed from a future release of the product.
All this event is saying is that the throttling infrastructure noted that a given operation has taken longer than expected, and it wanted you to know about it. This could be the result of an overloaded mailbox server, intense periods of garbage collection, a domain controller issue, and so on… It does not suggest that the “budget owner” has done anything wrong or nefarious nor does it suggest that the user in question was throttled. You can ignore this event log and look forward to the days when it will no longer darken the doorstep of your event log.