【问题标题】:VBA Function always return TRUEVBA 函数总是返回 TRUE
【发布时间】:2018-01-11 07:30:45
【问题描述】:

我有这个函数循环遍历我的 Outlook 收件箱,如果有符合我设定条件的电子邮件,则返回 Boolean 作为最终结果。 即使条件错误,该函数也始终返回 true。我将.Sender 替换为xxxxxxx,它也返回True

GetSMTPAddressForRecipients 来自 MSDN 仅将 Sub 更改为 Function GetSMTPAddressForRecipients(mail As Outlook.MailItem)

我做错了什么?

Function CheckInbox(ByVal fpemail As Variant) As Boolean

CheckInbox = False

Dim objOutlook As Object, objNamespace As Object, objFolder As Object
Dim EmailCount As Integer
Set objOutlook = CreateObject("Outlook.Application")
Set objNamespace = objOutlook.GetNamespace("MAPI")

On Error Resume Next
Set objFolder = objNamespace.GetDefaultFolder(olFolderInbox)

Dim tdyDate As Date
Dim checkDate As Date
tdyDate = Format(Now(), "Short Date")
checkDate = DateAdd("d", -7, tdyDate) ' DateAdd(interval,number,date)

 Dim iCount As Integer, DateCount As Integer
 EmailCount = objFolder.Items.Count
 DateCount = 0

 ' loop the mailbox
 For iCount = 1 To EmailCount
 'check for sender.email type first, mine is 'EX'
 With objFolder.Items(iCount)
    If DateSerial(Year(.ReceivedTime), Month(.ReceivedTime), Day(.ReceivedTime)) >= checkDate And _
       DateSerial(Year(.ReceivedTime), Month(.ReceivedTime), Day(.ReceivedTime)) <= tdyDate And _
       .Subject Like "Test Subject" And _
       .Sender.GetExchangeUser.PrimarySmtpAddress = "xxxxxxx" And _
       GetSMTPAddressForRecipients(.To) = fpemail Then
       CheckInbox = True
       Exit Function
    Else
       CheckInbox = False
    End If
 End With
 Next iCount

Set objFolder = Nothing
Set objNamespace = Nothing
Set objOutlook = Nothing

End Function

【问题讨论】:

  • 暂时删除On Error Resume Next 并告诉我们您在If 语句中遇到的错误。 (如果If 有错误,则下一条语句是CheckInbox = True。)您甚至可能在If 之前出现错误,但您要让它继续运行,直到它遇到If,然后得到一个那里也有错误 - 可能是因为未设置对象或类似的东西。但在您删除错误屏蔽之前,我们无法轻易判断是什么。
  • @YowE3K 运行时错误 91 对象变量或未设置块变量,突出显示我的整个 IF 条件...
  • 我的 猜测objFolder.Items(iCount).Sender.GetExchangeUser.PrimarySmtpAddress 失败了。在If 之前添加一些额外的语句,说Dim xxxx As Object,然后是Set xxxx = .Sender,然后是Set xxxx = xxxx.GetExchangeUser,然后是Debug.Print xxxx.PrimarySmtpAddress。然后运行代码并查看它崩溃的那些。 (我对 Outlook VBA 了解的不够多,无法知道哪些对象无效,因此这将是一种简单的测试方法。)
  • Debug.Print xxxx.PrimarySmtpAddress 崩溃。
  • 我刚刚搜索了您可能使用的 GetSMTPAddressForRecipients 函数。我找到的代码以MailItem 作为参数。你有没有修改它来接受一个字符串?如果不是,那将导致 object required 错误。 (您可能需要使用GetSMTPAddressForRecipients(objFolder.Items(iCount)) = fpemail Then,但没有看到您的代码,我无法确定。)

标签: excel vba function outlook


【解决方案1】:

这些是您可能需要考虑的事情:

  1. 首先进行早期绑定以确保您正确访问属性。
    您如何做到这一点?只需在 Tools>References 下添加对 Outlook 库 的引用。

    Microsoft Outlook XX.0 对象库

  2. 现在,请确保您正在使用 Outlook MailItem 对象。您可以尝试在循环中插入检查。类似的东西:

    Dim objItem As Outlook.MailItem '/* add declaration to make use of intellisense */
    
    '/* backward loop, but starts with most recent email */
    For iCount = EmailCount To 1 Step -1 
        ' check for sender.email type first, mine is 'EX'
        If TypeOf objFolder.Items(iCount) Is MailItem Then
            Set objItem = objFolder.Items(iCount)
            With objItem
                '...rest of code here
    
            End With
        End if
    Next
    

    我不知道,但是您先发表了评论以检查类型,但从未见过执行此操作的代码,因此我检查了项目的类型。

  3. 您不需要使用DateSerial 和所有其他函数来比较日期。你可以简单地:

    If Format(.ReceivedTime, "Short Date") >= checkdate Then
    
  4. 我不知道您是否正在测试 Subject 中的字符串 Test Subject 或等于它。首先,我认为应该是:

    And .Subject Like "*Test Subject*"
    

    Above 返回所有带有 Test Subject 的主题。或者更好:

    And Instr(.Subject, "Test Subject") <> 0 
    

    如果您试图让MailItemSubject 等于测试主题,那么只需使用:

    And .Subject = "Test Subject"
    
  5. 确保您确实从中检索到某些内容(应该是电子邮件地址)。

    .Sender.GetExchangeUser.PrimarySmtpAddress
    
  6. GetSMTPAddressForRecipients 过程需要 MailItem,但您提供了 MailItem To property(您说您按原样使用它,只是将其转换为函数)。另请注意,该过程将使MailItem 中的所有收件人都被测试。为什么首先需要 SMTP 地址?我建议你只使用名称?类似的东西:

    And Instr(.To, "John Doe") <> 0 
    

    其中 John Doe 是收件人指定的名称。


重构你的函数:

Function CheckInbox(ByVal fpemail As String) As Boolean

    Dim objOutlook As Outlook.Application 'As Object
    Dim objNamespace As Outlook.Namespace 'As Object
    Dim objFolder As Outlook.Folder 'As Object
    '/* added declarations */
    Dim objItem As Outlook.MailItem
    Dim objRecip As Outlook.Recipient
    Dim EmailCount As Integer

    '/* I assumed Outlook is already running, revert to your code other wise */    
    Set objOutlook = GetObject(, "Outlook.Application")
    Set objNamespace = objOutlook.GetNamespace("MAPI")

    Set objFolder = objNamespace.GetDefaultFolder(olFolderInbox)

    Dim tdyDate As Date
    Dim checkDate As Date
    tdyDate = Format(Now(), "Short Date")
    checkDate = DateAdd("d", -7, tdyDate)

    Dim iCount As Integer, DateCount As Integer
    EmailCount = objFolder.Items.Count
    DateCount = 0

    '/* loop the mailbox, same as your code */
    For iCount = EmailCount To 1 Step -1
        '/* Check for the type */
        If TypeOf objFolder.Items(iCount) Is MailItem Then
            '/* Set the object, get intellisense */
            Set objItem = objFolder.Items(iCount)
            With objItem
               If Format(.ReceivedTime, "Short Date") >= checkDate _
               And Format(.ReceivedTime, "Short Date") <= tdyDate _
               And InStr(.Subject, "Test Subject") <> 0 _
               And .Sender.GetExchangeUser.PrimarySmtpAddress = "xxxxxxx" _
               And EvaluateRecipientSMTP(.Recipients, fpemail) Then
               '/* we use below function here */ 
                  CheckInbox = True
                  Exit Function
               Else
                  CheckInbox = False
               End If
            End With
        End If
    Next iCount

    Set objFolder = Nothing
    Set objNamespace = Nothing
    Set objOutlook = Nothing

End Function

Edit1:额外功能

Private Function EvaluateRecipientSMTP(objAllRecip As Outlook.Recipients, _
                                       fpemail As String) As Boolean

    Dim objRecip As Outlook.Recipient
    Dim objExUser As Outlook.ExchangeUser
    Dim objExDisUser As Outlook.ExchangeDistributionList

    For Each objRecip In objAllRecip
        Select Case objRecip.AddressEntry.AddressEntryUserType
        '/* OlAddressEntryUserType.olExchangeUserAddressEntry or
        'OlAddressEntryUserType.olOutlookContactAddressEntry */
        Case 0, 10
            Set objExUser = objRecip.AddressEntry.GetExchangeUser
            If Not objExUser Is Nothing Then
                If objExUser.PrimarySmtpAddress = fpemail Then
                    EvaluateRecipientSMTP = True
                    Exit For
                End If
            End If
        '/* OlAddressEntryUserType.olExchangeDistributionListAddressEntry */
        Case 1
            Set objExDisUser = objRecip.AddressEntry.GetExchangeDistributionList
            If Not objExDisUser Is Nothing Then
                If objExDisUser.PrimarySmtpAddress = fpemail Then
                    EvaluateRecipientSMTP = True
                    Exit For
                End If
            End If
        '/* recipient not part of your exchange server */
        Case Else
        '/* Do nothing */
        End Select
    Next
End Function

重要:

  1. 上面的fpemailString 类型,这是您要查找的收件人姓名。
  2. 对于上述第 5 项,您可能需要考虑 YowE3K's 建议。
  3. 不要忘记设置参考。

【讨论】:

  • 感谢超级清晰的解释!澄清一下:第 4 点,我正在尝试获取完整的主题,第 5 点,我收到了全名和电子邮件地址。第 6 点,我使用 email 是因为 email 值来自 Cell 的值。
  • @Max 首先,不要立即更改接受的答案。它可能是也可能不是您正在寻找的那个。顺便说一句,在第 4 点和第 5 点上,我认为已经解决了(您可以按原样使用代码)。但是,对于第 6 点,我们可能需要使用另一个函数对其进行一些调整。但这仅适用于您邮件服务器上的收件人,而不适用于来自外部的收件人。
  • 重新考虑第 3 点 - 你甚至不需要 Format - .ReceivedTimecheckDate 都是日期,所以你可以比较两者。 (我实际上预计Format 会导致问题,因为然后将StringDate 进行比较,认为VBA 会将Date 转换为String 并给"01/05/2018" &gt;= "12/30/2017" 带来问题,这将是@ 987654351@,但 VBA 实际上是将String 转换为Date 并因此执行CDate(Format(.ReceivedTime, "Short Date")) &gt;= checkDate。)
  • @Max 您可以使用以下方法将其更改为不区分大小写的测试:If StrComp(objExUser.PrimarySmtpAddress, fpemail, vbTextCompare) = 0 Then 或经典方法:If LCase(objExUser.PrimarySmtpAddress) = LCase(fpemail) Then。两者都是不区分大小写的比较。
  • @Max 没有机会,特别是如果您有很多收件人。已经将其设计为在找到匹配项后退出。您必须以任何一种方式循环。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-11-23
  • 1970-01-01
  • 2020-10-30
  • 1970-01-01
  • 1970-01-01
  • 2013-08-06
  • 2017-05-10
相关资源
最近更新 更多