You are hereBlogs / rahul's blog / Exchange - Saving mails to delegated User's mailbox with EWS Managed API

Exchange - Saving mails to delegated User's mailbox with EWS Managed API


rahul's picture

By rahul - Posted on 24 December 2010

Microsoft Exchange allows a user to access another User's mailbox in 2 ways, Delegation and Impersonation (Check this for more details). If you have used Outlook or Outlook web Access (OWA) and shared mailboxes with other users, chances are that you used Exchange delegation for mailbox sharing.

For our Exchange email client for corporates, we were using delegation to enable users to share Mailboxes, when we faced an important constraint. If you (the delegate) are accessing someone else's (the delegator's) mailbox via Exchange delegation, any mails sent on behalf of the delegator would appear in your (delegate's) mailbox's Sent Items. Ideally, it should have shown in the delegator's Sent Items.

This is a documented (see this) Exchange constraint. However, we were surprised to see that Outlook and OWA did not follow this constraint and mails sent through them on behalf of the delegator actually appeared in the delegator's mailbox only (which was desired).

We thought there must be some trick to accomplish this for our own mail client (which uses Exchange Web Services Managed API for Exchange interaction).

After some testing, I got the following code to work and save the email sent to delegator's sent items folder when sent by a delegate:

 

message.Send();
message.Save(new FolderId(WellKnownFolderName.SentItems, new Mailbox("delegator@example.com")));

Exchange delegation allows you to save Mails to delegator's account. So, what I did was to send the mail without saving it to the delegate's mailbox, and then save it in the delegator's mailbox after it was sent.

The above approach worked fine, until it was reported that it failed if the Mail being sent had attachments. The error reported by Exchange was that you cannot call Save() for items that have already been saved (but instead should call Update()). This made sense, because attachments were automatically saved on Exchange when Send() was called. But we could not call Update() as the attachments were saved to delegate's mailbox, but we wanted to save in delegator's mailbox.

Again a quick check in OWA established that it saved the mail with attachments to delegator's mailbox only, providing sufficient clue that this should be possible.

Some more tweaking of the code, and this worked for mails with attachments:

 

message.Save(new FolderId(WellKnownFolderName.Drafts, new Mailbox("delegator@example.com")));
message.SendAndSaveCopy(new FolderId(WellKnownFolderName.SentItems, new Mailbox("delegator@example.com")));

This time, we saved the message first to delegator's Drafts folder, and then sent it saving it to the delegator's SentItems folder after the mail was sent.

The combination of above approaches with the first being used if no attachments are present, and the second used for mails sent on behalf of delegator with attachments resolved all scenarios.

Now, I really wonder, why MSDN says "Messages that are sent by delegates are saved in the delegate’s Sent Items folder", and does not provide this simple work-around to save messages sent to delegator's mailbox.

UPDATE:

  • Jan 7, 2011 - During my later testing, I found that there are issues with the first approach when forwarding/replying to mails for a delegated mailbox. So, I now instead use the second code above only, whether or not the mail has attachments. To eliminate any confusions, here is what I use now, no matter the mail has attachments or not:

    if (!savedAlready)
    {
    	message.Save(new FolderId(WellKnownFolderName.Drafts, new Mailbox("delegator@example.com")));
    }
    message.SendAndSaveCopy(new FolderId(WellKnownFolderName.SentItems, new Mailbox("delegator@example.com")));

    While forwarding/replying to mails for the delegated mailbox, I set a flag which indicates that the Mail is already saved. You cannot call Save() on the mail MailMessage twice (it would give an exception, instead you need to use Update() after the initial Save() for the EmailMessage). The check for !savedAlready ensures that no exception occurs is the mail is already saved.

 

Hi Rahul,

First of all, I am glad someone else is having the same problem as me! So far all I have been able to find out is that this can only be accomplished using 3rd party tools.  However I am, as yet, unable to find one that is able to run in non-cached mode.  A requirement as we are using a terminal server environment.  Therefore the code you have listed above sounds very good! My question is how do I implement this code so that I can use it?

I look forward to hearing from you.

Kind Regards,

Elia

rahul's picture

Hi Elia, the title and body of this blog post clearly mention that it uses Exchange Managed API to interact with Exchange Server.

Hello,…

Allthough this article is about Outlook 2007, I would like to add the correct way of using this features, as well as the correct behaviour of Sent and Deleted Items in the Oulook 2010 version. A couple of weeks ago, I published aan article about this on my site. Please take a look at: Url removed by moderator  My personal mail address is in one of the pictures.

have fun using Out;look 2010!

Regards,
Ben

rahul's picture

Hi Ben, you should have taken a more closer look at the blog post before commenting. It does not relate to Outlook (2007 or 2010) but to interacting directly with Exchange with EWS Managed API. Your url was not consistent with the theme of the blog post and has been removed. And you posted the same comment 4 times, which is considered an abuse and might lead to disabling of your comment posting access if it happens again.

Thank you so much for posting this solution.

hi Rahul,

First thanks for a very useful article. I am wondering if you have got success with composing html emails using EWS Managed API with Inline images and savign to drafts. The process explained by microsoft works if I use SendandSaveCopy() method but doesn't work if I use Save() method to save it to drafts. Emails saves to draft and attachments will be there but wont be inline. If I mark them inline, they simply disappear.

I have requested help on this earlier at Stackoverflow, any help is greatly appreciated.

Bhuvan

rahul's picture

Hi Bhuvan, I haven't tried that (saving inline images to Drafts). Please ensure that the attachment is being properly uploaded when being saved to Drafts. Also note that when you mark an Image as Inline, I think it normally does not show up in regular attachments collection (but still exists with the Exchange Email object).

You need to write special code to parse inline images from mail body html and convert them into image tags pointing to your server which return the image fetched from Exchange with proper content type headers (I will try to post related code soon).

I guess you are not parsing inline image tags from body properly. If you are sure you have everything setup correctly, you might then want to file a bug report with MS Connect (or discuss at official EWS forums).

i am sending mail through exchange server version Exchange2010.

below is my code:

static void Main()
       
{
           
try
           
{
               
string owausername = string.Empty;
               
string owapassword = string.Empty;
               
string mailFrom;
               
string mailTo;
               
string mailSub;
               
string mailBody;
 
               
ServicePointManager.ServerCertificateValidationCallback = CertificateValidationCallBack;
               
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010);
               
EmailMessage email = new EmailMessage(service);
 
               
string reg_subKey = "Software\\VB and VBA Program Settings\\LangServ15.2";
               
RegistryKey root = Registry.CurrentUser.CreateSubKey(reg_subKey);
               
foreach (string keyname in root.GetSubKeyNames())
               
{
                   
using (RegistryKey key = root.OpenSubKey(keyname, true))
                   
{
                       
foreach (string valueName in key.GetValueNames())
                       
{
 
                           
if (valueName == "owausername")
                           
{
                               
if (key.GetValue(valueName).ToString() != "")
                               
{
                                    owausername
= key.GetValue(valueName).ToString();
                               
}
                           
}
                           
if (valueName == "owapassword")
                           
{
                               
if (key.GetValue(valueName).ToString() != "")
                               
{
                                    owapassword
= key.GetValue(valueName).ToString();
                               
}
                           
}
                            service
.Credentials = new WebCredentials(owausername, owapassword);
                           
if (valueName == "owaurl")
                           
{
                               
if (key.GetValue(valueName).ToString() != "")
                               
{
                                    service
.Url = new Uri(key.GetValue(valueName).ToString());
                               
}
                           
}
                           
if (valueName == "textFrom")
                           
{
                               
if (key.GetValue(valueName).ToString() != "")
                               
{
                                    mailFrom
= key.GetValue(valueName).ToString();
                               
}
                           
}
                           
if (valueName == "textTo")
                           
{
                                mailTo
= key.GetValue(valueName).ToString();
                                email
.ToRecipients.Add(mailTo);
                           
}
                           
if (valueName == "textSub")
                           
{
                                mailSub
= key.GetValue(valueName).ToString();
                                email
.Subject = mailSub;
                           
}
                           
if (valueName == "textBody")
                           
{
                                mailBody
= key.GetValue(valueName).ToString();
                                email
.Body = mailBody;
 
                           
}
                       
}
                        root
.DeleteSubKey(keyname);
                   
}
               
}
                email
.SendAndSaveCopy();
               
System.Windows.Forms.MessageBox.Show("Email Sent Successfully...");
           
}
           
catch (Exception ex)
           
{
               
if (ex.Message.ToString() == "The request failed. The remote server returned an error: (401) Unauthorized.")
               
{
                   
System.Windows.Forms.MessageBox.Show("The OWA user name or OWA password you entered isn't correct. Enter corrent credentials and then Try again.");
               
}
               
//throw ex;
           
}
       
}
       
private static bool CertificateValidationCallBack(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate, System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors)
       
{
           
return true;
       
}

what i am doing i made .exe of this code and calling from my vb6.0 application. it works fine on my local machine. but when i upload it on my live server and test, it stucks at line email.SendAndSaveCopy();

don't know what is the problem. All other things are going fine. help would be appreciated.

thanks,
kk

rahul's picture

Hi Krunal, its difficult to speculate on the reason based on information provided, so many things can go wrong (it could be a permissions issue, trustLevel, firewall blocking the outbound connection etc). You will need to check server logs. It can't be stuck there forever, sooner or later, the call would time out. You can add a try/catch around SendAndSaveCopy and log the stack trace which should help you debug the issue.

Hi Rahul,

Thanks for posting a very useful article. I was able to save the emails in either the sentitems folder or drafts folder, but unable to configure it to do the same when I create a userdefined folder. I have many applications and want the sent emails to go to various userdefined folders. Do you have any clue if thats possible?

Thanks,
Anita

rahul's picture

Hi Anita, I haven't tried that but should be possible. In this code:

 

message.Save(new FolderId(WellKnownFolderName.Drafts, new Mailbox("delegator@example.com")));
message.SendAndSaveCopy(new FolderId(WellKnownFolderName.SentItems, new Mailbox("delegator@example.com")));

Please pass the first argument as the FolderId for your user-defined folder from the delegated mailbox.

 

Hi,

Thank you for a very helpfull blog.

I know this artical is around saving mail to a delegated user, but would it be possible to save a contact to a delegated user?

Thanks in advance,

Tom

rahul's picture

Hi Tom, I think you should be able to change WellKnownFolderName to Contacts, use a Contact object (instead of MailMessage) and save to delegated account folder, worth atleast a try :)

Post new comment

The content of this field is kept private and will not be shown publicly.
Type the characters you see in this picture. (verify using audio)
Type the characters you see in the picture above; if you can't read them, submit the form and a new image will be generated. Not case sensitive.

Recent comments