【问题标题】:Outlook MailItem: How to distinguish whether mail is incoming or outgoing?Outlook MailItem:如何区分邮件是传入还是传出?
【发布时间】:2010-11-20 02:52:24
【问题描述】:

我正在用 C# 编写 VSTO Outlook 插件,我需要区分给定的 MailItem 是传入还是传出(或者两者都不是,例如草稿)。

有什么万无一失的方法吗?我现在拥有的最佳解决方案是获取收件人、抄送和密件抄送列表,从活动帐户加载电子邮件地址,并检查这两个列表是否相交,但这对我来说似乎很脆弱,我希望有更好的解决方案.

用例:我想获得一封电子邮件的相关日期,可以是 ReceivedTime 或 SentOn,但要知道我应该使用哪个日期,我需要知道邮件是已发送还是已接收。

谢谢你的想法:)

【问题讨论】:

  • 您是否必须检查所有收件人、抄送等,或者您可以只查看发件人吗?如果帐户所有者没有发送它,那么它就会收到。
  • 不是所有收到的邮件也都发送了吗?

标签: c# outlook vsto mailitem


【解决方案1】:

我与 SenderName 与 CurrentUser 相矛盾,以区分收件箱或已发送文件夹中的电子邮件。

【讨论】:

  • 如果您在配置文件中有多个帐户,这将不起作用 - 例如,我有多个 POP3/SMTP 帐户发送到 Exchange 邮箱。
【解决方案2】:

对于通过 SMTP 地址进行简单的发送/接收控制,我建议使用地址检查方法。 可以这样实现:

'Get mail address sender
        Dim mailSender As String = GetSenderSMTPAddress(outMailItem)

'Get current user mail address
        Dim mailUser As String = OutlookMail2DocScriba.GetUserSMTPAddress(oNameSpace.CurrentUser.AddressEntry)

        'If sender and current user matches is a sended mail, otherwise received
        If String.Compare(mailSender, mailUser, True) = 0 Then
            Return "Sended"
        Else
            Return "Received"
        End If





    Public Shared Function GetSenderSMTPAddress(ByVal mail As Outlook.MailItem) As String
            'http://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook.oladdresslisttype.aspx

            If mail Is Nothing Then
                Throw New ArgumentNullException()
            End If
            If mail.SenderEmailType = "EX" Then
                Dim sender As Outlook.AddressEntry = Nothing

                Try
                    sender = mail.Sender
                Catch ex As Exception
                    'Se non è stato in grado di reperire il sender (Outlook 2007), 
                    'ignoro l'eccezione e procedo.
                End Try

                If sender IsNot Nothing Then
                    Return GetUserSMTPAddress(sender)
                Else
                    Return Nothing
                End If
            Else
                Return mail.SenderEmailAddress
            End If
        End Function

        Public Shared Function GetUserSMTPAddress(ByVal sender As Outlook.AddressEntry) As String
            'Now we have an AddressEntry representing the Sender
            'http://msdn.microsoft.com/en-us/library/office/ff868214(v=office.15).aspx
            Const EXCHANGE_USER_ADDRESS_ENTRY As Int32 = 0
            Const EXCHANGE_REMOTE_USER_ADDRESS_ENTRY As Int32 = 5
            Dim PR_SMTP_ADDRESS As String = "http://schemas.microsoft.com/mapi/proptag/0x39FE001E"

            If sender.AddressEntryUserType = EXCHANGE_USER_ADDRESS_ENTRY OrElse _
               sender.AddressEntryUserType = EXCHANGE_REMOTE_USER_ADDRESS_ENTRY Then
                'Use the ExchangeUser object PrimarySMTPAddress
                Dim exchUser As Object = sender.GetExchangeUser()
                If exchUser IsNot Nothing Then
                    Return exchUser.PrimarySmtpAddress
                Else
                    Return Nothing
                End If
            Else
                Return TryCast(sender.PropertyAccessor.GetProperty(PR_SMTP_ADDRESS), String)
            End If
        End Function

【讨论】:

    【解决方案3】:

    来到这个页面是因为我在 VBA 中遇到了同样的问题。检查父文件夹很麻烦,因为一条消息可以保存在几个文件夹深处(因此您必须迭代几个文件夹)或者用户可能已经更改了文件夹。一个极端的例子:已删除的项目文件夹包含传入和传出的邮件项目。

    我选择了与上面另一个人(Adi Kini)类似的解决方案,我在上面检查了 ReceivedByName(我认为他选择了 ReceivedEntryID)。对于已发送的消息,ReceivedByName 属性始终为 Null (""),无论它当前位于何处。此方法可以找到已被拖到收件箱的已发送邮件!这似乎是一种相当可靠的检查方法。

    看起来很奇怪,检查邮件是传入还是传出这样一个看似简单的事情却会让我们感到困惑!

    【讨论】:

    • 请注意,如果邮件是由分配了地址的公用文件夹接收的,ReceivedByNameReceivedEntryID 都不会有值。
    【解决方案4】:

    这就是我检查邮件类型的方式,即使将邮件移动到任何文件夹也能正常工作。此解决方案使用 Outlook 2007 中提供的属性访问器。下面是代码

    string PR_MAIL_HEADER_TAG = "http://schemas.microsoft.com/mapi/proptag/0x007D001E";
    
    Outlook.PropertyAccessor oPropAccessor = mItemProp.PropertyAccessor;
    
    string strHeader = (string)oPropAccessor.GetProperty(PR_MAIL_HEADER_TAG);
    
    if (strHeader == "")
    {
        // MAIL IS OF TYPE SENTBOX
    }
    else
    {
       // MAIL IS OF TYPE INBOX
    }
    

    【讨论】:

    • 适用于交换邮件帐户,但不适用于 imap/smtp - 使用 ol 2016 测试
    【解决方案5】:

    我通过在发送电子邮件后添加新的 UserProperty 解决了这个问题。因此,当我需要检查是否发送了电子邮件时,我会检查此属性。即使将电子邮件移出“已发送”文件夹,此操作也有效。当然,这仅适用于新创建的电子邮件,但您可以在首次启动时将此属性添加到已发送文件夹中的所有电子邮件。唯一的错误是默认打印 UserProperties,但这可以是 overridden

    【讨论】:

    • 这是一个非常重量级的解决方案,但可能只有一个可以工作。但是,加载项必须一直运行 - 否则我们会收到未标记的已接收电子邮件 - 并且在第一次启动时。我们将无法标记已移动到其他文件夹的已发送电子邮件。也许可以扫描所有邮件并查看收件人是否是用户的电子邮件地址之一,但对于大型交换/IMAP 帐户,这可能需要数小时...
    【解决方案6】:

    您可以检查它是否在Outlook.OlDefaultFolders.olFolderInboxolFolderOutbox 中,然后应该有其他方法可以用来检查它是否在这两个文件夹中!

    Outlook.Application _application = new Outlook.Application();
    Outlook.MAPIFolder folder = _application.GetNamespace("MAPI").GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
    

    【讨论】:

    • 我认为这不适用于已发送/接收的已移动到另一个文件夹(例如使用过滤器)的邮件 - 会吗?
    【解决方案7】:

    MailItem.sent 也适用于传入。

    如何检查 MailItem.ReceivedByEntryID。但我确信如果您说从 Outlook Express 或其他电子邮件程序导入,这将失败(ReceivedByEntryID 对于收件箱中的邮件将为空)

    如您所说,遍历邮件帐户/senderemail 可能会有所帮助,但它不是万无一失的(例如,如果您重命名电子邮件地址)

    【讨论】:

    • 谢谢!这可能适用于大多数用户,因为我认为许多企业用户不会从 Outlook Express 导入他们的电子邮件(即使他们这样做了,大多数有用的操作仍然只涉及 Outlook 接收的最近邮件)。
    【解决方案8】:

    我带着同样的问题来到这里。由于我会明确建议用户将邮件移动到我的用例中的某个文件夹,因此检查 Parent 将无济于事......

    关于 MailItem.Sent:您确定 MailItem.Sent 以这种方式工作吗?我刚刚编写了一个简单的代码来运行我的收件箱和 SentItems,几乎所有的 Sent 都是真的。我认为这实际上只是表明邮件是否已发送(= 不是草稿)...

    【讨论】:

      【解决方案9】:

      您尝试过 MailItem.Sent 属性吗?

      传入为真,传出为假。

      【讨论】:

      【解决方案10】:

      查看 MailItem 的 .Parent 属性 - 检查文件夹属性以确定它是否是收件箱、发件箱、草稿、已发送项目等。

      【讨论】:

      • 但是,如果用户(或邮件过滤规则)已经将邮件移动到一些通用文件夹(例如,项目 XYZ 的文件夹),其中包含传入和传出电子邮件,该怎么办?在这种情况下,传入/传出将是特定于电子邮件而不是文件夹的属性。好主意,但我没想到:)。
      • 这是一个非常好的问题。我没有一个上帝的答案。
      猜你喜欢
      • 2019-01-24
      • 2020-05-17
      • 2018-09-03
      • 1970-01-01
      • 2016-02-21
      • 1970-01-01
      • 2020-06-08
      • 2016-02-29
      • 2020-12-10
      相关资源
      最近更新 更多