Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Question
Tuesday, November 5, 2013 12:25 PM
I am just creating an windows service to check the unread mails (outlook.office365.com) using EWS 2.0
When i run
The request failed. The underlying connection was closed: An unexpected error occurred on a send.
File: CheckEmail.cs Method : ReadEmailContent Line: 77
System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a send. > System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. > System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)
at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
End of inner exception stack trace
at System.Net.TlsStream.EndWrite(IAsyncResult asyncResult)
at System.Net.PooledStream.EndWrite(IAsyncResult asyncResult)
at System.Net.ConnectStream.WriteHeadersCallback(IAsyncResult ar)
End of inner exception stack trace
at System.Net.HttpWebRequest.GetResponse()
at Microsoft.Exchange.WebServices.Data.EwsHttpWebRequest.Microsoft.Exchange.WebServices.Data.IEwsHttpWebRequest.GetResponse()
at Microsoft.Exchange.WebServices.Data.ServiceRequestBase.GetEwsHttpWebResponse(IEwsHttpWebRequest request)
I can't able to reproduce this error while debugging
public void ReadEmailContent()
{
try
{
if (!string.IsNullOrEmpty(emailConfig.EmailID))
{
ExchangeService service = new ExchangeService();
service.Credentials = new WebCredentials(emailConfig.EmailID, emailConfig.Password);
service.UseDefaultCredentials = false;
service.Url = new Uri("https://outlook.office365.com/EWS/Exchange.asmx");
Folder inbox = Folder.Bind(service, WellKnownFolderName.Inbox);
SearchFilter sf = new SearchFilter.SearchFilterCollection(LogicalOperator.And, new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, false));
if (inbox.UnreadCount > 0)
{
ItemView view = new ItemView(inbox.UnreadCount);
FindItemsResults<Item> findResults = inbox.FindItems(sf, view);
PropertySet itempropertyset = new PropertySet(BasePropertySet.FirstClassProperties, EmailMessageSchema.From, EmailMessageSchema.ToRecipients);
itempropertyset.RequestedBodyType = BodyType.Text;
//inbox.UnreadCount
ServiceResponseCollection<GetItemResponse> items = service.BindToItems(findResults.Select(item => item.Id), itempropertyset);
MailItem[] msit = getMailItem(items, service);
foreach (MailItem item in msit)
{
item.Message.IsRead = true;
item.Message.Update(ConflictResolutionMode.AlwaysOverwrite);
foreach (Attachment attachment in item.Attachment)
{
if (attachment is FileAttachment)
{
string extName = attachment.Name.Substring(attachment.Name.LastIndexOf('.'));
FileAttachment fileAttachment = attachment as FileAttachment;
fileAttachment.Load(emailConfig.TargetFolder.ToString() + attachment.Name);
Console.WriteLine("Attachment name: " + fileAttachment.Name + fileAttachment.Content + fileAttachment.ContentType + fileAttachment.Size);
}
}
}
}
DeleteMail();
}
}
catch (Exception ex)
{
Logger.Write(ex);
}
finally
{
}
}
// To delete the old emails
public void DeleteMail()
{
try
{
// ExchangeService service = new ExchangeService();
if (!string.IsNullOrEmpty(emailConfig.EmailID))
{
ExchangeService service = new ExchangeService();
service.Credentials = new WebCredentials(emailConfig.EmailID, emailConfig.Password);
service.UseDefaultCredentials = false;
service.Url = new Uri(emailConfig.ServerName);
DateTime searchdate = DateTime.Now;
searchdate = searchdate.AddDays(-4);
SearchFilter greaterthanfilter = new SearchFilter.IsGreaterThanOrEqualTo(ItemSchema.DateTimeReceived, searchdate);
SearchFilter lessthanfilter = new SearchFilter.IsLessThan(ItemSchema.DateTimeReceived, searchdate);
SearchFilter filter = new SearchFilter.SearchFilterCollection(LogicalOperator.Or, lessthanfilter);
Folder folder = Folder.Bind(service, WellKnownFolderName.Inbox);
//Or the folder you want to search in
if (folder.TotalCount > 0)
{
FindItemsResults<Item> results = folder.FindItems(filter, new ItemView(folder.TotalCount));
if (results.Count() > 0)
{
foreach (Item i in results.Items)
{
i.Delete(DeleteMode.MoveToDeletedItems);
}
}
}
}
}
catch (Exception ex)
{
Logger.Write(ex);
}
finally
{
}
}
//To parse the email content
private MailItem[] getMailItem(ServiceResponseCollection<GetItemResponse> items, ExchangeService service)
{
MailItem[] mainItems = null;
try
{
mainItems = items.Select(item =>
{
return new MailItem()
{
Message = EmailMessage.Bind(service, item.Item.Id, new PropertySet(BasePropertySet.IdOnly, ItemSchema.Attachments, ItemSchema.HasAttachments)),
From = ((Microsoft.Exchange.WebServices.Data.EmailAddress)item.Item[EmailMessageSchema.From]).Address,
Recipients = ((Microsoft.Exchange.WebServices.Data.EmailAddressCollection)item.Item[EmailMessageSchema.ToRecipients]).Select(recipient => recipient.Address).ToArray(),
Subject = item.Item.Subject,
Body = item.Item.Body.ToString(),
Attachment = item.Item.Attachments.ToList(),
ReceivedDateTime = item.Item.DateTimeReceived
};
}).ToArray();
}
catch (Exception ex)
{
Logger.Write(ex);
}
finally
{
}
return mainItems;
}
jayakumar
All replies (5)
Wednesday, November 6, 2013 1:58 AM
Generally that means the other end has dropped the connection while it was in use. If your application is trying to run against multiple accounts using multiple threads then it could be throttling http://msdn.microsoft.com/en-us/library/office/jj945066(v=exchg.150).aspx.
The other time I've seen this is when you have a intermittent network link eg the link drops before the operations completed and then restabilises back and the client tries to continue to use the TCP connection that the other end has already dropped. There isn't much you can do in this instance other then catch the exception and retry the operation.
Cheers
Glen
Wednesday, November 6, 2013 4:31 AM
Hi Glen Scales,
Thanks for your reply
In this service application i uses timer to perform the operation
Whether this will be reason for connection drop.
public void _CheckMail()
{
ReadEmailContent();
timer = new System.Timers.Timer();
timer.Interval = 80000D;
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
timer.Enabled = true;
timer.Start();
}
protected void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
ReadEmailContent();
}
Whether there is any other option to overcome it, for reading the exchange server mails without any error log.
Thanks in advance
jayakumar
Wednesday, November 6, 2013 6:01 AM
Hi Glen Scales
I didn't got those error initially. ie i coded this one month before but at that time it works fine
jayakumar
Wednesday, November 6, 2013 6:02 AM
If your underlying network link isn't reliable, other then catching the exception and retrying the operation there isn't much you can do.
The code itself your using isn't that efficient if your processing a large number of items which may explain why you getting throttled (if you are).
a few things Eg instead of using Bind eg
Message = EmailMessage.Bind(service, item.Item.Id,
to load items one at time which will makes a separate request for each item you should look at using LoadPropertiesfromItems http://blogs.msdn.com/b/exchangedev/archive/2010/03/16/loading-properties-for-multiple-items-with-one-call-to-exchange-web-services.aspx . This will reduce the number of calls you application needs to make and reduce the likely hood of errors or throttling issues.
You should also batch the Deletes your making using deleteitems http://msdn.microsoft.com/en-us/library/microsoft.exchange.webservices.data.exchangeservice.deleteitems(v=exchg.80).aspx rather then calling the delete method on each item separately which will also reduce the number of calls your making to the server.
Also instead of using the SearchFilter like you have you would be better using an AQS query which will use the Exchange indexes and you also need to Page your searches in batches of 1000 (throttling will restrict this anyway so the query your using if your expecting to process any more then 1000 objects won't work as it is to process all the available items.).
eg
DateTime searchdate = DateTime.Now;
searchdate = searchdate.AddDays(-4);
Folder folder = Folder.Bind(service, WellKnownFolderName.Inbox);
String AQSQueryString = "System.Message.DateReceived:<" + searchdate.ToString("MM/dd/yyyy");
ItemView iv = new ItemView(1000);
//iv.PropertySet = new PropertySet(BasePropertySet.IdOnly);
//Or the folder you want to search in
if (folder.TotalCount > 0)
{
FindItemsResults<Item> results = null;
do
{
results = folder.FindItems(AQSQueryString, iv);
if (results.Count() > 0)
{
foreach (Item i in results.Items)
{
if (i.DateTimeReceived < searchdate)
{
Console.WriteLine(i.Subject);
}
}
}
iv.Offset += results.Items.Count;
} while (results.MoreAvailable);
}
Cheers
Glen
Thursday, November 7, 2013 8:00 AM
Hi Glen,
After gone through this http://msdn.microsoft.com/en-us/library/office/jj945066(v=exchg.150).aspx
i understand your points.
Thanks for your Comments
jayakumar