将一封或多封邮件从 Outlook 拖放到 C# WPF 应用程序

Posted

技术标签:

【中文标题】将一封或多封邮件从 Outlook 拖放到 C# WPF 应用程序【英文标题】:Drag'n'drop one or more mails from Outlook to C# WPF application 【发布时间】:2010-09-23 22:23:18 【问题描述】:

我正在开发一个在 .Net 3.5 Sp1 上使用 C# 用 WPF 编写的 Windows 客户端,其要求是客户端收到的电子邮件中的数据可以存储在数据库中。现在最简单的处理方法是复制和粘贴文本、主题、联系信息和手动接收到的时间,使用可诱发关节炎的量 ctrl-c/ctrl-v。

我认为处理此问题的一种简单方法是允许用户将一封或多封电子邮件从 Outlook(它们目前都使用 Outlook 2007)拖到窗口中,允许我的应用程序提取必要的信息并发送它到后端系统进行存储。

然而,在谷歌上搜索这方面的信息几个小时似乎表明关于这个看似基本的任务的信息令人震惊地缺乏。我认为这样的东西在很多不同的环境中都会很有用,但到目前为止我所能找到的只是半生不熟的非解决方案。

有人对如何做到这一点有任何建议吗?因为我只是要阅读邮件而不是发送任何东西或做任何邪恶的事情,所以最好有一个不涉及讨厌的安全弹出窗口的解决方案,但任何事情都比无法做到这一点要好。

基本上,如果我能获得所有从 Outlook 中选择、拖放的邮件项目的列表,我就可以自己处理其余的了!

谢谢!

符文

【问题讨论】:

Rune 你还在寻找答案吗? 嗨,克里斯 - 是的,上个月我刚刚参与了一个完全不同的项目。一旦我的头浮出水面,我会尽力跟进。 您是否应该绑定到您的 Exchange 服务器,并以这种方式访问​​ Outlook 邮箱?为什么不研究 CDO 对象?这允许您从 Exchange 服务器获取邮件集合。 msdn.microsoft.com/en-us/library/ms978698.aspx Devtron - 在这种情况下,需要直接从 Outlook 处理拖放到 WPF 应用程序。因此,我必须以某种方式解释数据。否则,肯定会考虑 CDO 或赎回! 【参考方案1】:

我找到了一个很棒的article,它应该可以满足您的需要。

更新

稍作调整,我就能让那篇文章中的代码在 WPF 中工作,以下是您需要进行的更改。

将所有引用从 System.Windows.Forms.IDataObject 更改为 System.Windows.IDataObject

在 OutlookDataObject 构造函数中,更改

FieldInfo innerDataField = this.underlyingDataObject.GetType().GetField("innerData", BindingFlags.NonPublic | BindingFlags.Instance);

FieldInfo innerDataField = this.underlyingDataObject.GetType().GetField("_innerData", BindingFlags.NonPublic | BindingFlags.Instance);

将所有 DataFormats.GetFormat 调用更改为 DataFormats.GetDataFormat

更改 SetData 实现
public void SetData(string format, bool autoConvert, object data)

    this.underlyingDataObject.SetData(format, autoConvert, data);

public void SetData(string format, object data, bool autoConvert)

    this.underlyingDataObject.SetData(format, data, autoConvert);

通过这些更改,我能够像文章一样将消息保存到文件中。抱歉格式化,但编号/项目符号列表不适用于代码 sn-ps。

【讨论】:

谢谢 - 我也找到了这个并尝试使用它,但是我正在研究 System.Windows.Forms.IDataObject(在 Windows 窗体和本文中使用的那个)和System.Windows.IDataObject(WPF 使用的那个)。我不知道足够多的 COM(或任何看起来很可怕的东西)来让它工作,看起来..! 我已更新我的帖子以反映在 WPF 中工作所需的更改。 再次感谢 - 我非常接近为我工作,只需要在拖动多条消息时处理一些异常。恭喜你解决了一个困难的问题。 :) 你找到解决这个问题的方法了吗?【参考方案2】:

我发现很多解决方案建议您对所有文件名使用“FileGroupDescriptor”,并在 DragEventArgs 对象上使用“FileContents”来检索每个文件的数据。 “FileGroupDescriptor”适用于电子邮件名称,但“FileContents”返回 null,因为 .Net 中的 IDataObject 实现无法处理 COM 返回的 IStorage 对象。

David Ewen 有很好的解释、出色的示例和代码下载,在 http://www.codeproject.com/KB/office/outlook_drag_drop_in_cs.aspx 上运行良好。

【讨论】:

谢谢,这看起来很有希望 - 但是,它基于 WinForms (?) IDataObject,而 WPF 中使用的 IDataObject 略有不同。为此,我需要一种“无损”方式在两者之间进行转换,或者......?【参考方案3】:

您需要在您的 Xaml 中设置您的事件:

<TextBlock
        Name="myTextBlock"  
        Text="Drag something into here"
        AllowDrop="True" 
        DragDrop.Drop="myTextBlock_Drop"
        />

一旦你设置了 AllowDrop = True 并设置了你的 drop 事件,然后转到后面的代码并设置你的事件:

private void myTextBlock_Drop(object sender, DragEventArgs e)

         // Mark the event as handled, so TextBox's native Drop handler is not called.
         e.Handled = true;
         Stream sr;

          //Explorer 
          if (e.Data.GetDataPresent(DataFormats.FileDrop, true))
              //Do somthing

        //Email Message Subject 
        if (e.Data.GetDataPresent("FileGroupDescriptor"))
        
            sr = e.Data.GetData("FileGroupDescriptor") as Stream;
                StreamReader sr = new StreamReader(sr2);//new StreamReader(strPath, Encoding.Default);
            //Message Subject
                    string strFullString = sr.ReadToEnd();
         



如果你想进一步分解它,你可以使用: FILEDESCRIPTOR 或 FILECONTENTS 作为大纲如下article

您的另一个选择是绑定到前景 MS Office Primary Interop Assemblies 并以这种方式分解消息。

【讨论】:

FileGroupDescriptor 不包含文本,仅包含二进制数据。结果 strFullString 不包含任何可读内容 我在发布之前确实测试了代码,也许您需要更改编码? cgreeno - 我忘了评论我试过这个,但我得到的只是一堆零和中间的某个地方,消息的主题。 IE。如果我拖动主题为“Adresse”的消息,我会得到:\0\0\0 [等等,其中很多] Adresse.msg \0\0\0\0\0\0 [更多其中]。如果我删除 \0 字符,我可以在主题中找到,但没有迹象表明我可以在哪里找到邮件正文、任何附件、发件人或其他需要的信息。感谢您的尝试,非常感谢。 :)【参考方案4】:

我认为Shell Style Drag and Drop in .NET (WPF and WinForms) 可以帮助您。一旦您可以使用 COM 接口响应拖放,您应该能够从 Outlook 中获取数据。

【讨论】:

【参考方案5】:

我假设您有一个在 Outlook 后面运行的 Exchange 服务器。

您可以做的是从 Exchange 服务器检索邮件并根据邮件的 EntryIDStoreID 将其位置存储在您的数据库中。这是一个 VB.Net sn-p:

Imports Microsoft.Office.Interop

Public Class OutlookClientHandler

Private _application As Outlook.Application
Private _namespace As Outlook.NameSpace

Public Sub New()
    If Process.GetProcessesByName("outlook".ToLower).Length > 0 Then
        _application = New Outlook.Application
    Else
        Dim startInfo As ProcessStartInfo = New ProcessStartInfo("outlook.exe")
        startInfo.WindowStyle = ProcessWindowStyle.Minimized
        Process.Start(startInfo)

        _application = New Outlook.Application
    End If
End Sub

' Retrieves the specified e-mail from Outlook/Exchange via the MAPI
Public Function GetMailItem(ByVal entryID as String, ByVal storeID as String) As Outlook.MailItem
    _namespace = _application.GetNamespace("MAPI")
    Dim item As Outlook.MailItem
    Try
        item = _namespace.GetItemFromID(entryID, storeID)
    Catch comex As COMException
        item = Nothing ' Fugly, e-mail wasn't found!
    End Try

    Return item
End Function
End Class

我猜您对使用 MAPI 感到满意,否则您可以在此处阅读: http://msdn.microsoft.com/en-us/library/cc765775(v=office.12).aspx

从 Outlook 中检索选定的电子邮件:

Public Function GetSelectedItems() As List(Of Object) 
    Dim items As List(Of Object) = New List(Of Object)

    For Each item As Object In _application.ActiveExplorer().Selection
        items.Add(item)
    Next

    Return items
End Function

从 Outlook 检索电子邮件后,您可以将它们推送到您的数据库中!保存他们的EntryIDStoreID(您可能还想存储他们父级的(文件夹的)EntryIDStoreID)。

【讨论】:

以上是关于将一封或多封邮件从 Outlook 拖放到 C# WPF 应用程序的主要内容,如果未能解决你的问题,请参考以下文章

将电子邮件从 MS Outlook 拖放到 Eclipse RCP

如何确定Outlook拖放期间拖动的附件

无法在多封电子邮件中重复使用电子邮件附件

如何解决Outlook收件箱显示1000多封邮件,但是查看时都是已读的?

如何将多行转换为不同的列?

Lotus Notes电子邮件作为另一封电子邮件的附件