casting objects in c# (Exchange Web Services Item to Email) - c#

I cannot work out how I can do what I need to do.
I have a method called 'MarkAsRead' that takes an ItemID and should mark the mail item as read.
But it seems that the Item doesn't have an 'IsRead' proeprty, only an email does, so I need to cast my Exchange WebServices mail item to an email message.
here is the code:
try
{
System.Diagnostics.Debugger.Break();
//creates an object that will represent the desired mailbox
Mailbox mb = new Mailbox(common.strInboxURL);
//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);
//// if the property is not loaded yet, first load it
//mail.Load(PropertySet(BasePropertySet.IdOnly, EmailMessageSchema.IsRead));
//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
//}
// As a best practice, limit the properties returned to only those that are required.
PropertySet propSet = new PropertySet(BasePropertySet.IdOnly, ItemSchema.Subject);
// Bind to the existing item by using the ItemId.
// This method call results in a GetItem call to EWS.
Item item = Item.Bind(service, itemId, propSet);
EmailMessage mail = Item.Bind(service, itemId, propSet);
item.Load(new PropertySet(BasePropertySet.IdOnly,EmailMessageSchema.IsRead));
item.IsRead = true;
item.Update(ConflictResolutionMode.AlwaysOverwrite);
return true;
}
I am trying to do something like this:
// if the property is not loaded yet, first load it
mail.Load(PropertySet(BasePropertySet.IdOnly, EmailMessageSchema.IsRead));
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
}
unfortunately I need to be able to get a unique email message from the item.
how can I do that please?

Philip-
You can add EmailMessageSchema.IsRead to your property set, so that you can get it in your Bind call, and then you don't have to call Load at all.
PropertySet propSet = new PropertySet(BasePropertySet.IdOnly,
ItemSchema.Subject, EmailMessageSchema.IsRead);
The EmailClass derives from the Item class, so Bind works on both. So you can do the following:
EmailMessage mail = EmailMessage.Bind(service, itemId, propSet);
Put that together and you've got this:
PropertySet propSet = new PropertySet(BasePropertySet.IdOnly, ItemSchema.Subject, EmailMessageSchema.IsRead);
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
}

Philip,
When testing my code I added just a little bit to the Item.Bind() from your code to make this work:
EmailMessage mail = Item.Bind(service, itemId, propSet) as EmailMessage;
The as EmailMessage will cast it to the appropriate type for you. After that I was able to see the isRead property.
I hope this helps. If this does resolve your problem, please mark the post as answered.
Thanks,
--- Bob ---

Related

EWS Displays Emails very slow

I am using Exchange Services in my Application Code to display list of emails on application UI. However, it is able to retrieve emails list. But it takes very very long to display all set. If I decrease number of emails to display it takes less time to display.
public static List<EmailMsg> GetEmailListInFolder(string folderName)
{
var folderId = GetFolderId(folderName);
var service = GetExchangeService();
if (folderId != null)
{
var emails = new List<EmailMsg>();
var count = 0;
var findResults = service.FindItems(folderId, new ItemView(100));
foreach (var item in findResults.Items)
{
var emailPropertySet = new PropertySet(
BasePropertySet.FirstClassProperties,
new PropertyDefinitionBase[]{
new ExtendedPropertyDefinition(4115, MapiPropertyType.Binary)
});
var message = EmailMessage.Bind(service, item.Id, emailPropertySet);
emails.Add(new EmailMsg(folderName, count++, item.Id.UniqueId, message.Subject, message.DateTimeReceived.ToString("yyyy-MMM-dd HH:mm:ss"), ""));
}
return emails;
}
return null;
}
When I debug code and found out that it takes few seconds on this line to before proceeding to next line.
var message = EmailMessage.Bind(service, item.Id, emailPropertySet);
Kindly, suggest me a way to decrease the loading time of my email items. Thanks
You are returning all the BasePropertySet.FirstClassProperties!
You might want to consider changing this to just return the properties you need.
List of FirstClassProperties from msdn:
Id
ParentFolderId
ItemClass
Subject
Sensitivity
Body
Attachments
DateTimeReceived
Size
Categories
Importance
InReplyTo
IsSubmitted
IsDraft
IsFromMe
IsResend
IsUnmodified
InternetMessageHeaders
DateTimeSent
DateTimeCreated
AllowedResponseActions
ReminderDueBy
IsReminderSet
ReminderMinutesBeforeStart
DisplayCc
DisplayTo
HasAttachments
Culture
EffectiveRights
LastModifiedName
LastModifiedTime
IsAssociated
WebClientReadFormQueryString
WebClientEditFormQueryString
ConversationId
Flag
InstanceKey
EntityExtractionResult
Sender
ToRecipients
CcRecipients
BccRecipients
IsReadReceiptRequested
IsDeliveryReceiptRequested
ConversationIndex
ConversationTopic
From
InternetMessageId
IsRead
IsResponseRequested
ReplyTo
References
ReceivedBy
ReceivedRepresenting
You are loading the Attachments. To avoid this big load you can either:
Load the attachement only when you are on a specific mail.
Load only the properties
with LoadPropertiesForItems
and getting the attachments name, extention, etc without getting the real attachement.
Then getting the real attachment can be done using ExchangeService.GetAttachments

c# outlook MailItem add/remove recipient of type BCC

I want to programmatically add with C# recipients to an existing/composing MailItem. When I add a recipient like this:
Microsoft.Office.Interop.Outlook.Inspector inspector = Globals.ThisAddIn.Application.ActiveInspector();
Microsoft.Office.Interop.Outlook.MailItem item = inspector.CurrentItem as Microsoft.Office.Interop.Outlook.MailItem;
Microsoft.Office.Interop.Outlook.Recipient mRecipient = item.Recipients.Add("test.user");
mRecipient.Type = (int)Microsoft.Office.Interop.Outlook.OlMailRecipientType.olBCC;
it appears in the TO field of the MailItem.
When I do something like this:
item.BCC = "test.user";
it appears correclty...
Is there a way to to add the recipient with the first method (Type.olBCC) and show it up in the BCC mail field (2nd snippet)?
I want to go this way because then I can iterate through all recipients and remove some when a special condition is called.
The problem is when I remove the added BCC recipient with
item.BCC = "";
all recpients were deleted in the BCC field.
Apparently we are all missing the point: https://msdn.microsoft.com/en-us/vba/outlook-vba/articles/recipients-object-outlook
According to this
Microsoft.Office.Interop.Outlook.Recipient mRecipient = item.Recipients.Add("test.user");
mRecipient..Type = olCC // at a guess here olBCC would be BCC...
We can modify the list as a list.. :)
Note: I couldnt find olCC in my list.. but maybe I need to look harder.
Note2! Found it.
OlMailRecipientType. has olTo, olOriginator, olCC and olBCC
There you go. so mRecipient.Type = OlMailRecipientType.olBCC should do the trick
The following - opened a new mail item with joe.bloggs in bcc:
olApplication = new Microsoft.Office.Interop.Outlook.Application();
m = olApplication.CreateItem(OlItemType.olMailItem);
Recipient r = m.Recipients.Add("joe.bloggs");
r.Type = (int)OlMailRecipientType.olBCC;
m.Display(true);
Having saved a draft and worked out how to get hold of it as 1 item apparently isnt items[0] ..
the following also works:
Microsoft.Office.Interop.Outlook.MAPIFolder folderDrafts = ns.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderDrafts);
if (folderDrafts.Items.Count > 0)
{
m = (Microsoft.Office.Interop.Outlook.MailItem)folderDrafts.Items[1];
Recipient r = m.Recipients.Add("joe.bloggs");
r.Type = (int)OlMailRecipientType.olBCC;
m.Display(true);
}
As the user BugFinder mentioned there is a workaround neccessary since the UI adds the BCC recipient to the olTO field. I solved this with first adding a dummy, then add the BCC and remove the dummy:
Microsoft.Office.Interop.Outlook.Inspector inspector = Globals.ThisAddIn.Application.ActiveInspector();
Microsoft.Office.Interop.Outlook.MailItem item = inspector.CurrentItem as Microsoft.Office.Interop.Outlook.MailItem;
//Create dummy recipient object for UI bug
Microsoft.Office.Interop.Outlook.Recipient dummy =
item.Recipients.Add("bugDummy");
dummy.Type = (int)Microsoft.Office.Interop.Outlook.OlMailRecipientType.olBCC;
//Create the BCC object that will be used
Microsoft.Office.Interop.Outlook.Recipient mRecipient = item.Recipients.Add("test#user.de");
mRecipient.Type = (int)Microsoft.Office.Interop.Outlook.OlMailRecipientType.olBCC;
//iterate through the recipients and delete the dummy
foreach (Microsoft.Office.Interop.Outlook.Recipient recipient in item.Recipients)
{
if (string.Compare(recipient.Name, "bugDummy", true) == 0)
{
recipient.Delete();
break;
}
}

Exchange 2013 API - Get Room Properties

I am trying to get the room details from Exchange using EWS API.
Here is the example given for getting room list.
So as per the code I am trying to get the room details like location, city, state etc., but with code example's code block, I am only getting Id, MailboxType, Name & RoutingType.
Code snippet I have tried:
// Initialize service object here
EmailAddressCollection myRoomLists = service.GetRoomLists();
foreach (EmailAddress address in myRoomLists)
{
EmailAddress myRoomList = address.Address;
Console.WriteLine("Email Address: {0}", address.Address);
}
Really appreciate if some can help me in getting the room property (Location, City, State etc.) with Exchange API in C#?
The RoomList operation will only return the EmailAddresses of the Room Mailboxes in the list. To get further information on these you will need to use an operation like ResolveName and return the ContactInformation eg
EmailAddressCollection myRoomLists = service.GetRoomLists();
foreach (EmailAddress address in myRoomLists)
{
EmailAddress myRoomList = address.Address;
PropertySet AllProps = new PropertySet(BasePropertySet.FirstClassProperties);
NameResolutionCollection ncCol = service.ResolveName(address.Address, ResolveNameSearchLocation.DirectoryOnly, true, AllProps);
foreach (NameResolution nr in ncCol)
{
Console.WriteLine(nr.Contact.DisplayName);
Console.WriteLine(nr.Contact.Notes);
}
}
Room Capacity is not a property that is exposed by EWS so you need to use a workaround to get it https://social.technet.microsoft.com/Forums/office/en-US/9eef45a5-dd1d-4912-9beb-bded7b40cb9e/ews-managed-api-using-c?forum=exchangesvrdevelopment
Cheers
Glen

Find a recipient with a given address in a folder

My company needs an add-in for automatically adding offers to the email when it is the first time we send an email to a recipient.
My question is :
How can I check if this is the first time the user sends an email to the recipients?
I tried this but I receive error that Recipient is unknown property. And I also think that this is not the right approach...
object folderItem;
Boolean AlreadyEmailed = false;
if (mail != null)
{
const string PR_SMTP_ADDRESS =
"http://schemas.microsoft.com/mapi/proptag/0x39FE001E";
Outlook.Recipients recips = mail.Recipients;
foreach (Outlook.Recipient recip in recips)
{
Outlook.PropertyAccessor pa = recip.PropertyAccessor;
string smtpAddress =
pa.GetProperty(PR_SMTP_ADDRESS).ToString();
string filter = "[Recipient] = 'John#foo.com'";
filter = filter.Replace("John#foo.com", smtpAddress);
Debug.WriteLine(filter);
folderItem = items.Restrict(filter);
if(folderItem != null)
{
Debug.WriteLine("We found items that have the filter");
AlreadyEmailed = true;
}
//Debug.WriteLine(recip.Name + " SMTP=" + smtpAddress);
}
if(!AlreadyEmailed)
{
Debug.WriteLine("This is the first time we email ... ");
}
}
The Sent property of the MailItem class returns a Boolean value that indicates if a message has been sent. In general, there are three different kinds of messages: sent, posted, and saved. Sent messages are items sent to a recipient or public folder. Posted messages are created in a public folder. Saved messages are created and saved without either sending or posting.
Also you may use the following Extended MAPI properties that deal with the message state (replied/forwarded):
PR_ICON_INDEX (http://schemas.microsoft.com/mapi/proptag/0x10800003)
PR_LAST_VERB_EXECUTED (the DASL name is http://schemas.microsoft.com/mapi/proptag/0x10810003)
PR_LAST_VERB_EXECUTION_TIME (0x10820040)
To get these values use the PropertyAccessor class (see the corresponding properties of Outlook items).
Be aware, new Outlook items don't have the EntryID property set.
You can Use To/CC/BCC properties in Items.Find/Restrict. Note that it is better to use Find in your case since you only need a single match, not all of them. Also note that Restrict will not return null if no matches are found, but rather an Items collection with Items.Count == 0.
That being said, To/CC/BCC might not include addresses, only names, so search won't help you. You can still loop through all items in the folder and explicitly check the Recipients collection of each item, but that will be hugely inefficient.
On the Extended MAPI level (C++ or Delphi), one can create subrestrictions on message recipients (or attachments), but the Outlook Object Model does not expose that functionality.
If using Redemption is an option (I am its author), its implementation of Find/Restrict does support queries on the Recipients collection:
set Session = CreateObject("Redemption.RDOSession")
Session.MAPIOBJECT = Application.Session.MAPIOBJECT
set YourOutlookFolder = Application.ActiveExplorer.CurrentFolder
set rFolder = Session.GetFolderFromID(YourOutlookFolder.EntryID)
set rItems = rFolder.Items
set rMsg = rItems.Find("Recipients LIKE 'John#foo.com' ")
while not (rMsg Is Nothing)
Debug.print rMsg.Subject
set rMsg = rItems.FindNext
wend
In C# (not tested):
Redemption.RDOSession Session = new Redemption.RDOSession();
Session.MAPIOBJECT = Application.Session.MAPIOBJECT;
set rFolder = Session.GetFolderFromID(YourOutlookFolder.EntryID);
Redemption.RDOMail rMsg = rFolder.Items.Find("Recipients LIKE 'John#foo.com' ") ;
AlreadyEmailed = rMsg != null;

Outlook AddIn: creating new ContactItem

I use the following code to assign some data to an appropriate ContactItem (Sender) of given MailItem. If Sender.GetContact() returns null, I'm trying to create a new ContactItem.
Outlook.MailItem myItem = (Outlook.MailItem)this.OutlookItem;
Outlook.ContactItem currentContact = myItem.Sender.GetContact();
if (currentContact != null)
{
currentContact.Body = "Example";
currentContact.Save();
}
else
{
currentContact = Globals.ThisAddIn.Application.CreateItem(Outlook.OlItemType.olContactItem) as Outlook.ContactItem;
currentContact.Email1DisplayName = myItem.SenderName;
currentContact.Email1Address = myItem.SenderEmailAddress;
currentContact.Email1AddressType = myItem.SenderEmailType;
currentContact.Body = "Example";
currentContact.Save();
}
But this does not seem to work fine for me. The next time I'm getting the contact of that MailItem (see the following code), it returns null. Again. And again.
Outlook.MailItem myItem = (Outlook.MailItem)this.OutlookItem;
Outlook.ContactItem currentContact = myItem.Sender.GetContact();
Is there something wrong? It seems like that new ContactItem is not assigned to Sender.
GetContact will return ContactItem object only if the outgoing message (does not work for incoming) had the contact explicitly added as a recipient.
GetContact will not check if you happen to have a contact item with the same email address.
If you need to find a matching contact, explicitly use MAPIFolder.Items.Find on the Contacts folder.

Categories

Resources