EWS Managed API: External GUID in mail message? - c#

Is it possible to assign EmailMessage specific GUID/ID, which will be later used for search?
var email = new EmailMessage(_service);
email.ExternalGuid = /*Guid or Identifier*/;
email.Send();
And later I should be able to use it to find if this mail is present:
var isExist = _service.IsExistByExternalGuid(/*Guid or Identifier*/);

Why don't you use the InternetMessageid eg Internet Message ID FROM EWS Managed API Send Email c# this Id will then appear in any tracking logs associated with the Message and you can search for the message at a later date using a SearchFilter eg
ItemView ivew = new ItemView(3);
service.TraceEnabled = true;
ExtendedPropertyDefinition PidTagInternetMessageId = new ExtendedPropertyDefinition(4149, MapiPropertyType.String);
SearchFilter sf = new SearchFilter.IsEqualTo(PidTagInternetMessageId, MessageID);
FindItemsResults<Item> iCol = service.FindItems(WellKnownFolderName.Inbox, sf, ivew);
foreach (Item item in iCol.Items)
{
Console.WriteLine(item.Subject);
}

Related

Fetch emails received on certain day from non-Well-known folder in shared inbox, Exchange 2016 EWS in C#

I'm trying to fetch all messages from a user-specified date on an Exchange 2016 server using the EWS managed API in C#.
I authenticate with:
public static void Login(string username, string password)
{
service.UseDefaultCredentials = false;
service.Credentials = new WebCredentials(username, password);
service.AutodiscoverUrl(username, RedirectionUrlValidationCallback);
}
Then select the appropriate inbox with
sharedMailbox = new Mailbox(Properties.Settings.Default.Inbox);
the SMTP address is stored in Settings.settings .
I then find the desired folder using the following (from this thread):
targetFolderId = new FolderId(WellKnownFolderName.Inbox, sharedMailbox);
// set folder view
view.PropertySet = new PropertySet(BasePropertySet.FirstClassProperties);
view.PropertySet.Add(FolderSchema.DisplayName);
view.Traversal = FolderTraversal.Deep;
folderResults = service.FindFolders(WellKnownFolderName.Inbox, view);
foreach(Folder f in folderResults)
{
if(f.DisplayName == "Invoices")
{
targetFolderId = f.Id;
//tried showing a message box here
}
}
And use the following (filter code from here and retrieve details from Exchange server code from here) to get the messages I want:
public static void FetchUnreadMessages(DateTime searchDate)
{
SearchFilter greaterthanfilter = new SearchFilter.IsGreaterThanOrEqualTo(ItemSchema.DateTimeReceived, searchDate);
SearchFilter lessthanfilter = new SearchFilter.IsLessThan(ItemSchema.DateTimeReceived, searchDate.AddDays(1));
SearchFilter dayFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.And, greaterthanfilter, lessthanfilter);
results = service.FindItems(targetFolderId, dayFilter, view);
foreach(var item in results.Items)
{
emails.Add((EmailMessage)item);
}
PropertySet properties = (BasePropertySet.FirstClassProperties);
service.LoadPropertiesForItems(emails, properties);
}
I'm not sure where this is breaking down. I tried showing a message box in the foreach loop that finds the folder with the specified name, and it appears the folder is never found. I know there is a folder with that display name in the shared inbox.
I'm not great at debugging and unfortunately my grasp of the EWS API is pretty shaky. Any suggestions as to what I'm missing are welcome.
I keep everything related to the inbox in a static class so I only have to worry about one instance.
There is some problems with you code first
Then select the appropriate inbox with
sharedMailbox = new Mailbox(Properties.Settings.Default.Inbox);
targetFolderId = new FolderId(WellKnownFolderName.Inbox, sharedMailbox);
Nothing wrong with this code but you probably need to understand what's happening here. This code doesn't make any calls to the server it just setups a FolderId class that you can use in a call to get one of the well known folder.
view.PropertySet = new PropertySet(BasePropertySet.FirstClassProperties);
view.PropertySet.Add(FolderSchema.DisplayName);
view.Traversal = FolderTraversal.Deep;
folderResults = service.FindFolders(WellKnownFolderName.Inbox, view);
This code would just search the Inbox Subfolder of the Mailbox who's credentials you are using. eg
service.Credentials = new WebCredentials(username, password);
If you wanted to Search the SubFolders of the Inbox of the SharedMailbox you would use
view.PropertySet = new PropertySet(BasePropertySet.FirstClassProperties);
view.PropertySet.Add(FolderSchema.DisplayName);
view.Traversal = FolderTraversal.Deep;
folderResults = service.FindFolders(targetFolderId , view);
because you are using the targetFolderId in the FindFolder operations that is telling Exchange to Search the Shared Mailbox rather then the mailbox associated with the credentials you are using.

Create an email using EWS Exchange and attach another email

I'm having trouble attaching an email to a new email using EWS.
So i have the Microsoft.Exchnage.Webservice.Data.Item in my findResults.
If I find an issue in the form data of the email then I want to attach that item to a new email and send it to a supervisor for manual input.
I have tried;
EmailMessage newMessage = new EmailMessage(exchange);
newMessage.Subject = "Failed lead creation";
ItemAttachment attachment = new ItemAttachment("New Lead", message);
I can't seem to create the ItemAttachment as the erro I am getting is "ItemAttachment does not contain a constructor that takes 2 arguments".
How do I create a new message in EWS, attach the current Item to it and send to another recipient?
Thaks
You can't another message directly you need to use the MimeContent of the Original Message and then create an ItemAttachment based on that eg something like
FolderId folderid= new FolderId(WellKnownFolderName.Inbox,"MailboxName");
Folder Inbox = Folder.Bind(service,folderid);
ItemView ivItemView = new ItemView(1) ;
FindItemsResults<Item> fiItems = service.FindItems(Inbox.Id,ivItemView);
if(fiItems.Items.Count == 1){
EmailMessage mail = new EmailMessage(service);
EmailMessage OriginalEmail = (EmailMessage)fiItems.Items[0];
PropertySet psPropset= new PropertySet(BasePropertySet.IdOnly);
psPropset.Add(ItemSchema.MimeContent);
psPropset.Add(ItemSchema.Subject);
OriginalEmail.Load(psPropset);
ItemAttachment Attachment = mail.Attachments.AddItemAttachment<EmailMessage>();
Attachment.Item.MimeContent = OriginalEmail.MimeContent;
ExtendedPropertyDefinition PR_Flags = new ExtendedPropertyDefinition(3591, MapiPropertyType.Integer);
Attachment.Item.SetExtendedProperty(PR_Flags,"1");
Attachment.Name = OriginalEmail.Subject;
mail.Subject = "See the Attached Email";
mail.ToRecipients.Add("glen.scales#domain.com");
mail.SendAndSaveCopy();
Cheers
Glen
Utilizing answer from Glen Scales, if you have message id, code should look like below.
Additional info on PR_Flags extended property can be found on folowing link:
http://systemmanager.ru/windowsmobile_6_5.en/html/45cd0e95-9622-4180-bf85-290c421524f3.htm
PropertySet psPropset = new PropertySet(BasePropertySet.IdOnly);
psPropset.Add(ItemSchema.MimeContent);
psPropset.Add(ItemSchema.Subject);
EmailMessage attachment = EmailMessage.Bind(_exchangeService, new ItemId(ewsItemAsAttachment).UniqueId, psPropset).Result;
ItemAttachment Attachment = message.Attachments.AddItemAttachment<EmailMessage>();
Attachment.Item.MimeContent = attachment.MimeContent;
ExtendedPropertyDefinition PR_Flags = new ExtendedPropertyDefinition(3591, MapiPropertyType.Integer);
Attachment.Item.SetExtendedProperty(PR_Flags, "1");
Attachment.Name = attachment.Subject;

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();
}
}

Exchange EWS Managed API 2.0 get by date

Im using EWS Managed API to communicate between my c# project and our Exchange 2010 server.
I use this code to get all mails in the inbox from now and three days back.
var ews = new ExchangeService(ExchangeVersion.Exchange2010_SP1);
ews.Credentials = new NetworkCredential(usr, psw, dmn);
ews.AutodiscoverUrl(url);
PropertySet itempropertyset = new PropertySet(BasePropertySet.FirstClassProperties);
itempropertyset.RequestedBodyType = BodyType.Text;
ItemView view = new ItemView(int.MaxValue);
FindItemsResults<Item> findResults;
view.PropertySet = itempropertyset;
do
{
findResults = ews.FindItems(WellKnownFolderName.Inbox, view);
foreach (Item item in findResults.Items)
{
if (item.DateTimeCreated < DateTime.Now.AddDays(-3)) continue;
item.Load(itempropertyset);
var message = EmailMessage.Bind(ews, item.Id,
new PropertySet(BasePropertySet.FirstClassProperties, ItemSchema.Attachments));
string to = message.ToRecipients[0].Address.ToLower();
string body = item.Body;
}
view.Offset += findResults.TotalCount;
} while (findResults.MoreAvailable);
Now the problem. I want to improve this line if (item.DateTimeCreated < DateTime.Now.AddDays(-3)) continue; because when i use this, the api gets all the messages from inbox and just continue if its older then three days. I want specify this filter earlier in the code, so the api dont have to handle all messages.
If I understand the problem correctly, this should work. You can see all search filters available here: EWS Search Filters
ItemView view = new ItemView(int.MaxValue);
FindItemsResults<Item> findResults;
view.PropertySet = itempropertyset;
SearchFilter searchFilter =
new SearchFilter.IsGreaterThan(ItemSchema.DateTimeReceived, DateTime.Now.AddDays(-3));
findResults = service.FindItems(WellKnownFolderName.Inbox, searchFilter, view);

Get all emails in mailbox

How can I fetch all emails from Exchange 2010 in the least amount of EWS calls?
Our mailbox has 50k+ emails with 2k~ folders. I've tried iterating through each folder but this takes hours to fetch all of my emails. My current approach is to fetch all folders from the mailbox then make a list of search filters essentially filtering all items that have a parent folder id of n.
Here is what I have so far.
var allFolders = exchangeService.FindFolders(folderId,
new FolderView(int.MaxValue) {Traversal = FolderTraversal.Deep});
var searchFilterCollection = new List<SearchFilter>();
foreach(var folder in allFolders)
searchFilterCollection.Add(new SearchFilter.SearchFilterCollection(LogicalOperator.Or,
new SearchFilter.IsEqualTo(ItemSchema.ParentFolderId, folder.Id.ToString())));
var itemView = new ItemView(int.MaxValue)
{
PropertySet = PropertySet.FirstClassProperties
};
var findItems = exchangeService.FindItems(folderId,
new SearchFilter.SearchFilterCollection(LogicalOperator.Or, searchFilterCollection), itemView);
The error I receive it The property can not be used with this type of restriction..
If you use EWS directly instead of the EWS Managed API, you can use the FindItemOperation to do this. The EWS FindItemOperation takes multiple parentFolderIds as input.
http://msdn.microsoft.com/en-us/library/aa566107(v=exchg.140).aspx
http://social.technet.microsoft.com/Forums/en-US/exchangesvrdevelopment/thread/4bd4456d-c859-4ad7-b6cd-42831f4fe7ec/
This seems to say that ParentFolderId cannot be accessed in your filter because it is not yet loaded.
You can instruct EWS to load it by adding it to your FolderView:
FolderView view = new FolderView(int.MaxValue) {Traversal = FolderTraversal.Deep};
view.PropertySet.Add(FolderSchema.ParentFolderId);
var allFolders = exchangeService.FindFolders(folderId,view);
As an alternative to search in a mailbox you can use the AllItems folder and do a searchfilter using the MAPI Property "PR_PARENT_ENTRYID" - https://technet.microsoft.com/de-de/sysinternals/gg158149.
// use MAPI property from Items parent entry id
ExtendedPropertyDefinition MAPI_PARENT_ENTRYID = new ExtendedPropertyDefinition(0x0E09, MapiPropertyType.Binary);
// get the "AllItems" folder from its account
folderResult = service.FindFolders(WellKnownFolderName.Root, new SearchFilter.IsEqualTo(FolderSchema.DisplayName, "allitems"), folderView);
var allItemsFolder = folderResult.FirstOrDefault();
// convert EWS Folder Id to MAPI ENTRYID - parentFolderId is us an AlternateId
var convertedId = service.ConvertIds(parentFolderId, IdFormat.EntryId);
// use the MAPI Property with its converted PARENT_ENTRY_ID in EWS Searchfilters
var parent_entry_id = (ids.ConvertedId as AlternateId).UniqueId;
var searchFilterFolders = new SearchFilter.IsEqualTo(MAPI_PARENT_ENTRYID, parent_entry_id);
// search in "AllItems" using the searchFilter containing the converted PARENT_ENTRY_ID
result = service.FindItems(folderId, searchFilterFolders, view);

Categories

Resources