I am getting emails from a mailbox using exchange webservices using a custom code block in C# (I'm not versed in C# at all so forgive code quality!) in UiPath. I am passing the exchange service and folder ID as arguments to the code block. I noticed that when there was a large attachment on the email it took significantly longer. I am not interested in the attachment I just want to be able to access some information about the email. This was my initial code:
//Search for oldest email
ItemView objView = new ItemView(1);
objView.OrderBy.Add(ItemSchema.DateTimeReceived, SortDirection.Ascending);
FindItemsResults<Item> lstItems = objServer.FindItems(in_FolderID, objView);
//Bind to email from result
if(lstItems.Count() == 0)
{
Console.WriteLine("Inbox appears to be empty");
out_ExchangeMessage = null;
out_InternetMessageID = null;
}
else
{
Item objItem = lstItems.ElementAt(0);
Console.WriteLine("Retrieving email: " + objItem.Subject);
PropertySet objPropertySet = new PropertySet(BasePropertySet.FirstClassProperties, ItemSchema.MimeContent, EmailMessageSchema.IsRead,ItemSchema.Attachments,ItemSchema.TextBody);
out_ExchangeMessage = EmailMessage.Bind(objServer,objItem.Id, objPropertySet);
out_InternetMessageID = out_ExchangeMessage.InternetMessageId;
Console.WriteLine("Message Retrieved: " + out_ExchangeMessage.InternetMessageId);
}
I tried removing ItemSchema.Attachments so this line reads as follows. But the email still takes significantly longer to download
PropertySet objPropertySet = new PropertySet(BasePropertySet.FirstClassProperties, ItemSchema.MimeContent, EmailMessageSchema.IsRead,ItemSchema.TextBody);
Is there a way to speed up the retrieving of emails with large attachments?
Because your including ItemSchema.MimeContent in your propertyset that is going to give you the whole MimeStream of the Message including attachments. If you don't require the MimeStream don't request it. Eg you should be able to get all the other properties of the Message eg body,subject,headers etc from other properties so it would only be required if you wanted to save the message.
Related
What I have done so far is to connect to EWS, access my inbox, create an item (email) with some info in Body, Subject, From, and To, save it to the Draft folder, and finally move it to my inbox. It works, however, I get a draft in the inbox instead of an email.
Is it possible to get the message as an email with the above scenario and how can I achieve that?
Below is my code. Any input would be very appreciated.
try {
message.Save();
}
catch(Exception e21) {;
}
message.Load(PS);
message.From = new EmailAddress("someone#abc.com");
message.ToRecipients.Add("me#abc.com");
message.Body = "This is A test take 1";
message.Subject = "Testing to send as someone else...";
// add in the attachments......
message.Update(ConflictResolutionMode.AlwaysOverwrite); // require this here why????
message.Copy(theTempFolder.Id); // get the item as a draft in my mailbox instead of an email
}
catch(Exception e99) {
Console.WriteLine("Exception fail to connect to office 365 on the cloud: " + e99.Message);
}
You need to set the MessageFlags property https://learn.microsoft.com/en-us/office/client-developer/outlook/mapi/pidtagmessageflags-canonical-property to 1 (before you call update) eg
ExtendedPropertyDefinition PR_MESSAGE_FLAGS_msgflag_read = new ExtendedPropertyDefinition(3591, MapiPropertyType.Integer);
message.SetExtendedProperty(PR_MESSAGE_FLAGS_msgflag_read, 1);
Which will then make the message look like it was received. The other way is just import an EML like https://learn.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-import-items-by-using-ews-in-exchange
Have you tried to send it to yourself with either message.Send() or message.SendAndSaveCopy() ? see more here
I'm using the EWS Managed API in C# to download a bunch of messages from my company's exchange server. Loading the messages themselves takes a long time considering that service.FindItems() only fetches limited information about the messages, but it's not a huge deal. The serious problem I'm facing is how long it takes to load attachments.
The program is supposed to display an email and its image attachment side-by-side. When loading a new email, it can take well over a minute for the attachment to load. I initially fetched the attachments for each message when the message was loaded, but I thought it would be better to try to load them all at once into a List<EmailMessage> so the program wouldn't have to fetch the attachments when loading individual messages.
Here's the code I used to do that:
fetchView.PropertySet = new PropertySet(BasePropertySet.FirstClassProperties);
fetchView.Traversal = FolderTraversal.Deep;
//create itemView for actual message query since we finally found the damn folder
ItemView iView = new ItemView(int.MaxValue);
FolderId sharedInboxFolder = new FolderId(WellKnownFolderName.Root, sharedMailbox);
FolderId targetFolder = new FolderId(WellKnownFolderName.Root, sharedMailbox);
FindFoldersResults inboxFolders = service.FindFolders(sharedInboxFolder, fetchView);
bool folderFound = false;
//look through the folders in the inbox to find the user-specified one by name
foreach(Folder f in inboxFolders)
{
if (f.DisplayName == Properties.Settings.Default.InboxFolder)
{
targetFolder = f.Id;
folderFound = true;
}
}
// Set itemview properties for FindItems() operation
fullProperties.Add(ItemSchema.Body);
fullProperties.Add(ItemSchema.Attachments);
fullProperties.Add(ItemSchema.DateTimeReceived);
fullProperties.Add(ItemSchema.Subject);
if (!folderFound)
{
MessageBox.Show("Folder not found!");
} else {
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);
FindItemsResults<Item> fetchedMessages = service.FindItems(targetFolder, dayFilter, iView);
foreach (Item i in fetchedMessages.Items)
{
EmailMessage msg = EmailMessage.Bind(service, i.Id, fullProperties);
emails.Add(msg);
}
}
}
I then save all the attachments to disk with
for (int i = 0; i < message.Attachments.Count; i++)
{
if (message.Attachments[i] is FileAttachment)
{
FileAttachment att = message.Attachments[i] as FileAttachment;
att.Load();
using (FileStream attStream = new FileStream(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + #"\Program\images\" + i.ToString(), FileMode.Create, FileAccess.ReadWrite))
{
att.Load(attStream);
attStream.Close();
attStream.Dispose();
}
}
else
{
MessageBox.Show("Not FileAttachment!");
}
}
Then, to load an image and it's attachment, I do
imgViewer.Source = new BitmapImage(new Uri(/some/path/to/image/))
I suspect the hangup is during the save attachments phase. I found this post that indicated TraceFlags should be disabled, so I did service.TraceFlags = TraceFlags.None but that didn't seem to help at all. I'm contemplating just downloading all the attachments up front, or figuring out some kind of caching mechanism where I download the attachments of message[n+1...x] in the background while the user works on message[n], but this has limited usefulness, because the program should also let the user select an image and load it relatively instantly (i.e. much less than a minute).
Any suggestions are much appreciated.
Your loading the attachments twice for no apparent reason.
Remove the att.Load(); from your if (message.Attachments[i] is FileAttachment) statement.
Maybe have a look at implementing paging and in turn consider reducing your ItemView pageSize to batches of 1000 or less, instead of MaxValue
Also make sure you are only returning what you need in your PropertySet.
BasePropertySet.FirstClassProperties Consider changing this to just return what you need.
Side Note:
A good way to identify slow performing code is to use the .Net Stopwatch class.
Stopwatch sw = new Stopwatch();
sw.Start();
// code
sw.Stop();
StopWatchLog stopWatchLog = new StopWatchLog();
stopWatchLog.CreateXMLTextFile("MethodName()" + " took" + sw.Elapsed.Seconds + " seconds.");
I want to forward an existing Email from my Outlook inbox folder. On recent research I found some different solutions:
get the current mail item and copy it to a new message
move method to move in a different folder
forward method...
My goal is to find a simple way to forward an existing Email to another E-Mail adress.
My code enclosed does not have access to send!
private void buttonExplorer_Click(object sender, RibbonControlEventArgs e)
{
Microsoft.Office.Interop.Outlook.Selection mySelection = Globals.ThisAddIn.Application.ActiveExplorer().Selection;
Microsoft.Office.Interop.Outlook.MailItem mailItem = null;
foreach (Object obj in mySelection)
{
if (obj is Microsoft.Office.Interop.Outlook.MailItem)
{
mailItem = (Microsoft.Office.Interop.Outlook.MailItem)obj;
mailItem.Forward();
mailItem.Recipients.Add("test#web.com");
mailItem.Send();
}
}
}
Would be nice if there is a simple way to solve the forwarding event issue.
Forward() creates a new item, as stated here.
So you'll need to use that new item from then on:
var newItem = mailItem.Forward();
newItem.Recipients.Add("to.alt#web.de");
newItem.Send();
Try using Microsoft Exchange Web Service (EWS) to forward the email messages. EWS provides api for the commonly used events.
A sample code would like this,
// Connect to Exchange Web Services as user1 at contoso.com.
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
service.Credentials = new WebCredentials("user1#contoso.com", "password ");
service.AutodiscoverUrl("user1#contoso.com");
// Create the e-mail message, set its properties, and send it to user2#contoso.com, saving a copy to the Sent Items folder.
EmailMessage message = new EmailMessage(service);
message.Subject = "Interesting";
message.Body = "The proposition has been considered.";
message.ToRecipients.Add("user2#contoso.com");
message.SendAndSaveCopy();
For more info, refer https://msdn.microsoft.com/en-us/library/office/dd633681(v=exchg.80).aspx
I'm using EWS in order to retrieve emails, but when I want to retrieve the attachments I have to call the following function for each:
fileAttachment.Load();
Everytime I do that, it goes to the server. Is it possible to retrieve all the attachments at once? Also, is it possible to retrieve all the attachments for several mail items?
The ExchangeService object has a GetAttachments method which basically allows you to do a batch GetAttachment request. So if you want to load the attachments on several messages at once you need to do something like (first call loadpropertiesforitems which does a batch GetItem to get the AttachmentIds)
FindItemsResults<Item> fItems = service.FindItems(WellKnownFolderName.Inbox,new ItemView(10));
PropertySet psSet = new PropertySet(BasePropertySet.FirstClassProperties);
service.LoadPropertiesForItems(fItems.Items, psSet);
List<Attachment> atAttachmentsList = new List<Attachment>();
foreach(Item ibItem in fItems.Items){
foreach(Attachment at in ibItem.Attachments){
atAttachmentsList.Add(at);
}
}
ServiceResponseCollection<GetAttachmentResponse> gaResponses = service.GetAttachments(atAttachmentsList.ToArray(), BodyType.HTML, null);
foreach (GetAttachmentResponse gaResp in gaResponses)
{
if (gaResp.Result == ServiceResult.Success)
{
if (gaResp.Attachment is FileAttachment)
{
Console.WriteLine("File Attachment");
}
if (gaResp.Attachment is ItemAttachment)
{
Console.WriteLine("Item Attachment");
}
}
}
Cheers
Glen
I'm in the process of writing a simple console app that monitors a particular exchange mailbox, and when emails meeting particular criteria are received, the app will download an XML file attachment, and archive the email.
I've connected to EWS OK, and have been able to loop through any emails, but I'm struggling when it comes to create an EmailMessage object which I can use to access the attachments.
In the example code below, the EmailMessage message = EmailMessage.Bind(...) line executes without error, but doesn't return a valid message so when I access and properties or methods, I get an error: 'Object reference not set to an instance of an object'.
I'm new to C# let alone EWS so I'm struggling to know where to start...
Code Snippet:
public static void FindItems()
{
try
{
ItemView view = new ItemView(10);
view.OrderBy.Add(ItemSchema.DateTimeReceived, SortDirection.Ascending);
view.PropertySet = new PropertySet(
BasePropertySet.IdOnly,
ItemSchema.Subject,
ItemSchema.DateTimeReceived);
findResults = service.FindItems(
WellKnownFolderName.Inbox,
new SearchFilter.SearchFilterCollection(
LogicalOperator.Or,
new SearchFilter.ContainsSubstring(ItemSchema.Subject, "Sales Enquiry")),
view);
log2.LogInfo("Total number of items found: " + findResults.TotalCount.ToString());
foreach (Item item in findResults)
{
log2.LogInfo(item.Id);
EmailMessage message = EmailMessage.Bind(service, item.Id, new PropertySet(BasePropertySet.IdOnly, ItemSchema.Attachments));
Console.WriteLine(message.Subject.ToString());
if (message.HasAttachments && message.Attachments[0] is FileAttachment)
{
FileAttachment fileAttachment = message.Attachments[0] as FileAttachment;
fileAttachment.Load("C:\\temp\\" + fileAttachment.Name);
fileAttachment.Load();
Console.WriteLine("FileName: " + fileAttachment.FileName);
}
}
}
catch (Exception ex)
{
log2.LogError(ex.InnerException);
}
}
My code for accessing the attachments is straight from MSDN so I'm hoping it is there are thereabouts... Any ideas?
I'm afraid I revisited this problem and managed to cure it. Unfortunately I was too pressed at the time to come back here and document the solution. Time having passed, and my memory of what I changed has faded, but as far as I can remember it was a one line change:
EmailMessage message = EmailMessage.Bind(service, item.Id, new PropertySet(BasePropertySet.FirstClassProperties, EmailMessageSchema.Attachments));
The key difference here is that we have specified BasePropertySet.FirstClassProperties as the first parameter of PropertySet, rather than the BasePropertySet.IdOnly that we originally had.
My original code was lifted from an example online that did precisely what I was trying to achieve, so either the example wasn't quite right, or I transcribed it incorrectly or misunderstood some facet of the problem.
foreach(EmailMessage message in findResults)
{
message.Load();
Console.WriteLine(message.Subject.ToString());
if (message.HasAttachments && message.Attachments[0] is FileAttachment)
{
FileAttachment fileAttachment = message.Attachments[0] as FileAttachment;
fileAttachment.Load("C:\\temp\\" + fileAttachment.Name);
fileAttachment.Load();
Console.WriteLine("FileName: " + fileAttachment.FileName);
}
}