3

Running Exchange 2013

I am using EWS in a c# service that sends emails from a service account.

I want to have the emails have a reply-to address different than the sending account, a distribution list address.

How can I do this? The EmailMessage.ReplyTo field is read only.

Code:

ExchangeService service = new ExchangeService();
service.Credentials = EWScredentials;
service.Url = new Uri(string.Format("https://{0}/EWS/Exchange.asmx", ExchangePath));

EmailMessage message = new EmailMessage(service);
message.ToRecipients.AddRange(receipients);

//This didn't work
message.ReplyTo.Clear();
message.ReplyTo.Add(replyToAddress);

message.Subject = subject;
message.Body = html;
message.SendAndSaveCopy();

Only other thread that seemed related, though I'm not using powershell: How do you set a message Reply-To address using EWS Managed API?

Community
  • 1
  • 1
Aaron
  • 1,390
  • 1
  • 16
  • 30

5 Answers5

4

You can use the PidTagReplyRecipientEntries extended property https://msdn.microsoft.com/en-us/library/office/cc815710.aspx to do that eg

        EmailMessage DifferentReplyTo = new EmailMessage(service);
        DifferentReplyTo.Subject = "test";
        DifferentReplyTo.ToRecipients.Add("destination@domain.com");
        DifferentReplyTo.Body = new MessageBody("test");           
        ExtendedPropertyDefinition PidTagReplyRecipientEntries = new ExtendedPropertyDefinition(0x004F, MapiPropertyType.Binary);
        ExtendedPropertyDefinition PidTagReplyRecipientNames = new ExtendedPropertyDefinition(0x0050, MapiPropertyType.String);
        DifferentReplyTo.SetExtendedProperty(PidTagReplyRecipientEntries, ConvertHexStringToByteArray(GenerateFlatList("departmentdg@domain.com", "jc")));
        DifferentReplyTo.SetExtendedProperty(PidTagReplyRecipientNames, "jc");
        DifferentReplyTo.SendAndSaveCopy();

    internal static String GenerateFlatList(String SMTPAddress, String DisplayName)
    {
        String abCount = "01000000";
        String AddressId = GenerateOneOff(SMTPAddress, DisplayName);
        return abCount + BitConverter.ToString(INT2LE((AddressId.Length / 2) + 4)).Replace("-", "") + BitConverter.ToString(INT2LE(AddressId.Length / 2)).Replace("-", "") + AddressId;
    }

    internal static String GenerateOneOff(String SMTPAddress,String DisplayName)
    {
        String Flags = "00000000";
        String ProviderUid = "812B1FA4BEA310199D6E00DD010F5402";
        String Version = "0000";
        String xFlags = "0190";
        String DisplayNameHex = BitConverter.ToString(UnicodeEncoding.Unicode.GetBytes(DisplayName + "\0")).Replace("-","");
        String SMTPAddressHex = BitConverter.ToString(UnicodeEncoding.Unicode.GetBytes(SMTPAddress + "\0")).Replace("-", "");
        String AddressType = BitConverter.ToString(UnicodeEncoding.Unicode.GetBytes("SMTP" + "\0")).Replace("-", "");
        return Flags + ProviderUid + Version + xFlags + DisplayNameHex + AddressType + SMTPAddressHex;
    }
    internal static byte[] INT2LE(int data)
    {
        byte[] b = new byte[4];
        b[0] = (byte)data;
        b[1] = (byte)(((uint)data >> 8) & 0xFF);
        b[2] = (byte)(((uint)data >> 16) & 0xFF);
        b[3] = (byte)(((uint)data >> 24) & 0xFF);
        return b;
    }
    internal static byte[] ConvertHexStringToByteArray(string hexString)
    {
        if (hexString.Length % 2 != 0)
        {
            throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, "The binary key cannot have an odd number of digits: {0}", hexString));
        }

        byte[] HexAsBytes = new byte[hexString.Length / 2];
        for (int index = 0; index < HexAsBytes.Length; index++)
        {
            string byteValue = hexString.Substring(index * 2, 2);
            HexAsBytes[index] = byte.Parse(byteValue, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
        }

        return HexAsBytes;
    }

Cheers Glen

Glen Scales
  • 20,495
  • 1
  • 20
  • 23
  • 1
    so, 1 issue: the `ConvertHexStringToByteArray` method isn't present in your code. perhaphs you mean something like http://stackoverflow.com/questions/321370/how-can-i-convert-a-hex-string-to-a-byte-array ? – Aaron Mar 16 '16 at 17:47
  • 1
    using the code from that question to add a `ConvertHexStringToByteArray` method and trying your code doesn't seem to change the reply to address, at least not on our employees outlook clients. it does compile and run though – Aaron Mar 16 '16 at 18:38
  • 1
    I've added the conversion method I used if you check the Transport headers what do you see ? It tests okay for me, one thing you can do is try doing the same thing in outlook and then use a Mapi editor to compare the two values between Outlook and your code. – Glen Scales Mar 17 '16 at 03:47
  • 1
    Ok so I compiled and executed the code, and am looking at the email i received from Exchange in MS's MAPI editor. I havn't used the editor before so still getting the hang of it, it lists Properties and Values. The property `PR_REPLY_RECIPIENT_ENTRIES` did not appear in the list. I also see from the document linked, that `If either this property or the PR_REPLY_RECIPIENT_NAMES property is set, the other property must be set also.` Either way, it doesn't seem to be working yet. BTW we are running exchange 2013 and I'm running Outlook 2016 – Aaron Mar 17 '16 at 13:55
  • I've added PidTagReplyRecipientNames to the code sample its just a string property. You need to look at the copy of the message in the SentItems folder to see those properties as these are envelope properties they won't appear on the Message that is received. For that you should just be looking at the Transport Headers to see if you can see a Reply-To header. I'm using Office365 (so Exchange 2016) and Outlook 2013 but it should be the same as Exchange 2013 – Glen Scales Mar 18 '16 at 02:20
  • Works great! not sure what step fixed my problem! I can now see the property in the editor, and in outlook it is respecting the address. Thanks! – Aaron Mar 22 '16 at 16:25
0

that work for me :

EmailAddressCollection emailAddressCollection = new EmailAddressCollection();
emailAddressCollection.add(new EmailAddress("ReplayToEmail@gmail.com"));
emailMessage.getPropertyBag().setObjectFromPropertyDefinition(EmailMessageSchema.ReplyTo, emailAddressCollection);
0

I solved this by loading the ToRecipients and CcRecipients properties on the EmailMessage replyMessage object.

C# code is something like this:

// somehow get a hold of an ExchangeService object
var message = service.Bind(service, mail.Id);
var replyMessage = message.CreateReply(replyToAll: true);

replyMessage.Load(new PropertySet() { EmailMessageSchema.ToRecipients, EmailMessageSchema.CcRecipients });

replyMessage.ToRecipients.Add("some_email@email.com");
replyMessage.CcRecipients.Add("some_email_cc@email.com");

replyMessage.Send();

Of course, if you don't plan on working with Cc, you don't have to load it. This allows you to append new addresses, or clear the recipients and add whatever you want.

George D
  • 41
  • 1
  • 2
  • 9
0

There is a simpler solution: use ResponseMessage:

ResponseMessage responseMessage = originalEmail.createReply(isReplyAll);
responseMessage.getToRecipients().addEmailRange(...email address...);
responseMessage.sendAndSaveCopy();
blaiz128
  • 115
  • 9
0

I'm sure it's due to this question being 6 years old, and the library has been updated since.

The ReplyTo property is a readonly EmailAddressCollection that can be cleared, and added to.

var emailSend = new EmailMessage(service)
emailSend.ToRecipients.Add("recipient@example.com");

// change the reply-to
if(email.FromAddress.ToLower() != "noreply@example.com"){
    emailSend.ReplyTo.Clear();
    emailSend.ReplyTo.Add(new EmailAddress() { Address = "replyto@example.com" });
}
                                
emailSend.Save();
emailSend.Send(); 
InbetweenWeekends
  • 1,405
  • 3
  • 23
  • 28