简体   繁体   English

如何从C#中的Outlook仅保存Excel附件?

[英]How to save only Excel attachments from outlook in C#?

I have to create a program which saves Excel attachments from the mail inbox. 我必须创建一个程序来保存邮件收件箱中的Excel附件。 At the moment I am saving all attachments from incoming mails via an event handler, but it seems like that the event is not always triggered but rather 3 from 4 mails only. 目前,我正在通过事件处理程序保存来自传入邮件的所有附件,但似乎该事件并非总是触发的,而是仅触发4个邮件中的3个。 I don't know the reason though. 我不知道原因。

So I was thinking about looping through the inbox mails, look for mails with specific subject title and save the attached Excel files. 因此,我正在考虑遍历收件箱邮件,查找具有特定主题标题的邮件并保存附加的Excel文件。

But how can I do that? 但是我该怎么办呢? Other solutions shows only via add in, but I want to use a Windows service for that. 其他解决方案仅通过加载项显示,但我想为此使用Windows服务。

So far my code (this doesn't work every time though, maybe someone knows a reason for that?) 到目前为止,我的代码(但这并非每次都有效,也许有人知道原因吗?)

public partial class MyService : ServiceBase
{
        public string AttachPath = @"[mypath to save attachments]";

        public MyService()
        {
            InitializeComponent();
        }

        public void RunAsConsole(string[] args)
        {
            Console.WriteLine("This service is executed as a console application.");
            Console.WriteLine("Application active.");
            OnStart(args);
            Console.WriteLine("Press q to exit.");
            string userInput = Console.ReadLine();

            while (userInput != "q")
            {
                userInput = Console.ReadLine();
            }

            Console.WriteLine("Finished! \nPress any key to exit...");
            Console.ReadLine();
            OnStop();
        }

        protected override void OnStart(string[] args)
        {
            Outlook.NameSpace outlookNameSpace;
            Outlook.MAPIFolder inbox;
            Outlook.Items items;

            Outlook.Application oApp = new Outlook.Application();
            outlookNameSpace = oApp.GetNamespace("MAPI");
            inbox = outlookNameSpace.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderInbox);

            items = inbox.Items;
            items.ItemAdd +=
                new Outlook.ItemsEvents_ItemAddEventHandler(items_ItemAdd);
        }

        void items_ItemAdd(object Item)
        {
            string filter = "[myFilter]";
            Outlook.MailItem mail = (Outlook.MailItem)Item;

            if (Item != null)
            {
                if (mail.Subject.ToUpper().Contains(filter.ToUpper()))
                {
                    Console.WriteLine(DateTime.Now.ToShortTimeString() + " Mail found!: " + mail.Subject);

                    if (mail.Attachments.Count > 0)
                    {
                        for (int i = 1; i - 1 < mail.Attachments.Count; ++i)
                        {
                            Console.WriteLine($@"Saving {mail.Attachments[i].FileName}");
                            //Console.WriteLine(Path.Combine(AttachPath, mail.Attachments[i].FileName));
                            string filepath = Path.Combine(AttachPath, mail.Attachments[i].FileName);
                            mail.Attachments[i].SaveAsFile(filepath);

                            //if (File.Exists(filepath))
                            //{
                            //    mail.Delete(); //after saving the file delete the mail
                            //}
                        }
                    }
                    else
                    {
                        Console.WriteLine("No attachments found: execute auto reply...");
                        Outlook.MailItem replyMail = mail.Reply();
                        replyMail.HTMLBody = $@"Some answer for reply";
                        replyMail.Send();
                    }

                    Console.WriteLine("Delete mail: " + mail.Subject.ToString());
                    mail.UnRead = false; //mark as read
                    mail.Delete();
                }
            }
        }

        protected override void OnStop()
        {
            //nothing
        }
    }

At the moment, the service can be executed as a console application and a Windows service, so please don't pay too much attention at that point, it's for debugging reasons. 目前,该服务可以作为控制台应用程序和Windows服务执行,因此此时请不要太在意,这是出于调试原因。

Other Solutions shows only via add in, but I want to use a windows service for that. 其他解决方案仅通过加载项显示,但我想为此使用Windows服务。

Microsoft does not currently recommend, and does not support, Automation of Microsoft Office applications from any unattended, non-interactive client application or component (including ASP, ASP.NET, DCOM, and NT Services), because Office may exhibit unstable behavior and/or deadlock when Office is run in this environment. Microsoft当前不建议也不支持任何无人参与的非交互客户端应用程序或组件(包括ASP,ASP.NET,DCOM和NT Services)中的Microsoft Office应用程序自动化,因为Office可能表现出不稳定的行为和/在此环境中运行Office时出现死锁或死锁。

If you are building a solution that runs in a server-side context, you should try to use components that have been made safe for unattended execution. 如果要构建在服务器端上下文中运行的解决方案,则应尝试使用对无人值守执行安全的组件。 Or, you should try to find alternatives that allow at least part of the code to run client-side. 或者,您应该尝试找到允许至少部分代码在客户端运行的替代方法。 If you use an Office application from a server-side solution, the application will lack many of the necessary capabilities to run successfully. 如果您从服务器端解决方案中使用Office应用程序,则该应用程序将缺少许多成功运行所需的功能。 Additionally, you will be taking risks with the stability of your overall solution. 此外,您将承担整体解决方案稳定性的风险。 Read more about that in the Considerations for server-side Automation of Office article. 在《 服务器端Office自动化注意事项》一文中了解有关此内容的更多信息。

As a workaround, you may consider using a low-level API on which Outlook is based on - Extended MAPI or just any wrappers around that API such as Redemption. 作为一种解决方法,您可以考虑使用基于Outlook的低级API-扩展MAPI或围绕该API的任何包装程序(如Redemption)。

If you deal with Exchange only, you may consider using Graph API or EWS, see Start using web services in Exchange for more information. 如果仅使用Exchange,则可以考虑使用Graph API或EWS,请参阅开始使用Exchange中的Web服务以获取更多信息。

Please refer to Eugene's answer on the architecture side of things. 请在架构方面参考Eugene的回答。 But from the perspective of extracting the emails with a filter, you can try this code. 但是从使用过滤器提取电子邮件的角度来看,您可以尝试以下代码。

Instead of getting items = inbox.Items , try finding the emails with a filter query which returns an Outlook.Table Then you can iterate on this table to get the emails. 而不是获取items = inbox.Items ,而是尝试使用过滤器查询查找返回Outlook.Table的电子邮件,然后可以对该表进行迭代以获取电子邮件。

const string PropTag = "http://schemas.microsoft.com/mapi/proptag/";
var filter = "@SQL=" + "\"" + PropTag
         + "0x0037001E" + "\"" + " ci_phrasematch " + "\'" + strFilter + "\'";

Outlook.Table table = inbox.GetTable(filter, Outlook.OlTableContents.olUserItems);

while (!table.EndOfTable)            
{
        Outlook.Row nextRow = table.GetNextRow();
        try
        {
            Outlook.MailItem mi;
            try
            {
                string entryId = nextRow["EntryID"];
                var item = outlookNameSpace.GetItemFromID(entryId);
                mi = (Outlook.MailItem)item;
            }
            catch (InvalidCastException ex)
            {
                Console.WriteLine("Cannot cast mail item, so skipping. Error: {0}", e);                       
                continue;
            } 
            //Extract the attachments here and archive or reply - put your logic here
        }
        catch (Exception e)
        {   
            Console.WriteLine("An error occurred: '{0}'", e);
        }
 }  

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM