Mail item not found on Exchange server using Item ID - c#

I have an application that has been working fine for several weeks, basically it polls an Exchange 2010 mail server mailbox for new messages, gets the details of each one and any attachments, and use that information to create cases (with attachments) on the SalesForce CRM.
After each case is created from the email, the email must be marked as read by retrieving it from Exchange using the stored Item ID and calling the property set.
For several weeks this has been working fine, even getting some extra properties from Exchange such as the Subject, From, To properties which I can use in the session log.
Suddenly today the mail isn't being returned by Exchange from the itemID if I try to include the PropSet - if I omit the PropSet it works fine.
here is the code:
try
{
//creates an object that will represent the desired mailbox
Mailbox mb = new Mailbox(common.strInboxURL); // new Mailbox(targetEmailAddress); #"bbtest#bocuk.local"
//creates a folder object that will point to inbox fold
FolderId fid = new FolderId(WellKnownFolderName.Inbox, mb);
//this will bind the mailbox you're looking for using your service instance
Microsoft.Exchange.WebServices.Data.Folder inbox = Microsoft.Exchange.WebServices.Data.Folder.Bind(service, fid);
// As a best practice, limit the properties returned to only those that are required.
PropertySet propSet = new PropertySet(BasePropertySet.IdOnly,
ItemSchema.Subject, EmailMessageSchema.IsRead, EmailMessageSchema.Sender, EmailMessageSchema.DateTimeReceived);
// Bind to the existing item by using the ItemId.
// This method call results in a GetItem call to EWS.
EmailMessage mail = EmailMessage.Bind(service, itemId); //, propSet);
if (!mail.IsRead) // check that you don't update and create unneeded traffic
{
mail.IsRead = true; // mark as read
mail.Update(ConflictResolutionMode.AutoResolve); // persist changes
}
mail.Update(ConflictResolutionMode.AlwaysOverwrite);
e2cSessionLog("\tcommon.MarkAsRead", "email Item ID: " + itemId);
//e2cSessionLog("\tcommon.MarkAsRead", "MARKED AS READ email Subject: " + mail.Subject.ToString() + "; From: " + mail.Sender.Name, mail.DateTimeReceived.ToString());
return true;
}
catch (Exception ex)
{
string innerException = "";
...
notice that in the line EmailMessage mail = EmailMessage.Bind(service, itemId); //, propSet); I have now omitted the PropSet argument and it now works.
But why?
Is there something else I need to do in order to always get the properties back with the mail returned using Item ID?
Any thoughts?

Related

C# Exchange web service - send and immediately retrieve sent message

The system I'm working has a requirement where the MimeContent of a just-sent email is stored in a local database. My understanding of how Exchange works is that it will create the MimeContent on the server and I cannot access it unless I query the service for that just-sent message.
So, the steps I take are:
-- Send the email and get it's Id
message.SendAndSaveCopy();
return message.Id.UniqueId;
-- Use the new id to get the just-sent EmailMessage
ExchangeService exchangeService = ExchangeService;
var properties = new List<PropertyDefinitionBase>
{
ItemSchema.MimeContent
};
EmailMessage message = EmailMessage.Bind(exchangeService, new ItemId(messageId), new PropertySet(BasePropertySet.IdOnly, properties));
When this code runs without interruption, it works. The Id returned is still valid (message is in the outbox folder perhaps) and I get the result. However, if I slow it down for even a second, the Id is no longer valid (I guess it's now moved into the sent folder).
I cannot leave it like this as there is no guarantee I will get back to the server in time to retrieve the message with that Id.
If there is a solution that involves me not having to query the service for the message again, that'd be swell. However, if not, is there a way I can use the Id and ChangeKey to get the just-sent email?
Eventually answered my own question. I did this by adding a custom property onto each email that I control. I then use that same value to search for the email. I had some issues with the email moving between folders inbetween the queries but it's sorted now.
Define this somewhere, I have it within my EmailProvider class:
private readonly PropertyDefinitionBase _TempEmailId = new ExtendedPropertyDefinition(DefaultExtendedPropertySet.PublicStrings, "TempEmailId", MapiPropertyType.String);
Then add it just before you send the email:
string messageId = null;
if (getTempId)
{
messageId = Guid.NewGuid().ToString();
message.SetExtendedProperty((ExtendedPropertyDefinition) _TempEmailId, messageId);
}
message.SendAndSaveCopy();
return messageId;
Finally, use the messageId to get the MimeContent (or any other properties you desire):
/// <summary>
/// Get the mime content for an email just sent
/// </summary>
/// <param name="messageId"></param>
/// <returns></returns>
public byte[] GetJustSentMimeContent(string messageId)
{
ExchangeService exchangeService = ExchangeService;
// Use the following search filter to get mail with TempEmailId set to what we just got
var searchCriteria = new SearchFilter.IsEqualTo(_TempEmailId, messageId);
var itemView = new ItemView(1) {PropertySet = new PropertySet(BasePropertySet.IdOnly)};
byte[] GetMimeContent(WellKnownFolderName folder)
{
var items = exchangeService.FindItems(folder, searchCriteria, itemView);
if (items.TotalCount > 0)
{
// if it's still in there, try and load the properties for it
exchangeService.LoadPropertiesForItems(items,
new PropertySet(BasePropertySet.IdOnly,
ItemSchema.MimeContent));
var emailMessage = (EmailMessage) items.First();
// if the content has been loaded, return it
if (emailMessage.MimeContent != null)
return emailMessage.MimeContent.Content;
}
return null;
}
// check the drafts folder to see if it's still in there
var mimeContent = GetMimeContent(WellKnownFolderName.Drafts);
if (mimeContent != null)
return mimeContent;
// if at this point, either:
// - email was moved to SentItems before the first search was done
// - or email was found in Drafts but then moved to SentItems but before the MimeContent could be loaded. Need to restart the process and find the email in SentItems instead
// should be in here (sentItems) now, try and load the properties for it
return GetMimeContent(WellKnownFolderName.SentItems);
}

Exchange web services - Forward Email as Attachment

I'm currently using Exchange Web Services in C#. I basically have a small application that reads emails from an inbox and process them.
I would like to forward those emails I receive as an attachment of an email. This attachment will be an outlook email that will include the original email (including its own attachments if any).
Any ideas?
Thanks!
EDIT:
Not sure why I'm getting the down votes but it seems this is not possible as the EWS API does not provide such functionality
You can create an ItemAttachment with EWS but you can't replicate fully what is possible in Outlook with MAPI. Eg with EWS you can create an ItemAttachment and then use the MIMEContent to create an attachment based on a current message as a workaround eg
FolderId Inboxid = new FolderId(WellKnownFolderName.Inbox, "target#domain.com");
ItemView InboxItemView = new ItemView(1);
FindItemsResults<Item> inFiResuls = service.FindItems(Inboxid,InboxItemView);
if(inFiResuls.Items.Count == 1){
EmailMessage fwdMail = new EmailMessage(service);
EmailMessage orgMail = (EmailMessage)inFiResuls.Items[0];
PropertySet psPropSet = new PropertySet(BasePropertySet.FirstClassProperties);
psPropSet.Add(ItemSchema.MimeContent);
orgMail.Load(psPropSet);
ItemAttachment emAttach = fwdMail.Attachments.AddItemAttachment<EmailMessage>();
emAttach.Item.MimeContent = orgMail.MimeContent;
ExtendedPropertyDefinition pr_flags = new ExtendedPropertyDefinition(3591,MapiPropertyType.Integer);
emAttach.Item.SetExtendedProperty(pr_flags,"1");
emAttach.Name = orgMail.Subject;
fwdMail.Subject = "see Attached";
fwdMail.ToRecipients.Add("user#domain.com");
fwdMail.Send();
}
This however doesn't give full fidelity of all the mapi properties associated with a particular message as the MIMEContent is just that, for most normal email messages this isn't an issue however for a message with an attached Outlook Task or other TNEF attachment then you would loose these of attachments or for other properties like categories,flags you would loose these also (you could copy these manually if needed).
Cheers
Glen
you can forward your email using this way. It first loads and reads the each emails with attachment who has "msg" extension. then forwards it to given address. see the below code
FindItemsResults<Item> findResults = exchange.FindItems(WellKnownFolderName.Inbox, newItemView(50,50));
Item[] msgItems = findResults.Where(msgItem => msgItem.HasAttachments).ToArray();
EmailMessage msgInfo = null;
var fileExtensions = new List<string> { "msg", "MSG", "Msg" };
foreach (MSEWS.Item msgItem in msgItems )
{
msgInfo = EmailMessage.Bind(exchange, msgItem.Id);
FileAttachment fa = msgInfo.Attachments[0] asFileAttachment;
if (fileExtensions.Any(ext => ext.Contains(fa.Name.Substring(fa.Name.Length - 3))))
{
fa.Load();
ResponseMessage responseMessage = msgInfo.CreateForward();
responseMessage.BodyPrefix = "messageBody";
responseMessage.ToRecipients.Add("toAddress");
responseMessage.Subject = "subject";
responseMessage.SendAndSaveCopy();
}
}

EWS only reading my inbox [duplicate]

This question already has answers here:
Wrong mailbox items being retrieved using Exchange Web Services managed API in C#
(2 answers)
Closed 8 years ago.
I am trying to read a particular email account to find items with attachments that are unread, and have certain words in the subject.
I have the below code that works but only reads my inbox and not the inbox I want to check
static void Main(string[] args)
{
ServicePointManager.ServerCertificateValidationCallback=CertificateValidationCallBack;
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010_SP2);// .Exchange2007_SP1);
service.UseDefaultCredentials = true;
service.AutodiscoverUrl("bbtest#domainname.com"); //, RedirectionUrlValidationCallback); //bbtest#bocuk.local
ItemView view = new ItemView(1);
string querystring = "HasAttachments:true Kind:email";
//From:'Philip Livingstone' Subject:'ATTACHMENT TEST' Kind:email";
// Find the first email message in the Inbox that has attachments.
// This results in a FindItem operation call to EWS.
FindItemsResults<Item> results = service.FindItems(WellKnownFolderName.Inbox, querystring, view);
foreach (EmailMessage email in results)
if (email.IsRead == false) // && email.HasAttachments == true
{
System.Diagnostics.Debug.Write("Found attachemnt on msg with subject: " + email.Subject);
// Request all the attachments on the email message.
//This results in a GetItem operation call to EWS.
email.Load(new PropertySet(EmailMessageSchema.Attachments));
foreach (Attachment attachment in email.Attachments)
{
if (attachment is FileAttachment)
...
what do I have to change so that my code will read the messages in the inbox of bbtest#domainname.com?
By default your mailbox' inbox folder will be set as root when calling FindItems on ExchangeService object. Assuming your domain account has the necessary permissions to access the other mailbox this below should do the trick. I have ommited the service creation part.
//creates an object that will represent the desired mailbox
Mailbox mb = new Mailbox(#"othermailbox#domain.com");
//creates a folder object that will point to inbox folder
FolderId fid = new FolderId(WellKnownFolderName.Inbox, mb);
//this will bind the mailbox you're looking for using your service instance
Folder inbox = Folder.Bind(service, fid);
//load items from mailbox inbox folder
if(inbox != null)
{
FindItemsResults<Item> items = inbox.FindItems(new ItemView(100));
foreach(var item in items)
Console.WriteLine(item);
}

Retrieving Some Email Information

I'm trying to obtain some information from emails sent to an Outlook email. I've successfully connected to the Exchange Server and have been able to retrieve some information from emails with attachments (I am skipping emails without attachments).
What I Have: I can retrieve the attachment file name, the email date, and the email subject.
What I Need: I need to retrieve the sender name and email also. From what I've done, I can retreive the body of the email (in HTML), but not the body text only (requires Exchange 2013 - Hello MS advertising).
I'm new to C# and today is my first time to connect to the Exchange Server. I noticed from reading around that "find" is limited in what it can obtain, and that I'll need to bind the message in order to get more information from the email.
Code thus far:
foreach (Item item in findResults.Items)
if (item.HasAttachments) // && item.Attachments[0] is FileAttachment)
{
item.Load();
FileAttachment fileAttachment = item.Attachments[0] as FileAttachment;
date = Convert.ToString(item.DateTimeCreated);
name = Convert.ToString(fileAttachment.Name);
fileAttachment.Load("C:\\test\\" + fileAttachment.Name);
Console.WriteLine(name);
Console.WriteLine(item.Subject);
Console.WriteLine(date);
}
My question from here is if I do EmailMessage msg = EmailMessage.Bind ... what information will I need in order to grab more information?
Solved - for getting sender email and name as well as loading an attachment.
I used the EmailMessage class (just added it in the above loop, and added the variables to the beginning):
EmailMessage msg = (EmailMessage)item;
senderemail = Convert.ToString(msg.Sender.Address);
sendername = Convert.ToString(msg.Sender.Name);
I can then reproduce these on the console:
Console.WriteLine(senderemail);
Console.WriteLine(sendername);
Also, for loading an email's attaachment, I declared a byte[] variable at the beginning, loaded the attachment, converted it, and wrote its content to the console:
fileAttachment.Load();
filecontent = fileAttachment.Content;
System.Text.Encoding enc = System.Text.Encoding.ASCII;
string strFileContent = enc.GetString(filecontent);
Console.WriteLine(strFileContent);

How do I determine the sender of an email via Exchange Web Services in C#?

I'm currently pulling emails from an exchange inbox like so...
var exchangeService = new ExchangeService(ExchangeVersion.Exchange2007_SP1)
{
Credentials = new NetworkCredential("user", "password", "domain")
};
exchangeService.AutodiscoverUrl("user#domain.com");
var emails = exchangeService.FindItems(WellKnownFolderName.Inbox, new ItemView(5));
foreach (var email in emails)
{
//var senderEmail = email.???
}
The email object doesn't seem to have any property for getting the sender's email address. How do I get that?
Here's some quick source I pulled from a working project example.
Basically, you can get minor details just by casting your result to an EmailMessage. However if you want to get richer details about the sender (display name, etc.) then you have to make a specific, additional bind (Web service request) against the message.
findResults = exchangeService.FindItems(folder.Id, messageFilter, view);
foreach (Item item in findResults)
{
if (item is EmailMessage)
{
EmailMessage message;
if (!toFromDetails)
message = (EmailMessage)item;
else
message = EmailMessage.Bind(exchangeService, item.Id);
As you can see in this code, I have an option to perform the additional bind, because it can take awhile, and I'm often dealing with thousands of results from hundreds of mailboxes. Sometimes the additional time may not be worth it to a particular customer.

Categories

Resources