/// <summary>
        /// Build search filter from options.
        /// </summary>
        /// <param name="options">Options.</param>
        /// <returns>Search filter collection.</returns>
        private static SearchFilter.SearchFilterCollection BuildFilterCollection(ExchangeOptions options)
        {
            // Create search filter collection.
            var searchFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.And);

            // Construct rest of search filter based on options
            if (options.GetOnlyEmailsWithAttachments)
            {
                searchFilter.Add(new SearchFilter.IsEqualTo(ItemSchema.HasAttachments, true));
            }

            if (options.GetOnlyUnreadEmails)
            {
                searchFilter.Add(new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, false));
            }

            if (!string.IsNullOrEmpty(options.EmailSenderFilter))
            {
                searchFilter.Add(new SearchFilter.IsEqualTo(EmailMessageSchema.Sender, options.EmailSenderFilter));
            }

            if (!string.IsNullOrEmpty(options.EmailSubjectFilter))
            {
                searchFilter.Add(new SearchFilter.ContainsSubstring(EmailMessageSchema.Subject, options.EmailSubjectFilter));
            }

            return(searchFilter);
        }
        /// <summary>
        /// Save attachments from collection to files.
        /// </summary>
        /// <param name="attachments">Attachments collection.</param>
        /// <param name="options">Options.</param>
        /// <returns>List of full paths to saved file attachments.</returns>
        private static List <string> SaveAttachments(Microsoft.Exchange.WebServices.Data.AttachmentCollection attachments, ExchangeOptions options)
        {
            List <string> pathList = new List <string> {
            };

            foreach (var attachment in attachments)
            {
                FileAttachment file = attachment as FileAttachment;
                string         path = Path.Combine(
                    options.AttachmentSaveDirectory,
                    options.OverwriteAttachment ? file.Name :
                    String.Concat(
                        Path.GetFileNameWithoutExtension(file.Name), "_",
                        Guid.NewGuid().ToString(),
                        Path.GetExtension(file.Name))
                    );
                file.Load(path);
                pathList.Add(path);
            }

            return(pathList);
        }
/// <summary>
/// Convert Email collection t EMailMessageResults.
/// </summary>
/// <param name="emails">Emails collection.</param>
/// <param name="exchangeService">Exchange services.</param>
/// <param name="options">Options.</param>
/// <returns>Collection of EmailMessageResult.</returns>
        private static List <EmailMessageResult> ReadEmails(IEnumerable <EmailMessage> emails, ExchangeService exchangeService, ExchangeOptions options)
        {
#if NET471
            List <EmailMessageResult> result = new List <EmailMessageResult>();

            foreach (EmailMessage email in emails)
            {
                // Define property set
                var propSet = new PropertySet(
                    BasePropertySet.FirstClassProperties,
                    EmailMessageSchema.Body,
                    EmailMessageSchema.Attachments);

                // Bind and load email message with desired properties
                var newEmail = EmailMessage.Bind(exchangeService, email.Id, propSet);

                var pathList = new List <string>();
                if (!options.IgnoreAttachments)
                {
                    // Save all attachments to given directory

                    pathList = SaveAttachments(newEmail.Attachments, options);
                }

                // Build result for email message

                var emailMessage = new EmailMessageResult
                {
                    Id                 = newEmail.Id.UniqueId,
                    Date               = newEmail.DateTimeReceived,
                    Subject            = newEmail.Subject,
                    BodyText           = "",
                    BodyHtml           = newEmail.Body.Text,
                    To                 = string.Join(",", newEmail.ToRecipients.Select(j => j.Address)),
                    From               = newEmail.From.Address,
                    Cc                 = string.Join(",", newEmail.CcRecipients.Select(j => j.Address)),
                    AttachmentSaveDirs = pathList
                };


                // Catch exception in case of server version is earlier than Exchange2013
                try { emailMessage.BodyText = newEmail.TextBody.Text; } catch { }

                result.Add(emailMessage);
            }

            return(result);
#else
            throw new Exception("Only supported on .NET Framework (i.e. on Windows).");
#endif
        }
/// <summary>
/// Reads emails from an Exchange server. Can be used only on legacy (Windows) agents.
/// </summary>
/// <param name="settings">Settings to use</param>
/// <param name="options">Options to use</param>
/// <returns>
/// List of
/// {
/// string Id.
/// string To.
/// string Cc.
/// string From.
/// DateTime Date.
/// string Subject.
/// string BodyText.
/// string BodyHtml.
/// List(string) AttachmentSaveDirs
/// }
/// </returns>
        public static List <EmailMessageResult> ReadEmailFromExchangeServer([PropertyTab] ExchangeSettings settings, [PropertyTab] ExchangeOptions options)
        {
#if NET471
            if (!options.IgnoreAttachments)
            {
                // Check that save directory is given
                if (options.AttachmentSaveDirectory == "")
                {
                    throw new ArgumentException("No save directory given. ",
                                                nameof(options.AttachmentSaveDirectory));
                }
                // Check that save directory exists
                if (!Directory.Exists(options.AttachmentSaveDirectory))
                {
                    throw new ArgumentException("Could not find or access attachment save directory. ",
                                                nameof(options.AttachmentSaveDirectory));
                }
            }

            // Connect, create view and search filter
            ExchangeService         exchangeService = Services.ConnectToExchangeService(settings);
            ItemView                view            = new ItemView(options.MaxEmails);
            var                     searchFilter    = BuildFilterCollection(options);
            FindItemsResults <Item> exchangeResults;

            if (!string.IsNullOrEmpty(settings.Mailbox))
            {
                var mb    = new Mailbox(settings.Mailbox);
                var fid   = new FolderId(WellKnownFolderName.Inbox, mb);
                var inbox = Folder.Bind(exchangeService, fid);
                exchangeResults = searchFilter.Count == 0 ? inbox.FindItems(view) : inbox.FindItems(searchFilter, view);
            }
            else
            {
                exchangeResults = searchFilter.Count == 0 ? exchangeService.FindItems(WellKnownFolderName.Inbox, view) : exchangeService.FindItems(WellKnownFolderName.Inbox, searchFilter, view);
            }
            // Get email items
            List <EmailMessage> emails = exchangeResults.Where(msg => msg is EmailMessage).Cast <EmailMessage>().ToList();

            // Check if list is empty and if an error needs to be thrown.
            if (emails.Count == 0 && options.ThrowErrorIfNoMessagesFound)
            {
                // If not, return a result with a notification of no found messages.
                throw new ArgumentException("No messages matching the search filter found. ",
                                            nameof(options.ThrowErrorIfNoMessagesFound));
            }

            // Load properties for each email and process attachments
            var result = ReadEmails(emails, exchangeService, options);

            // should delete mails?
            if (options.DeleteReadEmails)
            {
                emails.ForEach(msg => msg.Delete(DeleteMode.HardDelete));
            }

            // should mark mails as read?
            if (!options.DeleteReadEmails && options.MarkEmailsAsRead)
            {
                foreach (EmailMessage msg in emails)
                {
                    msg.IsRead = true;
                    msg.Update(ConflictResolutionMode.AutoResolve);
                }
            }

            return(result);
#else
            throw new Exception("Only supported on .NET Framework (i.e. on Windows).");
    #endif
        }