How to read emails message BodyText through EWS? C# - c#

I would like to get all messages.BodyText in my email. I have already some code, tried many things, but didn't catch what really will work.
My code:
ExchangeService service;
service = new ExchangeService
{
Credentials = new WebCredentials("mail.com", #"password")
};
List<String> items = new List<String>();
// This is the office365 webservice URL
service.Url = new Uri("https://outlook.office365.com/EWS/Exchange.asmx");
ItemView view = new ItemView(50);
FindItemsResults<Item> Items = service.FindItems(WellKnownFolderName.Inbox, view); // line 34
// 'Object reference not set to an instance of an object.' / on line 34
foreach (Item item in Items)
{
if (item is EmailMessage)
{
item.Load();
string subject = item.Subject;
string mailMessage = item.Body;
}
items.Add(item.TextBody); // line 44
//You must load or assign this property before you can read its value / on line 44
}
foreach (var item in items)
{
Console.WriteLine(item);
}
When I'm trying to run my code, then I got two errors:
You must load or assign this property before you can read its value / on line 44
'Object reference not set to an instance of an object.' / on line 34
The second error is working from time to time, I'm not sure what is wrong.
Thank you in advance!

If you want the Text body of the message then you need to use a propertyset that will specifically request that. A message may not have a Text body so in that instance the Exchange store will do an on the fly conversion what you code should look like is
PropertySet psPropSet = new PropertySet(BasePropertySet.FirstClassProperties)
{
RequestedBodyType = BodyType.Text
};
foreach (Item item in Items)
{
if (item is EmailMessage)
{
item.Load(psPropSet);
string subject = item.Subject;
string mailMessage = item.Body;
}
items.Add(item.TextBody);
}
Keep in mind this will make a call to the Exchange server every time you call Load which is really inefficient and done on a large scale will mean you code with be throttled. This can be batched using LoadPropertiesForItems in EWS eg https://learn.microsoft.com/en-us/answers/questions/614111/processing-120k-emails-takes-more-than-a-day-using.html

Try calling the load method before attempting to assign a value.
In your code here:
foreach (Item item in Items)
{
if (item is EmailMessage)
{
item.Load();
string subject = item.Subject;
string mailMessage = item.Body;
}
items.Add(item.TextBody); // line 44
//You must load or assign this property before you can read its value / on line 44
}
You are checking if an item is EmailMessage. There may be some in the list that are not an EmailMessage which would cause them to be accessed before using the Load method.
You could try putting the item load outside of the conditional and that would most likely fix the issue.
Please see this question here:
Error when I try to read/update the .Body of a Task via EWS Managed API - "You must load or assign this property before you can read its value."

Related

ServiceObjectPropertyException when trying to get emails with Exchange Webservices?

I am trying to get unread emails and then mark them as read.
I am getting this exception when I run the code:
ServiceObjectPropertyException was unhandeld:
An unhandled exception of type
'Microsoft.Exchange.WebServices.Data.ServiceObjectPropertyException'
occurred in Microsoft.Exchange.WebServices.dll
This error occurred when I try to map my Exchange mail object to my business model object.
This is the Map method:
class MailMapper
{
public static PhishingMail Map(EmailMessage OutlookMail)
{
//Map Exchange email object op Business model email object
PhishingMail readMail = new PhishingMail();
readMail.Subject = OutlookMail.Subject;
return readMail;
}
}
This is the code where it should mark emails as read.
public List<PhishingMail> GetEmails()
{
phishingMailList = new List<PhishingMail>();
FolderId InboxId = new FolderId(WellKnownFolderName.Inbox, "A*******m#i*****nl");
FindItemsResults<Item> findResults = service.FindItems(InboxId, new ItemView(100));
foreach (Item phishingmail in findResults.Items)
{
((EmailMessage)phishingmail).Load(new PropertySet(BasePropertySet.IdOnly, EmailMessageSchema.IsRead));
if (!((EmailMessage)phishingmail).IsRead)
{
((EmailMessage)phishingmail).IsRead = true;
((EmailMessage)phishingmail)
.Update(ConflictResolutionMode.AutoResolve);
}
PhishingMail mail = MailMapper.Map((EmailMessage)phishingmail);
phishingMailList.Add(new PhishingMail());
/// Console.WriteLine(mail.Subject);
}
return phishingMailList;
}
What am I doing wrong? What is wrong with map method?
When you load an item, you speficy the properties to load.
item.Load(new PropertySet(PropertySet.FirstClassProperties));
If you need more properties after loading, you can do the following:
Service.LoadPropertiesForItems(items, PropertySet.FirstClassProperties);
I think the issue is that when you Load the email you're only asking for the ID and IsRead properties. Since your map routine fetches the Subject property, you would need to add that to the Load as well.

Use attachments from calendar items - Outlook - C#

I'm trying to use the attachments included in calendar items pulled progmatically.
I have a list of chosen calendar subject lines from a previous dialog box, and while the subject is transferring properly, the body isn't working well (another question altogether) but the attachments aren't working whatsoever.
Here's my foreach loop where the attachments are being placed into an Attachments array for use later:
string[] subjects = new string[dialog.chosen.Count];
string[] bodies = new string[dialog.chosen.Count];
Attachments[] attach = new Attachments[dialog.chosen.Count];
foreach (Outlook.AppointmentItem appt in rangeAppts)
{
foreach (string text in dialog.chosen)
{
if (text == appt.Subject)
{
subjects[i] = appt.Subject;
bodies[i] = Convert.ToString(appt.Body);
attach[i] = appt.Attachments;
i = i + 1;
}
}
}
And then here's where I actually call the method:
sendEmailTemplate(bodies[i], subject, to, "", attachment: attach[i]);
And then the method itself:
public void sendEmailTemplate(string body, string subject, string to, string cc , Attachments attachment = null)
{
Microsoft.Office.Interop.Outlook.Application oApp = new Microsoft.Office.Interop.Outlook.Application();
Microsoft.Office.Interop.Outlook._MailItem oMailItem = (Microsoft.Office.Interop.Outlook._MailItem)oApp.CreateItem(Microsoft.Office.Interop.Outlook.OlItemType.olMailItem);
oMailItem.HTMLBody = body;
oMailItem.Subject = subject;
try
{
oMailItem.Attachments.Add(attachment);
}
catch {}
oMailItem.To = to;
oMailItem.CC = cc;
oMailItem.Display(false);
oMailItem.Application.ActiveInspector().WindowState = Microsoft.Office.Interop.Outlook.OlWindowState.olNormalWindow;
}
I've tried several things, however when I actually go to send the e-mail, I end up getting:
Exception: Member not found. HRESULT: 0x80020003
And then I haven't been able to get anything else to work. The try/catch loop on the method is to prevent the above exception as I was getting that exception regardless of whether or not an attachment was present, and now attachments just aren't being added.
I'm using Interop that comes with Office along with C#. Winforms if that makes a difference.
MailItem.Attachments takes either a string (fully qualified file name), or another Outlook item (MailItem, ContactItem, etc.).
You cannot pass Attachments object as an argument. If you need to copy the attachments, loop through all attachments in the Attachments collection, call Attachment.SaveAsFile for each attachment, pass the file name to MailItem.Attachments.Add, delete thee temporary file.

EWS - Determine if an e-mail is a reply or has been forwarded

I am using the Exchange Web Services Managed API 2.2 to monitor users inboxes and need to determine if an e-mail is a new item, a reply or a forwarded message.
I have seen various articles on SO such as how to notice if a mail is a forwarded mail? and Is there a way to determine if a email is a reply/response using ews c#? which both help in their specific cases but I still cannot work out how to distinguish between a reply and a forwarded item.
In the first article an extra 5 bytes is added each time (forward or reply) so I don't know what the last action was.
The second article suggests using the InReplyTo however when I examine the property for forwarded e-mails it contains the original senders e-mail address (not null).
I have seen other articles such as this or this that suggest using extended properties to examine the values in PR_ICON_INDEX, PR_LAST_VERB_EXECUTED and PR_LAST_VERB_EXECUTION_TIME.
My code looks as follows but never returns a value for lastVerbExecuted
var lastVerbExecutedProperty = new ExtendedPropertyDefinition(4225, MapiPropertyType.Integer);
var response = service.BindToItems(newMails, new PropertySet(BasePropertySet.IdOnly, lastVerbExecutedProperty));
var items = response.Select(itemResponse => itemResponse.Item);
foreach (var item in items)
{
object lastVerb;
if (item.TryGetProperty(lastVerbExecutedProperty, out lastVerb))
{
// do something
}
}
PR_ICON_INDEX, PR_LAST_VERB_EXECUTED and PR_LAST_VERB_EXECUTION_TIME would only work to tell you if the recipient has acted on a message in their Inbox. Eg if the user had replied or forwarded a message in their inbox then these properties get set on the message in their Inbox. On the message that was responded to or forwarded these properties would not be set. I would suggest you use the In-Reply-To Transport header which should be set on any message that is replied to or forwarded, this should contain the internet messageid of the message that was replied to or forwarded eg.
FindItemsResults<Item> fiRs = service.FindItems(WellKnownFolderName.Inbox, new ItemView(10));
PropertySet fiRsPropSet = new PropertySet(BasePropertySet.FirstClassProperties);
ExtendedPropertyDefinition PR_TRANSPORT_MESSAGE_HEADERS = new ExtendedPropertyDefinition(0x007D, MapiPropertyType.String);
fiRsPropSet.Add(PR_TRANSPORT_MESSAGE_HEADERS);
service.LoadPropertiesForItems(fiRs.Items, fiRsPropSet);
foreach (Item itItem in fiRs)
{
Object TransportHeaderValue = null;
if(itItem.TryGetProperty(PR_TRANSPORT_MESSAGE_HEADERS,out TransportHeaderValue)) {
string[] stringSeparators = new string[] { "\r\n" };
String[] taArray = TransportHeaderValue.ToString().Split(stringSeparators, StringSplitOptions.None);
for (Int32 txCount = 0; txCount < taArray.Length; txCount++)
{
if (taArray[txCount].Length > 12)
{
if (taArray[txCount].Substring(0, 12).ToLower() == "in-reply-to:")
{
String OriginalId = taArray[txCount].Substring(13);
Console.WriteLine(OriginalId);
}
}
}
}
}
Apart from the Subject prefix that was discussed in the other link I don't know of any other proprieties that will differentiate between a reply or forward.
Cheers
Glen
The best way to rely is on the ResponeCode of Extended properties
Refer below scripts
private static int IsForwardOrReplyMail(ExchangeService service, EmailMessage messageToCheck)
{
try
{
// Create extended property definitions for PidTagLastVerbExecuted and PidTagLastVerbExecutionTime.
ExtendedPropertyDefinition PidTagLastVerbExecuted = new ExtendedPropertyDefinition(0x1081, MapiPropertyType.Integer);
ExtendedPropertyDefinition PidTagLastVerbExecutionTime = new ExtendedPropertyDefinition(0x1082, MapiPropertyType.SystemTime);
PropertySet propSet = new PropertySet(BasePropertySet.IdOnly, EmailMessageSchema.Subject, PidTagLastVerbExecutionTime, PidTagLastVerbExecuted);
messageToCheck = EmailMessage.Bind(service, messageToCheck.Id, propSet);
// Determine the last verb executed on the message and display output.
object responseType;
messageToCheck.TryGetProperty(PidTagLastVerbExecuted, out responseType);
if (responseType != null && ((Int32)responseType) == 104)
{
//FORWARD
return 104;
}
else if (responseType != null && ((Int32)responseType) == 102)
{
//REPLY
return 102;
}
}
catch (Exception)
{
return 0;
//throw new NotImplementedException();
}
}
To determine if it was a reply to a email, you can use the EmailMessage objects InReplyTo property, e.g:
EmailMessage mail = ((EmailMessage)Item.Bind(service, new ItemId(UniqueId)));
if (mail.InReplyTo == null)
return;
else
..your code

Get only text of Item from ItemAttachment (EWS Managed API)

Is there a way to remove HTML tags from Item which is from ItemAttachment?
I can get only text from Item. But not from Item which is from ItemAttachment.
Here is my code:
foreach (ItemAttachment itemAttach in item.Attachments.OfType<ItemAttachment>())
{
Console.WriteLine(itemAttach.Name);
itemAttach.Load();
PropertySet propSet = new PropertySet();
propSet.RequestedBodyType = BodyType.Text;
propSet.BasePropertySet = BasePropertySet.FirstClassProperties;
itemAttach.Item.Load(propSet);
Console.WriteLine(itemAttach.Item.Body.Text);
}
It will get this exception
This operation isn't supported on attachments
I tried binding to the exchange service with item ID.
It also gives me some exception!
Please give some advice on how I can do.
Jin,
The exception you are getting has to do with the property set you are creating. I don't see your code for getting the items so I can't determine the exact cause. I was able to get the following code to work on my machine. You should be able to modify it for your needs.
// Return the first ten items.
ItemView view = new ItemView(10);
// Set the query string to only find emails with attachments.
string querystring = "HasAttachments:true Kind:email";
// Find the items in the Inbox.
FindItemsResults<Item> results = service.FindItems(WellKnownFolderName.Inbox, querystring, view);
// Loop through the results.
foreach (EmailMessage email in results)
{
// Load the email message with the attachments
email.Load(new PropertySet(EmailMessageSchema.Attachments));
// Loop through the attachments.
foreach (Attachment attachment in email.Attachments)
{
// Only process item attachments.
if (attachment is ItemAttachment)
{
ItemAttachment itemAttachment = attachment as ItemAttachment;
// Load the attachment.
itemAttachment.Load(new PropertySet(EmailMessageSchema.TextBody));
// Output the body.
Console.WriteLine(itemAttachment.Item.TextBody);
}
}
For each email that had an item attachment I was able to see the body of the item with the HTML tags removed.
I hope this helps. If this solves your problem, please mark this post as answered.
Thanks,
--- Bob ---

Unable to fetch built in properties of email along with the extended property

I am working with Exchange Web Services Managed API. I am adding a single extended property to mail items in inbox as they get processed based on some condition. Thus, not all mails will get this extended property attached to them.
Next I am refetching all mails in inbox and if they have this property attached to them, I process them again.
Below is the simple method getAllMailsInInbox(), I have written to refetch the mails in inbox:
class MyClass
{
private static Guid isProcessedPropertySetId;
private static ExtendedPropertyDefinition isProcessedPropertyDefinition = null;
static MyClass()
{
isProcessedPropertySetId = new Guid("{20F3C09F-7CAD-44c6-BDBF-8FCB324244}");
isProcessedPropertyDefinition = new ExtendedPropertyDefinition(isProcessedPropertySetId, "IsItemProcessed", MapiPropertyType.String);
}
public List<EmailMessage> getAllMailsInInbox()
{
List<EmailMessage> emails = new List<EmailMessage>();
ItemView itemView = new ItemView(100, 0);
FindItemsResults<Item> itemResults = null;
PropertySet psPropSet = new PropertySet(BasePropertySet.IdOnly);
itemView.PropertySet = psPropSet;
PropertySet itItemPropSet = new PropertySet(BasePropertySet.IdOnly,
ItemSchema.Attachments,
ItemSchema.Subject,
ItemSchema.Importance,
ItemSchema.DateTimeReceived,
ItemSchema.DateTimeSent,
ItemSchema.ItemClass,
ItemSchema.Size,
ItemSchema.Sensitivity,
EmailMessageSchema.From,
EmailMessageSchema.CcRecipients,
EmailMessageSchema.ToRecipients,
EmailMessageSchema.InternetMessageId,
ItemSchema.MimeContent,
isProcessedPropertyDefinition); //***
itemResults = service.FindItems(WellKnownFolderName.Inbox, itemView);
service.LoadPropertiesForItems(itemResults.Items, itItemPropSet);
String subject = itItem.Subject; //Exception: "You must load or assign this property before you can read its value."
//....
}
}
As you can see, on call service.LoadPropertiesForItems(), it does not load any properties, thus resulting in You must load or assign this property before you can read its value. exception while accessing any of those properties.
If I remove isProcessedPropertyDefinition from the itItemPropSet property set, it fetches all the properties properly.
So can I just know how can I fetch all built in EmailMessage properties along with the extended property?
Your GUID is two digits too short after the last dash. Strange that you're not seeing a FormatException. Still, you should update your code to inspect the GetItemResponse for each item. That way if some error occurs on one item, your code can be aware of it. That means you'll need to make another collection to return.
Update your code with this:
ServiceResponseCollection<ServiceResponse> responses = service.LoadPropertiesForItems(itemResults.Items, itItemPropSet);
foreach (ServiceResponse response in responses)
{
if (response.Result == ServiceResult.Error)
{
// Handle the error associated
}
else
{
String subject = (response as GetItemResponse).Item.Subject;
}
}
Instead of doing
service.LoadPropertiesForItems(itemResults.Items, itItemPropSet);
Try doing
itemResult.LoadPropertiesForItems(itItemPropSet);
Casue once you have the item, you can load the extended property of the item by loading the specific one.

Categories