VB.NET Outlook 项目中的 HTML 不正确。HTMLBody

VB.NET Incorrect HTML from Outlook Item .HTMLBody

提问人:sickboy 提问时间:7/6/2023 最后编辑:sickboy 更新时间:7/7/2023 访问量:132

问:

我正在尝试将我制作的 VBA 函数复制到 VB.NET 中。 它基本上得到一个邮件,然后它从它的HTMLBody中提取它的TABLE标签。 我的问题是函数给出了不同的输出。 VBA 返回标准 HTML 格式,包括所有标记,包括 TABLE。 VB中。NET的输出如下。

<!-- Converted from text/rtf format -->
<P><FONT SIZE=2>TEXT0,<BR>
<BR>
<BR>
INTRO:<BR>
<BR>
A. TEXT1<BR>
<BR>
B TEXT2<BR>
<BR>
C. TEXT3<BR>
<BR>
D. TEXT4<BR>
<BR>
E. TEXT5 &amp; TEXT6<BR>
<BR>
<BR>

相反,这是我想要的

<body lang=EN-US link=blue vlink=purple style='word-wrap:break-word'><div class=WordSection1><p><span style='font-family:Arial'>TEXT0<o:p></o:p></span></p>
<p><span style='font-family:Arial'><br>INTRO <o:p></o:p></span></p>
<p><span style='font-family:Arial'>A. TEXT1 <o:p></o:p></span></p>
<p><span style='font-family:Arial'>B. TEXT2 <o:p></o:p></span></p>
<p><span style='font-family:Arial'>C. TEXT3 <o:p></o:p></span></p>
<p><span style='font-family:Arial'>D. TEXT4 <o:p></o:p></span></p>
<p style='margin-bottom:12.0pt'><span style='font-family:Arial'>E. TEXT5

我已经尝试了所有的 BodyFormats,结果几乎相同,没有标准的 HTML。 两者中使用的引用是相同的。 在代码下方。

Function GetMailTable(Subject As String, daysAgo As Integer, ParamArray Keywords() As Object)
    Dim myOlApp As New Outlook.Application
    Dim objNamespace As Outlook.NameSpace = myOlApp.GetNamespace("MAPI")
    Dim objFolder As Outlook.MAPIFolder = objNamespace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox)
    Dim itm As Outlook.MailItem
    Dim Found As Boolean
    Dim strFilter As String
    Dim Subj As String = Subject
    Dim arrList As ArrayList = New ArrayList
    daysAgo = myDate.Subtract(previousBusinessDay(myDate, daysAgo)).TotalDays
    strFilter = "@SQL=" & Chr(34) & "urn:schemas:httpmail:subject" & Chr(34) & " like '%" & Subj & "%'"
    Dim filtereditemssubj As Object = objFolder.Items.Restrict(strFilter)
    Dim filteredItems As Object = filtereditemssubj.Restrict("[ReceivedTime]>'" & Format(myDate.AddDays(-daysAgo), "dd/MM/yyyy") + " 00:00" & "'")
    filteredItems = filteredItems.Restrict("[ReceivedTime]<'" & Format(myDate.AddDays(-daysAgo).AddDays(1), "dd/MM/yyyy") + " 00:00" & "'")
    Dim htmlDoc As New mshtml.HTMLDocument
    Dim tables As mshtml.DispHTMLElementCollection
    Dim Table As mshtml.HTMLTable
    If filteredItems.Count = 0 Then
        Found = False
    Else
        Found = True
        For Each itm In filteredItems
            htmlDoc.HTMLBody = itm.HTMLBody
            tables = htmlDoc.getElementsByTagName("table")
            For Each Table In tables
                arrList.Add(Table)
            Next Table
        Next itm
    End If
    myOlApp = Nothing
    Return arrList
End Function

您可以尝试复制它,在邮件正文中包含表示例。 有人有什么建议吗?

谢谢大家

编辑:我试图在Outlook中查看源代码,正确的输出是在VBA中获得的输出,我真的不明白为什么我在 VB.NET 中没有得到相同的结果。 谁能帮忙?

vb.net HTML 表格 Outlook MSHTML

评论

0赞 Joel Coehoorn 7/6/2023
fwiw,这些元素不是标准的 HTML。<o:p></o:p>

答:

0赞 11 revsJoel Coehoorn #1

社区维基,因为这可能无法完全解决问题(可能会给出相同的结果),但它也太长了,无法发表评论。下面的代码为现代 VB.Net 重写了一些东西。如果这仍然只是一个 Office 加载项,您可能无法使用所有这些语言功能,但某些更改(例如不使用 ArrayList 或匈牙利变量前缀)已成为超过 15 年的标准做法,并且从不需要或根本没有帮助 .Net 将项目设置为方法的末尾。Nothing

Function GetMailTable(Subject As String, daysAgo As Integer, ParamArray Keywords() As Object) As IEnumerable(Of mshtml.HTMLTable)
    Dim App As New Outlook.Application()
    Dim Mapi As Outlook.NameSpace = App.GetNamespace("MAPI")
    Dim Inbox As Outlook.MAPIFolder = Mapi.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox)

    Dim searchDate As DateTime = DateTime.Today.AddDays(-daysAgo) 
    Dim quote As String = Chr(34)
    ' Below line assumes "Option Infer On"
    Dim filteredItems = Inbox.Items.
                   Restrict($"@SQL={quote}urn:schemas:httpmail:subject{quote} like '%{Subject}%'").
                   Restrict($"[ReceivedTime]>'{searchDate:dd/MM/yyyy HH:mm}'")
   
    ' Needs "Imports System.Linq" at the top
    Return filteredItems.
        Select(Function(itm) New mshtml.HTMLDocument With {.HTMLBody = itm.HTMLBody}).
        SelectMany(Function(doc)  doc.getElementsByTagName("table")).
        Cast(Of mshtml.HTMLTable)()
End Function

此外,该参数从未被使用过。我只保留它,以防万一某处有代码调用该方法,如果未定义参数,该方法可能会中断。Keywords

当然,调用代码也必须针对新的返回类型进行调整。新结果可以与循环、Linq 运算符方法一起使用,也可以通过追加到函数调用作为列表使用。尽量避免最后一个。For Each.ToList()

最后,如果我看不到的类型没有正式实现正确的接口,您可能需要包含此方法(在单独的类或模块中):filteredItems

' Requires Option Strict Off, so the compiler will make the implied GetEnumerator() call :(
<Extension()> 
Public Shared Iterator Function AsEnumerable(Of T)(input As Object) As IEnumerable(Of T)
    For Each item As T In input.GetEnumerator()
        Yield item
    Next
End Function

然后语句的第一行如下所示:Return

Return filteredItems.AsEnumerable(Of Outlook.MailItem)().

我们知道将具有所需的方法,否则它将无法与原始代码中的循环一起使用。显式键入初始变量声明也可以避免这种情况,但如果您遇到这个问题,我认为这无济于事。filteredItemsGetEnumerator()For EachfilteredItems

评论

0赞 sickboy 7/6/2023
首先,谢谢你抽出时间,乔尔。其次,我试图用你的函数替换我的函数,但尽管添加了 Linq imports 语句,我在 '{.HTMLBody' - “成员 HTMLBody 无法在对象初始值设定项表达式中初始化,因为它不是字段或属性”。排在第三位的是,除了老式的方法和语法之外,我不明白我的函数在获取 HTML 消息时失败的地方,但这可能是因为您可能已经注意到,我仍然在从 VBA VB.NET。再次感谢
0赞 Dmitry Streblechenko 7/6/2023 #2

HTML 指示消息是纯文本或 RTF,而不是 HTML。很可能您的脚本正在访问与 VBA 访问的邮件不同的邮件。

尝试找到正确的消息,选择它,并使用集合而不是受限制的集合作为测试。Application.ActiveExplorer.SelectionItems

评论

0赞 sickboy 7/6/2023
如果你的意思是,如果它正在访问同一封电子邮件,它是,相同的文本,相同的收件人等。
0赞 Dmitry Streblechenko 7/6/2023
当您选择邮件,单击“项目”按钮,然后选择属性时,是否也会在OutlookSpy(dimastr.com/outspy)中看到该值?HTMLBody
0赞 sickboy 7/7/2023
我不明白如何将其添加到我的 Outlook 功能区,但我在 VBA 中看到的代码与我在邮件中右键单击并“查看源代码”时看到的代码相同。这是我真的看不出为什么我没有通过 VB.NET
0赞 Dmitry Streblechenko 7/8/2023
作为测试,您是否尝试过使用集合而不是?Application.ActiveExplorer.SelectionItems.Restrict
0赞 sickboy 7/10/2023
我设法按照您的建议获得了正确的格式,并将限制方法获得的项目添加到application.activeexplorer.addtoselection 方法中。当然这不是最有效的方法,所以我仍在试图弄清楚为什么我从同一封邮件中得到 2 个不同的 html 代码。你明白了吗?