Voting button's in emails are one the long standing features of using Outlook with Exchange, in Exchange 2013 SP1 there is now support for responding to Vote requests with EWS . However there is still no direct support for sending a message with voting buttons in EWS, so in this post I'm going to show a method you can use to send a message with Voting Button in EWS by setting the PidLidVerbStream extended Property on a message which is documented in the http://msdn.microsoft.com/en-us/library/ee218541(v=exchg.80).aspx .
I used this property a few months back in another script for stopping ReplyAll on a message, this script uses much the same code with the addition of Hex values for the Voting options to include in the Message. Firstly each voting option you want to add uses the VoteOption Structure http://msdn.microsoft.com/en-us/library/ee218406(v=exchg.80).aspx . This is reasonable straight forward eg
$ApproveOption = "0400000007417070726F76650849504D2E4E6F74650007417070726F766500000000000000000001000000020000000200000001000000FFFFFFFF"
equates to
04000000 VerbType
07 Length of the DisplayName eg the length of (Approve)
417070726F7665 (Approve in Hex)
08 Length of the MsgClsNameCount eg the length of (IPM.Note)
49504D2E4E6F7465 (IPM.Note in Hex)
00 Internal1StringCount
07417070726F7665 Repeat of the DisplayName and Length
The rest of the options are listed in the documentation link the one interesting option is SendBehavior which allows you to control if you want the user to be prompted about the response of to just send it immediately. In my example scripts its set to prompt the user
The following script will send a message using EWS with Appove/Reject voting buttons I've put a download of this script here the code itself looks like
I used this property a few months back in another script for stopping ReplyAll on a message, this script uses much the same code with the addition of Hex values for the Voting options to include in the Message. Firstly each voting option you want to add uses the VoteOption Structure http://msdn.microsoft.com/en-us/library/ee218406(v=exchg.80).aspx . This is reasonable straight forward eg
$ApproveOption = "0400000007417070726F76650849504D2E4E6F74650007417070726F766500000000000000000001000000020000000200000001000000FFFFFFFF"
equates to
04000000 VerbType
07 Length of the DisplayName eg the length of (Approve)
417070726F7665 (Approve in Hex)
08 Length of the MsgClsNameCount eg the length of (IPM.Note)
49504D2E4E6F7465 (IPM.Note in Hex)
00 Internal1StringCount
07417070726F7665 Repeat of the DisplayName and Length
The rest of the options are listed in the documentation link the one interesting option is SendBehavior which allows you to control if you want the user to be prompted about the response of to just send it immediately. In my example scripts its set to prompt the user
The following script will send a message using EWS with Appove/Reject voting buttons I've put a download of this script here the code itself looks like
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | $MailboxName = $args[0] $SentTo = $args[1] $VerbSetting = "" | Select DisableReplyAll,DisableReply,DisableForward,DisableReplyToFolder $VerbSetting.DisableReplyAll = $false $VerbSetting.DisableReply = $false $VerbSetting.DisableForward = $false $VerbSetting.DisableReplyToFolder = $false ## Load Managed API dll ###CHECK FOR EWS MANAGED API, IF PRESENT IMPORT THE HIGHEST VERSION EWS DLL, ELSE EXIT $EWSDLL = (($(Get-ItemProperty -ErrorAction SilentlyContinue -Path Registry::$(Get-ChildItem -ErrorAction SilentlyContinue -Path 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Exchange\Web Services'|Sort-Object Name -Descending| Select-Object -First 1 -ExpandProperty Name)).'Install Directory') + "Microsoft.Exchange.WebServices.dll") if (Test-Path $EWSDLL) { Import-Module $EWSDLL } else { "$(get-date -format yyyyMMddHHmmss):" "This script requires the EWS Managed API 1.2 or later." "Please download and install the current version of the EWS Managed API from" "http://go.microsoft.com/fwlink/?LinkId=255472" "" "Exiting Script." exit } ## 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 #$service.ImpersonatedUserId = new-object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $MailboxName) function Get-VerbStream{ param ( $VerbSettings = "$( throw 'VerbSettings is a mandatory Parameter' )" ) process{ $Header = "02010600000000000000" $ReplyToAllHeader = "055265706C790849504D2E4E6F7465074D657373616765025245050000000000000000" $ReplyToAllFooter = "0000000000000002000000660000000200000001000000" $ReplyToHeader = "0C5265706C7920746F20416C6C0849504D2E4E6F7465074D657373616765025245050000000000000000" $ReplyToFooter = "0000000000000002000000670000000300000002000000" $ForwardHeader = "07466F72776172640849504D2E4E6F7465074D657373616765024657050000000000000000" $ForwardFooter = "0000000000000002000000680000000400000003000000" $ReplyToFolderHeader = "0F5265706C7920746F20466F6C6465720849504D2E506F737404506F737400050000000000000000" $ReplyToFolderFooter = "00000000000000020000006C00000008000000" $ApproveOption = "0400000007417070726F76650849504D2E4E6F74650007417070726F766500000000000000000001000000020000000200000001000000FFFFFFFF" $RejectOption= "040000000652656A6563740849504D2E4E6F7465000652656A65637400000000000000000001000000020000000200000002000000FFFFFFFF" $VoteOptionExtras = "0401055200650070006C00790002520045000C5200650070006C007900200074006F00200041006C006C0002520045000746006F007200770061007200640002460057000F5200650070006C007900200074006F00200046006F006C00640065007200000741007000700072006F00760065000741007000700072006F007600650006520065006A0065006300740006520065006A00650063007400" if($VerbSetting.DisableReplyAll){ $DisableReplyAllVal = "00" } else{ $DisableReplyAllVal = "01" } if($VerbSetting.DisableReply){ $DisableReplyVal = "00" } else{ $DisableReplyVal = "01" } if($VerbSetting.DisableForward){ $DisableForwardVal = "00" } else{ $DisableForwardVal = "01" } if($VerbSetting.DisableReplyToFolder){ $DisableReplyToFolderVal = "00" } else{ $DisableReplyToFolderVal = "01" } $VerbValue = $Header + $ReplyToAllHeader + $DisableReplyAllVal + $ReplyToAllFooter + $ReplyToHeader + $DisableReplyVal +$ReplyToFooter + $ForwardHeader + $DisableForwardVal + $ForwardFooter + $ReplyToFolderHeader + $DisableReplyToFolderVal + $ReplyToFolderFooter + $ApproveOption + $RejectOption + $VoteOptionExtras return $VerbValue } } 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 } $VerbStreamProp = new-object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition([Microsoft.Exchange.WebServices.Data.DefaultExtendedPropertySet]::Common,0x8520, [Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Binary) $VerbSettingValue = get-VerbStream $VerbSetting $EmailMessage = New-Object Microsoft.Exchange.WebServices.Data.EmailMessage -ArgumentList $service $EmailMessage.Subject = "Message Subject" #Add Recipients $EmailMessage.ToRecipients.Add($SentTo) $EmailMessage.Body = New-Object Microsoft.Exchange.WebServices.Data.MessageBody $EmailMessage.Body.BodyType = [Microsoft.Exchange.WebServices.Data.BodyType]::HTML $EmailMessage.Body.Text = "Body" $EmailMessage.SetExtendedProperty($VerbStreamProp,(hex2binarray $VerbSettingValue)) $EmailMessage.SendAndSaveCopy() |