Sender Flags are an Outlook Feature that allow you to set a follow up flag on Message when your sending it as well as being able to set a Recipient Followup flag if you want to. (eg)
What happens in Exchange when you set a Sender Flag on a Message is documented in the Informational Flagging Protocol document http://msdn.microsoft.com/en-us/library/cc433487(v=exchg.80).aspx . If you want to do the same thing to a Message your sending in EWS there is nothing in the strongly typed classes to help out so you need to manually set two of the extended properties that are documented in that protocol document before you send the message and the Store will do the rest on submit. (More specifically what happens with the properties involved is documented here http://msdn.microsoft.com/en-us/library/ee217246(v=exchg.80).aspx )
The important properties that are involved with sender flags are the PidTagSwappedToDoData which is used to Store the information about what sender flags your want (eg in Outlook configured via the above dialogue box). This is a binary property containing an number of Flags, The text for the Message Flags and the DateTime values for the Start and DueDate. The full structure of the property is documented in http://msdn.microsoft.com/en-us/library/ee201575(v=exchg.80).aspx
The DateTime values used in this Property are stored as a 4-byte integer that are expressed as the number of minutes since 00:00:00 on January 1, 1601, in UTC. To get this Integer the method I used is a TimeSpan between the Date you want and January 1, 1601, in UTC, you can then get the TotalMinutes for the timespan as an Integer.
TimeSpan ts = new DateTime(2013,12,01,0,0,0,0,DateTimeKind.Utc) - new DateTime(1601, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
The other important property is the PidTagSwappedToDoStore which is used by the Store after the Message is submitted. To use this is EWS you need to construct it based on the format documented in http://msdn.microsoft.com/en-us/library/ee203516%28v=exchg.80%29.aspx . The information necessary for this can be obtain through AutoDiscover.
I've created a Powershell and EWS Sample for setting a Sender Flag on a Message with a Start and DueDate. I've put a download of this script here the code itself looks like
- ## Get the Mailbox to Access from the 1st commandline argument
- $MailboxName = $args[0]
- $SenderFlagText = "This is a Test Blah Blah"
- $FlagStartDate = (Get-Date).AddDays(1)
- $FlagDueDate = (Get-Date).AddDays(7)
- ## Load Managed API dll
- Add-Type -Path "C:\Program Files\Microsoft\Exchange\Web Services\2.0\Microsoft.Exchange.WebServices.dll"
- ## Set Exchange Version
- $ExchangeVersion = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP2
- ## Create Exchange Service Object
- $service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService($ExchangeVersion)
- ## Set Credentials to use two options are availible Option1 to use explict credentials or Option 2 use the Default (logged On) credentials
- #Credentials Option 1 using UPN for the windows Account
- $psCred = Get-Credential
- $creds = New-Object System.Net.NetworkCredential($psCred.UserName.ToString(),$psCred.GetNetworkCredential().password.ToString())
- $service.Credentials = $creds
- #Credentials Option 2
- #service.UseDefaultCredentials = $true
- ## Choose to ignore any SSL Warning issues caused by Self Signed Certificates
- ## Code From http://poshcode.org/624
- ## Create a compilation environment
- $Provider=New-Object Microsoft.CSharp.CSharpCodeProvider
- $Compiler=$Provider.CreateCompiler()
- $Params=New-Object System.CodeDom.Compiler.CompilerParameters
- $Params.GenerateExecutable=$False
- $Params.GenerateInMemory=$True
- $Params.IncludeDebugInformation=$False
- $Params.ReferencedAssemblies.Add("System.DLL") | Out-Null
- $TASource=@'
- namespace Local.ToolkitExtensions.Net.CertificatePolicy{
- public class TrustAll : System.Net.ICertificatePolicy {
- public TrustAll() {
- }
- public bool CheckValidationResult(System.Net.ServicePoint sp,
- System.Security.Cryptography.X509Certificates.X509Certificate cert,
- System.Net.WebRequest req, int problem) {
- return true;
- }
- }
- }
- '@
- $TAResults=$Provider.CompileAssemblyFromSource($Params,$TASource)
- $TAAssembly=$TAResults.CompiledAssembly
- ## We now create an instance of the TrustAll and attach it to the ServicePointManager
- $TrustAll=$TAAssembly.CreateInstance("Local.ToolkitExtensions.Net.CertificatePolicy.TrustAll")
- [System.Net.ServicePointManager]::CertificatePolicy=$TrustAll
- ## end code from http://poshcode.org/624
- ## Set the URL of the CAS (Client Access Server) to use two options are availbe to use Autodiscover to find the CAS URL or Hardcode the CAS to use
- #CAS URL Option 1 Autodiscover
- $service.AutodiscoverUrl($MailboxName,{$true})
- "Using CAS Server : " + $Service.url
- #CAS URL Option 2 Hardcoded
- #$uri=[system.URI] "https://casservername/ews/exchange.asmx"
- #$service.Url = $uri
- ## Optional section for Exchange Impersonation
- function hex2binarray($hexString){
- $i = 0
- [byte[]]$binarray = @()
- while($i -le $hexString.length - 2){
- $strHexBit = ($hexString.substring($i,2))
- $binarray += [byte]([Convert]::ToInt32($strHexBit,16))
- $i = $i + 2
- }
- return ,$binarray
- }
- function GetAutoDiscoverSettings{
- param (
- $adEmailAddress = "$( throw 'emailaddress is a mandatory Parameter' )",
- $Credentials = "$( throw 'Credentials is a mandatory Parameter' )"
- )
- process{
- $adService = New-Object Microsoft.Exchange.WebServices.AutoDiscover.AutodiscoverService($ExchangeVersion);
- $adService.Credentials = $Credentials
- $adService.EnableScpLookup = $false;
- $adService.RedirectionUrlValidationCallback = {$true}
- $UserSettings = new-object Microsoft.Exchange.WebServices.Autodiscover.UserSettingName[] 3
- $UserSettings[0] = [Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::UserDN
- $UserSettings[1] = [Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::InternalRpcClientServer
- $UserSettings[2] = [Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::UserDisplayName
- $adResponse = $adService.GetUserSettings($adEmailAddress , $UserSettings);
- return $adResponse
- }
- }
- function GetAddressBookId{
- param (
- $AutoDiscoverSettings = "$( throw 'AutoDiscoverSettings is a mandatory Parameter' )"
- )
- process{
- $userdnString = $AutoDiscoverSettings.Settings[[Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::UserDN]
- $userdnHexChar = $userdnString.ToCharArray();
- foreach ($element in $userdnHexChar) {$userdnStringHex = $userdnStringHex + [System.String]::Format("{0:X}", [System.Convert]::ToUInt32($element))}
- $Provider = "00000000DCA740C8C042101AB4B908002B2FE1820100000000000000"
- $userdnStringHex = $Provider + $userdnStringHex + "00"
- return $userdnStringHex
- }
- }
- function GetStoreId{
- param (
- $AutoDiscoverSettings = "$( throw 'AutoDiscoverSettings is a mandatory Parameter' )"
- )
- process{
- $userdnString = $AutoDiscoverSettings.Settings[[Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::UserDN]
- $userdnHexChar = $userdnString.ToCharArray();
- foreach ($element in $userdnHexChar) {$userdnStringHex = $userdnStringHex + [System.String]::Format("{0:X}", [System.Convert]::ToUInt32($element))}
- $serverNameString = $AutoDiscoverSettings.Settings[[Microsoft.Exchange.WebServices.Autodiscover.UserSettingName]::InternalRpcClientServer]
- $serverNameHexChar = $serverNameString.ToCharArray();
- foreach ($element in $serverNameHexChar) {$serverNameStringHex = $serverNameStringHex + [System.String]::Format("{0:X}", [System.Convert]::ToUInt32($element))}
- $flags = "00000000"
- $ProviderUID = "38A1BB1005E5101AA1BB08002B2A56C2"
- $versionFlag = "0000"
- $DLLFileName = "454D534D44422E444C4C00000000"
- $WrappedFlags = "00000000"
- $WrappedProviderUID = "1B55FA20AA6611CD9BC800AA002FC45A"
- $WrappedType = "0C000000"
- $StoredIdStringHex = $flags + $ProviderUID + $versionFlag + $DLLFileName + $WrappedFlags + $WrappedProviderUID + $WrappedType + $serverNameStringHex + "00" + $userdnStringHex + "00"
- return $StoredIdStringHex
- }
- }
- function GetPidTagSwappedToDoData {
- param (
- $FlagText = "$( throw 'FlagText is a mandatory Parameter' )",
- $StartTime = "$( throw 'StartTime is a mandatory Parameter' )",
- $DueTime = "$( throw 'DueTime is a mandatory Parameter' )"
- )
- process{
- $todoTimeFlagged = "01000000";
- $PidLidFlagRequest = ""
- $PidLidFlagRequestHexChar = $FlagText.ToCharArray();
- $PidLidFlagRequest = [System.BitConverter]::ToString([System.Text.UnicodeEncoding]::Unicode.GetBytes($FlagText)).Replace("-","")
- #Pad Flag to 512 Bytes
- for ($padCnt = $PidLidFlagRequest.Length / 2; $padCnt -lt 512; $padCnt++) {
- $PidLidFlagRequest = $PidLidFlagRequest + "00";
- }
- $stime = New-Object System.DateTime $StartTime.Year,$StartTime.Month,$StartTime.Day,0,0,0,0,Utc
- $dtime = New-Object System.DateTime $DueTime.Year,$DueTime.Month,$DueTime.Day,0,0,0,0,Utc
- $etime = New-Object System.DateTime 1601, 1, 1, 0, 0, 0, 0,Utc
- [System.TimeSpan]$StartDateTimets = $stime - $etime
- [System.TimeSpan]$DateDueTimets = $dtime - $etime
- $HexDateStartTime = [System.Convert]::ToInt64($StartDateTimets.TotalMinutes).ToString("X8");
- $HexDateStartTime = $HexDateStartTime.Substring(6, 2) + $HexDateStartTime.Substring(4, 2) + $HexDateStartTime.Substring(2, 2) + $HexDateStartTime.Substring(0, 2);
- $HexDateDueTime = [System.Convert]::ToInt64($DateDueTimets.TotalMinutes).ToString("X8");
- $HexDateDueTime = $HexDateDueTime.Substring(6, 2) + $HexDateDueTime.Substring(4, 2) + $HexDateDueTime.Substring(2, 2) + $HexDateDueTime.Substring(0, 2);
- $ulVersion = "01000000";
- $dwFlags = "79000000"; #dwToDoItem,rtmStartDate,rtmDueDate ,wszFlagTo ,fReminderSet
- $dwToDoItem = $todoTimeFlagged;
- $wszFlagTo = $PidLidFlagRequest;
- $rtmStartDate = $HexDateStartTime;
- $rtmDueDate = $HexDateDueTime;
- $rtmReminder = "00000000";
- $fReminderSet = "00000000";
- return ($ulVersion + $dwFlags + $dwToDoItem + $wszFlagTo + $rtmStartDate + $rtmDueDate + $rtmReminder + $fReminderSet);
- }
- }
- #$service.ImpersonatedUserId = new-object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $MailboxName)
- $SenderFlagEmail = New-Object Microsoft.Exchange.WebServices.Data.EmailMessage -ArgumentList $service
- $SenderFlagEmail.ToRecipients.Add("glenscales@yahoo.com");
- $SenderFlagEmail.Subject = "test";
- $SenderFlagEmail.Body = New-Object Microsoft.Exchange.WebServices.Data.MessageBody([Microsoft.Exchange.WebServices.Data.BodyType]::HTML,"test");
- $PR_SWAPPED_TODO_DATA = new-object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(0x0E2D,[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Binary);
- $PR_SWAPPED_TODO_STORE = new-object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(0x0E2C,[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Binary);
- $adset = GetAutoDiscoverSettings -adEmailAddress $MailboxName -Credentials $creds
- $storeID = ""
- if($adset -is [Microsoft.Exchange.WebServices.Autodiscover.AutodiscoverResponse]){
- Write-Host ("Get StoreId")
- $storeID = GetStoreId -AutoDiscoverSettings $adset
- }
- $senderFlagHex = GetPidTagSwappedToDoData -FlagText $SenderFlagText -StartTime $FlagStartDate -DueTime $FlagDueDate
- $SenderFlagEmail.SetExtendedProperty($PR_SWAPPED_TODO_DATA,(hex2binarray $senderFlagHex));
- $SenderFlagEmail.SetExtendedProperty($PR_SWAPPED_TODO_STORE,(hex2binarray $storeID));
- $SenderFlagEmail.SendAndSaveCopy();
- Write-Host ("Message Sent")