[英]How to save only Excel attachments from outlook in C#?
我必须创建一个程序来保存邮件收件箱中的Excel附件。 目前,我正在通过事件处理程序保存来自传入邮件的所有附件,但似乎该事件并非总是触发的,而是仅触发4个邮件中的3个。 我不知道原因。
因此,我正在考虑遍历收件箱邮件,查找具有特定主题标题的邮件并保存附加的Excel文件。
但是我该怎么办呢? 其他解决方案仅通过加载项显示,但我想为此使用Windows服务。
到目前为止,我的代码(但这并非每次都有效,也许有人知道原因吗?)
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
}
}
目前,该服务可以作为控制台应用程序和Windows服务执行,因此此时请不要太在意,这是出于调试原因。
其他解决方案仅通过加载项显示,但我想为此使用Windows服务。
Microsoft当前不建议也不支持任何无人参与的非交互客户端应用程序或组件(包括ASP,ASP.NET,DCOM和NT Services)中的Microsoft Office应用程序自动化,因为Office可能表现出不稳定的行为和/在此环境中运行Office时出现死锁或死锁。
如果要构建在服务器端上下文中运行的解决方案,则应尝试使用对无人值守执行安全的组件。 或者,您应该尝试找到允许至少部分代码在客户端运行的替代方法。 如果您从服务器端解决方案中使用Office应用程序,则该应用程序将缺少许多成功运行所需的功能。 此外,您将承担整体解决方案稳定性的风险。 在《 服务器端Office自动化注意事项》一文中了解有关此内容的更多信息。
作为一种解决方法,您可以考虑使用基于Outlook的低级API-扩展MAPI或围绕该API的任何包装程序(如Redemption)。
如果仅使用Exchange,则可以考虑使用Graph API或EWS,请参阅开始使用Exchange中的Web服务以获取更多信息。
请在架构方面参考Eugene的回答。 但是从使用过滤器提取电子邮件的角度来看,您可以尝试以下代码。
而不是获取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.