ews-managed-api
                                
                                 ews-managed-api copied to clipboard
                                
                                    ews-managed-api copied to clipboard
                            
                            
                            
                        Unable to download FileAttachment
Hello! I'm having a hard time downloading attachments.
The below code never downloads an attachment:
        private Dictionary<string, Stream> DownloadAttachments(EmailMessage message)
        {
            var result = new Dictionary<string, Stream>();
            var pdfAttachments = message.Attachments.Where(a => a.ContentType.Equals("application/pdf", StringComparison.OrdinalIgnoreCase));
            Log.Debug($"{pdfAttachments.Count()} attachment(s) found.");
            foreach (FileAttachment attachment in pdfAttachments)
            {
                var ms = new MemoryStream(attachment.Size);
                attachment.Load(ms);
                result.Add(attachment.Name, ms);
            }
            return result;
        }
No error is thrown; the attachment.Content property is null, and the length of the MemoryStream is 0. The metadata for the attachment is downloaded correctly though. I can obtain attachment filename, size, and content type.
Please note, that the EmailMessage message argument is already bound to an ExchangeService by the calling method using the ItemSchema.Attachments amongst other schemas.
Any help/insights would be greatly appreciated!
Try load message first then try to find attachments.
private Dictionary<string, Stream> DownloadAttachments(EmailMessage message)
{
    var result = new Dictionary<string, Stream>();
    message.Load();
    var pdfAttachments = message.Attachments.Where(a => a.ContentType.Equals("application/pdf", StringComparison.OrdinalIgnoreCase));
    Log.Debug($"{pdfAttachments.Count()} attachment(s) found.");
    foreach (FileAttachment attachment in pdfAttachments)
    {
        var ms = new MemoryStream(attachment.Size);
        attachment.Load(ms);
        result.Add(attachment.Name, ms);
    }
    return result;
}
Yes, I'm already doing this in the calling method like this (code is shortened for brevity):
var newMail = await EmailMessage.Bind(Server, email.ItemId, EmailSchema);
await newMail.Load();
var attachments = DownloadAttachents(newMail);
This works for me
var message = await EmailMessage.Bind(_exchange, item.Id, new PropertySet(ItemSchema.Attachments));
await message.Load();
var attachment = attachments[0] as FileAttachment;
string file = Path.Combine(FolderPath, attachment.FileName);
await attachment.Load(file);
Thanks for your assistance @LubosVoska! The funny thing is I was thinking the same thing because that approach is all over the Internet. However, it doesn't work for me :(
I'm using the NuGet package 1.1.3 Do you see anything wrong with it? Should I integrate EWS by some other means?
Try to use version 2.0.0. I am using 2.0.0-beta1 but there is newer version 2.0.0-beta2.
FYI, 2.0.0-beta2 leads to another issue: opening a StreamingSubscriptionConnection hangs till the HttpClient timeout then throws. I'm trying 2.0.0-beta1 and get back with some news...
No joy. 2.0.0-beta1 has the same issue as 2.0.0-beta2.
System.AggregateException: One or more errors occurred. (The request failed. The request was canceled due to the configured HttpClient.Timeout of 100 seconds elapsing.)
 ---> Microsoft.Exchange.WebServices.Data.ServiceRequestException: The request failed. The request was canceled due to the configured HttpClient.Timeout of 100 seconds elapsing.
 ---> Microsoft.Exchange.WebServices.Data.EwsHttpClientException: The request was canceled due to the configured HttpClient.Timeout of 100 seconds elapsing.
   at Microsoft.Exchange.WebServices.Data.EwsHttpWebRequest.GetResponse()
   at Microsoft.Exchange.WebServices.Data.ServiceRequestBase.GetEwsHttpWebResponse(IEwsHttpWebRequest request)
   --- End of inner exception stack trace ---
   at Microsoft.Exchange.WebServices.Data.ServiceRequestBase.GetEwsHttpWebResponse(IEwsHttpWebRequest request)
   at Microsoft.Exchange.WebServices.Data.ServiceRequestBase.ValidateAndEmitRequest()
   --- End of inner exception stack trace ---
   at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
   at System.Threading.Tasks.Task`1.get_Result()
   at Microsoft.Exchange.WebServices.Data.HangingServiceRequestBase.InternalExecute()
   at Microsoft.Exchange.WebServices.Data.StreamingSubscriptionConnection.Open()
   at Lantech.Salechase.Business.MsExchangeMailboxMonitor.Watch(Object folder, Boolean skipInitialSync) in C:\Users\bstoinev...\MsExchangeMailboxMonitor.cs:line 217
   at Lantech.Salechase.WindowsService.SalechaseService.StartMonitoringWithRetry() in C:\Users\bstoinev...\SalechaseService.cs:line 106
And this is the offending code:
            var streamIsClosed = !Stream.CurrentSubscriptions.Any();
            var subscription = await Server.SubscribeToStreamingNotifications(new FolderId[] { targetFolderId }, EventType.NewMail);
            Stream.AddSubscription(subscription);
            if (streamIsClosed)
            {
                // This next line hangs for 100 seconds then throws the above error.
                Stream.Open();
            }
Unfortunately i don't have Exchange to test currrently. If you can give me (privately) a sample account + code that doesn't work I can check it.
I'm in the same shoes; I'm using Office 365 but am initializing with ExchangeVersion.Exchange2010_SP1 like this:
            Server = new ExchangeService(ExchangeVersion.Exchange2010_SP1)
            {
                Credentials = new WebCredentials(Config.Mailbox, Config.Password),
                TraceEnabled = true,
                TraceFlags = TraceFlags.All,
                Url = new Uri(Config.Endpoint)
            };
Is this the issue? Do I need a real MS Exchange, in my case version 2010 to accomplish what I'm after? Otherwise, I have no issues sharing the test mailbox details in private...
FYI, I have to use 2010 as this is the production requirement. So far I'm developing in a lab environment, using Office 365.
Try this
public ExchangeService ConnectToExchange(string username, string password, string email)
{
        var exchange = new ExchangeService(ExchangeVersion.Exchange2013_SP1);
        exchange.TraceEnabled = true;
        exchange.Credentials = new WebCredentials(email, password);
        exchange.UseDefaultCredentials = false;
        exchange.PreAuthenticate = false;
        exchange.Url = new Uri("https://outlook.office365.com/EWS/Exchange.asmx");
        exchange.AutodiscoverUrl(email, (url) =>
        {
            // The default for the validation callback is to reject the URL.
            bool result = false;
            Uri redirectionUri = new Uri(url);
            // Validate the contents of the redirection URL. In this simple validation
            // callback, the redirection URL is considered valid if it is using HTTPS
            // to encrypt the authentication credentials. 
            if (redirectionUri.Scheme == "https")
            {
                result = true;
            }
            return result;
        });
        return exchange;
}
Ah, sorry @LubosVoska but you're getting out of context...I have no issues connecting with the mailbox and actually am receiving streaming notifications in real-time, searching items, moving stuff around, etc. All the email attributes received are as expected with the exception of the attachments which is the current issue...
However, I just tried the above suggestion for ExchangeVersion.Exchange2013_SP1 and it doesn't make a difference.
This does not work in 1.1.3, because of missing await in FileAttachment.Load function.
It works in 2.0.0-beta2, where FileAttachment.Load is made async.
Same problem is discussed in #40
Hi @mirecad, where to get the v2 version of the NuGet Package? I cannot even find the repo and who has made it...
Related to the missing await for the Load functions: it has not been the only bug, if you take a look at on the souce code in the master branch, there are only dummy implementations for both Load method overrides: https://github.com/sherlock1982/ews-managed-api/blob/master/ComplexProperties/FileAttachment.cs
Should be the OfficeDev the official repo for the implementation? They neither seem to have an implemenation for the Load(Stream stream) and Load(string) methods.
Has somebody already a fork, which has made some meaningful steps to solve the problem?
For those who stay with the stable v1.1.3 from nuget.org: ` string emailId = "xxxx";
        // sorry, these 2 lines reference to my external code, but simple calls the EmailMessage.Bind with the unique id
        EmailMessage emailMsg = exchService.GetEmailMessage(emailId);
        await emailMsg.Load();
        if (emailMsg.HasAttachments)
            foreach (FileAttachment fileAttachment in emailMsg.Attachments.Where(att => att is FileAttachment))
            {
                await fileAttachment.Load();
                
                    //fileAttachment.Load($"./{fileAttachment.Name}"); // not working due to dummy implemenation
                using (var fileOutput = new FileStream($"./{fileAttachment.Name}", FileMode.Create, FileAccess.Write))
                    fileOutput.Write(fileAttachment.Content, 0, fileAttachment.Content.Length);
            }
`
I simply use the async Load method of the base class, which works and loads the Content property with bytes of the file.
hi @sherlock1982 , at first many thanks for your fork! I'm a little bit sceptic, what you want to do with a real account: in order to replace the dummy implementation a mock is fairly enough and should be faster than playing with a real EWS.
Hi @mirecad, where to get the v2 version of the NuGet Package? I cannot even find the repo and who has made it...
Look for prerelease packages: https://www.nuget.org/packages/Microsoft.Exchange.WebServices.NETStandard/2.0.0-beta2
According to AssemblyInfoOpenSource.cs the master branch is on the version 2.2.1 - still with missing/dummy implementation of Load(Stream stream) and Load(string fileName), that means, the upgrade to 2.0.0-beta2 cannot really solve the problem right?
Has somebody already a fork, which has made some meaningful steps to solve the problem? If not, than I might have some time at the weekend to create fork with the implementation.
I've started to fix the missing implementation, but I miss the information/documentation on the private member 'loadToStream'. I have the strong assumption, that this class member has nothing to do with referential integrity. I hope, nobody will have bad feelings about the removal of it from the method (it's simply useless).