使用Outlook VBA提高从Excel附件复制的速度

发布于 2025-01-26 11:51:24 字数 9378 浏览 1 评论 0原文

在过去的几年中,我们收到了数千封电子邮件,直到现在直到现在,我都想将其合并到一个文件中。

Outlook收件箱有38.000个未读电子邮件。

每个电子邮件都是从同一地址发送的,并包含两个名为“ ChannelName-Yyyy-Mm-DD-TagesReport.csv”和“ ChannelName-yyyy-yyyy-mm-dd-tageskategorien.csv”的文件。

我只需要“ TagesKategorien”文件。

所有文件都具有相同的结构,LINE1中的标题和第2行中的数据将“;”分开。 :

datum; pi;访问; uc tag; usetime标签; pi laufende woche;访问laufende
Woche; Pi Laufender Monat;访问Laufender Monat

我有工作代码,但很慢(每封电子邮件9秒)。
它通过非默认邮箱进行查看,将附件保存到本地文件夹中,并根据某些条件将第二行复制到另一个工作簿中。

如果不是为此做VBA,请告诉我。

当我将邮件项目限制到一个月的时间范围时,它通常会陷入困境或表现很奇怪(仅在某些时间内进行一些例程)。

代码的第一部分逐一访问电子邮件,并调用两个子例程:

Option Explicit

Sub SearchEmails()

Dim oINS As NameSpace
Dim FolderInbox As MAPIFolder
Dim filtered_items As Items
Dim olMail As MailItem
Dim strFilter As String
Dim olRecip As Recipient

Set oINS = GetNamespace("MAPI")
Set FolderInbox = oINS.Folders("Onlinearchiv - [email protected]")
Set FolderInbox = FolderInbox.Folders("Posteingang")

strFilter = "[ReceivedTime]>'" & Format(Date - 10, "DDDDD HH:NN") & "'"

Set filtered_items = FolderInbox.Items.Restrict(strFilter)

If filtered_items.Count = 0 Then
    GoTo empty_objects
End If

For Each olMail In filtered_items
    Call SaveTagesreport.saveAttachtoDisk(olMail)
    Call mergeReport.Merge_oewaReport(olMail)
Next olMail

empty_objects:
    Set FolderInbox = Nothing
    Set oINS = Nothing

End Sub

CALL SAVETAGESREPORT.SAVEATTACHTOCHTODISK(OLMAIL)将两个附件文件之一(取决于名称)保存到本地文件夹中。有人告诉我,这是需要的,因为我们只能在保存文件时复制一行。最初,我想直接访问它而无需保存。

Option Explicit
Function FileExists(FilePath As String) As Boolean
    Dim TestStr As String

    TestStr = ""
    On Error Resume Next
    TestStr = Dir(FilePath)
    On Error GoTo 0
    If TestStr = "" Then
        FileExists = False
    Else
        FileExists = True
    End If
End Function

Public Sub saveAttachtoDisk(itm As Outlook.MailItem)

Dim objAtt As Outlook.Attachment
Dim x As Long
Dim saveFolder As String
Dim Name As String

saveFolder = "Mypath/mylocalfolder"

For Each objAtt In itm.Attachments
    x = InStr(1, "tageskategorien.csv", objAtt.DisplayName)
    Name = objAtt.DisplayName
    If InStr(1, objAtt.DisplayName, "tageskategorien.csv", 1) = 0 Then
        If Not FileExists(saveFolder & objAtt.DisplayName) Then
            objAtt.SaveAsFile saveFolder & objAtt.DisplayName
        End If
    End If

    Set objAtt = Nothing

Next

End Sub

最后一部分打开.csv文件,如果尚未包含在alldata.xlsx文件中,则将数字写入alldata.xlsx文件。然后删除.csv文件,因为它仅包含我写入alldata.xlsx文件的一行,因此之后不需要。

Option Explicit

Sub Merge_oewaReport(itm As Outlook.MailItem)

'AllData.file Dims
Dim wb_path As String
Dim app_master As Excel.Application
Dim wb_master As Excel.Workbook
Dim ws_master As Excel.Worksheet

Dim ic_last As Integer
Dim ir_last As Integer
Dim ic_zeitr As Integer
Dim ic_date As Integer
Dim ic_ID As Integer

'EmailFile Dims
Dim objAtt As Outlook.Attachment
Dim FileName As String

Dim app_email As Excel.Application
Dim wb_email As Excel.Workbook
Dim ws_email As Excel.Worksheet

Dim ic_last2 As Integer
Dim ic_Date_e As Integer
Dim headerList() As String
Dim content() As String

'other dims
Dim Path As String
Dim datestr As Date
Dim datetemp As Date

Dim fID() As String
Dim fDay As String
Dim columnHeading As String
Dim i As Integer
Dim j As Integer
Dim Duplicate As Boolean

'Set up identifiers for AllData.file
Path = "mypath/mylocalfolder/"
wb_path = Path & "AllData.xlsx"
Set app_master = CreateObject("Excel.Application")
Set wb_master = app_master.Workbooks.Open(wb_path, ReadOnly:=False)
Set ws_master = wb_master.Sheets(1)

ic_last = ws_master.Cells.Find(What:="*", SearchDirection:=xlPrevious, SearchOrder:=xlByColumns).Column
ir_last = ws_master.Cells(ws_master.Rows.Count, 1).End(-4162).Row
ic_date = ws_master.Cells.Find(What:="DATUM", SearchDirection:=xlNext, SearchOrder:=xlByColumns).Column
ic_ID = ws_master.Cells.Find(What:="ID", SearchDirection:=xlNext, SearchOrder:=xlByColumns).Column
ic_zeitr = ws_master.Cells.Find(What:="Zeitraum", SearchDirection:=xlNext, SearchOrder:=xlByColumns).Column

For Each objAtt In itm.Attachments

    FileName = objAtt.DisplayName
    If InStr(1, FileName, "tageskategorien.csv", 1) = 0 Then
        Set app_email = CreateObject("Excel.Application")
        Set wb_email = app_email.Workbooks.Open(Path & FileName, True, True)
        Set ws_email = wb_email.Sheets(1)
        
        'find Date and Name in Emailfile
        fID = Split(FileName, " - ")
        headerList = Split(ws_email.Cells(1, 1), ";")
        content = Split(ws_email.Cells(2, 1), ";")
        For i = 0 To UBound(headerList)
            If headerList(i) = "DATUM" Then
                datestr = content(i)
                Exit For
            End If
        Next i
        
        'check ID of every line that matches the date, to find if new Data already exists
        Duplicate = False
        For i = 2 To ir_last
            datetemp = ws_master.Cells(i, ic_date)
            If ws_master.Cells(i, ic_date).Value = datestr Then
                If ws_master.Cells(i, ic_ID) = fID(0) Then
                    Duplicate = True
                    Exit For
                End If
            End If
        
        Next i
        
        'If the new data is not a duplicate, then fill in a new line
        If Not Duplicate = True Then
            j = ws_master.Cells.Find(What:="ID", SearchDirection:=xlNext, SearchOrder:=xlByColumns).Column
            ws_master.Cells(ir_last + 1, j) = fID(0)
            
            fID = Split(fID(1), "-")
            fDay = fID(UBound(fID))
            fDay = Split(fDay, ".")(0)
            If fDay = "tagesreport" Then
                ws_master.Cells(ir_last + 1, ic_zeitr) = "Tag"
            End If
            ir_last = ir_last + 1
            
            For i = 0 To UBound(headerList)
                columnHeading = headerList(i)
                
                Select Case columnHeading
                        
                    Case "DATUM"
                        ws_master.Cells(ir_last, ic_date) = datestr
                        
                        j = ws_master.Cells.Find(What:="Month", SearchDirection:=xlNext, SearchOrder:=xlByColumns).Column
                        ws_master.Cells(ir_last, j) = Month(datestr)
                        
                        j = ws_master.Cells.Find(What:="Year", SearchDirection:=xlNext, SearchOrder:=xlByColumns).Column
                        ws_master.Cells(ir_last, j) = Year(datestr)
                    
                    Case "PI"
                        j = ws_master.Cells.Find(What:="PI", SearchDirection:=xlNext, SearchOrder:=xlByColumns).Column
                        ws_master.Cells(ir_last, j) = content(i)
                        
                    Case "Visit"
                        j = ws_master.Cells.Find(What:="Visit", SearchDirection:=xlNext, SearchOrder:=xlByColumns).Column
                        ws_master.Cells(ir_last, j) = content(i)
                        
                    Case "UC Tag"
                        j = ws_master.Cells.Find(What:="UC Tag", SearchDirection:=xlNext, SearchOrder:=xlByColumns).Column
                        ws_master.Cells(ir_last, j) = content(i)
                        
                    Case "Usetime Tag"
                        j = ws_master.Cells.Find(What:="Usetime Tag", SearchDirection:=xlNext, SearchOrder:=xlByColumns).Column
                        ws_master.Cells(ir_last, j) = content(i)
                        
                    Case "PI laufende Woche"
                        j = ws_master.Cells.Find(What:="PI laufende Woche", SearchDirection:=xlNext, SearchOrder:=xlByColumns).Column
                        ws_master.Cells(ir_last, j) = content(i)
                        
                    Case "Visit laufende Woche"
                        j = ws_master.Cells.Find(What:="Visit laufende Woche", SearchDirection:=xlNext, SearchOrder:=xlByColumns).Column
                        ws_master.Cells(ir_last, j) = content(i)
                        
                    Case "PI laufender Monat"
                        j = ws_master.Cells.Find(What:="PI laufender Monat", SearchDirection:=xlNext, SearchOrder:=xlByColumns).Column
                        ws_master.Cells(ir_last, j) = content(i)
                        
                    Case "Visit laufender Monat"
                        j = ws_master.Cells.Find(What:="Visit laufender Monat", SearchDirection:=xlNext, SearchOrder:=xlByColumns).Column
                        ws_master.Cells(ir_last, j) = content(i)
                        
                End Select
            Next i
            
        End If
    End If
    Set objAtt = Nothing

Next

wb_master.Close SaveChanges:=True

'Delete the temp file again
For Each objAtt In itm.Attachments
    If FileExists(Path & objAtt.DisplayName) Then
        ' First remove readonly attribute, if set
        SetAttr Path & objAtt.DisplayName, vbNormal
        ' Then delete the file
        Kill Path & objAtt.DisplayName
    End If
Next

End Sub

Over the past years we received thousands of emails with an attachment we didn't use until now, I would like to combine to one file.

The Outlook inbox has 38.000 unread emails.

Each email is sent from the same address and contains two files named "channelname-yyyy-mm-dd-tagesreport.csv" and "channelname-yyyy-mm-dd-tageskategorien.csv".

I only need the "tageskategorien" file.

All files have the same structure, a header in line1 and data in line 2 seperated by ";" :

DATUM;PI;Visit;UC Tag;Usetime Tag;PI laufende Woche;Visit laufende
Woche;PI laufender Monat;Visit laufender Monat

I have working code but it is slow (9 seconds per email).
It looks through the non-default Mailbox, saves the attachment to a local folder, and copies the second line to another workbook based on some criteria.

If VBA is not made for this let me know.

When I restrict the mail items to a time range of one month it often gets stuck or behaves weirdly (doing some routines only part of the time).

The first part of the code accesses the emails one by one and calls two subroutines:

Option Explicit

Sub SearchEmails()

Dim oINS As NameSpace
Dim FolderInbox As MAPIFolder
Dim filtered_items As Items
Dim olMail As MailItem
Dim strFilter As String
Dim olRecip As Recipient

Set oINS = GetNamespace("MAPI")
Set FolderInbox = oINS.Folders("Onlinearchiv - [email protected]")
Set FolderInbox = FolderInbox.Folders("Posteingang")

strFilter = "[ReceivedTime]>'" & Format(Date - 10, "DDDDD HH:NN") & "'"

Set filtered_items = FolderInbox.Items.Restrict(strFilter)

If filtered_items.Count = 0 Then
    GoTo empty_objects
End If

For Each olMail In filtered_items
    Call SaveTagesreport.saveAttachtoDisk(olMail)
    Call mergeReport.Merge_oewaReport(olMail)
Next olMail

empty_objects:
    Set FolderInbox = Nothing
    Set oINS = Nothing

End Sub

Call SaveTagesreport.saveAttachtoDisk(olMail) saves one of the two attached files (depending on the Name) to a local folder. I was told that this is needed as we can only copy a line if the file is saved. Originally I wanted to directly access it without saving.

Option Explicit
Function FileExists(FilePath As String) As Boolean
    Dim TestStr As String

    TestStr = ""
    On Error Resume Next
    TestStr = Dir(FilePath)
    On Error GoTo 0
    If TestStr = "" Then
        FileExists = False
    Else
        FileExists = True
    End If
End Function

Public Sub saveAttachtoDisk(itm As Outlook.MailItem)

Dim objAtt As Outlook.Attachment
Dim x As Long
Dim saveFolder As String
Dim Name As String

saveFolder = "Mypath/mylocalfolder"

For Each objAtt In itm.Attachments
    x = InStr(1, "tageskategorien.csv", objAtt.DisplayName)
    Name = objAtt.DisplayName
    If InStr(1, objAtt.DisplayName, "tageskategorien.csv", 1) = 0 Then
        If Not FileExists(saveFolder & objAtt.DisplayName) Then
            objAtt.SaveAsFile saveFolder & objAtt.DisplayName
        End If
    End If

    Set objAtt = Nothing

Next

End Sub

The last part opens the .csv file, and writes the numbers into the AllData.xlsx file, if they are not already included. Then the .csv file is deleted, because it only contains this one line that I write to the AllData.xlsx file, so it is not needed afterwards.

Option Explicit

Sub Merge_oewaReport(itm As Outlook.MailItem)

'AllData.file Dims
Dim wb_path As String
Dim app_master As Excel.Application
Dim wb_master As Excel.Workbook
Dim ws_master As Excel.Worksheet

Dim ic_last As Integer
Dim ir_last As Integer
Dim ic_zeitr As Integer
Dim ic_date As Integer
Dim ic_ID As Integer

'EmailFile Dims
Dim objAtt As Outlook.Attachment
Dim FileName As String

Dim app_email As Excel.Application
Dim wb_email As Excel.Workbook
Dim ws_email As Excel.Worksheet

Dim ic_last2 As Integer
Dim ic_Date_e As Integer
Dim headerList() As String
Dim content() As String

'other dims
Dim Path As String
Dim datestr As Date
Dim datetemp As Date

Dim fID() As String
Dim fDay As String
Dim columnHeading As String
Dim i As Integer
Dim j As Integer
Dim Duplicate As Boolean

'Set up identifiers for AllData.file
Path = "mypath/mylocalfolder/"
wb_path = Path & "AllData.xlsx"
Set app_master = CreateObject("Excel.Application")
Set wb_master = app_master.Workbooks.Open(wb_path, ReadOnly:=False)
Set ws_master = wb_master.Sheets(1)

ic_last = ws_master.Cells.Find(What:="*", SearchDirection:=xlPrevious, SearchOrder:=xlByColumns).Column
ir_last = ws_master.Cells(ws_master.Rows.Count, 1).End(-4162).Row
ic_date = ws_master.Cells.Find(What:="DATUM", SearchDirection:=xlNext, SearchOrder:=xlByColumns).Column
ic_ID = ws_master.Cells.Find(What:="ID", SearchDirection:=xlNext, SearchOrder:=xlByColumns).Column
ic_zeitr = ws_master.Cells.Find(What:="Zeitraum", SearchDirection:=xlNext, SearchOrder:=xlByColumns).Column

For Each objAtt In itm.Attachments

    FileName = objAtt.DisplayName
    If InStr(1, FileName, "tageskategorien.csv", 1) = 0 Then
        Set app_email = CreateObject("Excel.Application")
        Set wb_email = app_email.Workbooks.Open(Path & FileName, True, True)
        Set ws_email = wb_email.Sheets(1)
        
        'find Date and Name in Emailfile
        fID = Split(FileName, " - ")
        headerList = Split(ws_email.Cells(1, 1), ";")
        content = Split(ws_email.Cells(2, 1), ";")
        For i = 0 To UBound(headerList)
            If headerList(i) = "DATUM" Then
                datestr = content(i)
                Exit For
            End If
        Next i
        
        'check ID of every line that matches the date, to find if new Data already exists
        Duplicate = False
        For i = 2 To ir_last
            datetemp = ws_master.Cells(i, ic_date)
            If ws_master.Cells(i, ic_date).Value = datestr Then
                If ws_master.Cells(i, ic_ID) = fID(0) Then
                    Duplicate = True
                    Exit For
                End If
            End If
        
        Next i
        
        'If the new data is not a duplicate, then fill in a new line
        If Not Duplicate = True Then
            j = ws_master.Cells.Find(What:="ID", SearchDirection:=xlNext, SearchOrder:=xlByColumns).Column
            ws_master.Cells(ir_last + 1, j) = fID(0)
            
            fID = Split(fID(1), "-")
            fDay = fID(UBound(fID))
            fDay = Split(fDay, ".")(0)
            If fDay = "tagesreport" Then
                ws_master.Cells(ir_last + 1, ic_zeitr) = "Tag"
            End If
            ir_last = ir_last + 1
            
            For i = 0 To UBound(headerList)
                columnHeading = headerList(i)
                
                Select Case columnHeading
                        
                    Case "DATUM"
                        ws_master.Cells(ir_last, ic_date) = datestr
                        
                        j = ws_master.Cells.Find(What:="Month", SearchDirection:=xlNext, SearchOrder:=xlByColumns).Column
                        ws_master.Cells(ir_last, j) = Month(datestr)
                        
                        j = ws_master.Cells.Find(What:="Year", SearchDirection:=xlNext, SearchOrder:=xlByColumns).Column
                        ws_master.Cells(ir_last, j) = Year(datestr)
                    
                    Case "PI"
                        j = ws_master.Cells.Find(What:="PI", SearchDirection:=xlNext, SearchOrder:=xlByColumns).Column
                        ws_master.Cells(ir_last, j) = content(i)
                        
                    Case "Visit"
                        j = ws_master.Cells.Find(What:="Visit", SearchDirection:=xlNext, SearchOrder:=xlByColumns).Column
                        ws_master.Cells(ir_last, j) = content(i)
                        
                    Case "UC Tag"
                        j = ws_master.Cells.Find(What:="UC Tag", SearchDirection:=xlNext, SearchOrder:=xlByColumns).Column
                        ws_master.Cells(ir_last, j) = content(i)
                        
                    Case "Usetime Tag"
                        j = ws_master.Cells.Find(What:="Usetime Tag", SearchDirection:=xlNext, SearchOrder:=xlByColumns).Column
                        ws_master.Cells(ir_last, j) = content(i)
                        
                    Case "PI laufende Woche"
                        j = ws_master.Cells.Find(What:="PI laufende Woche", SearchDirection:=xlNext, SearchOrder:=xlByColumns).Column
                        ws_master.Cells(ir_last, j) = content(i)
                        
                    Case "Visit laufende Woche"
                        j = ws_master.Cells.Find(What:="Visit laufende Woche", SearchDirection:=xlNext, SearchOrder:=xlByColumns).Column
                        ws_master.Cells(ir_last, j) = content(i)
                        
                    Case "PI laufender Monat"
                        j = ws_master.Cells.Find(What:="PI laufender Monat", SearchDirection:=xlNext, SearchOrder:=xlByColumns).Column
                        ws_master.Cells(ir_last, j) = content(i)
                        
                    Case "Visit laufender Monat"
                        j = ws_master.Cells.Find(What:="Visit laufender Monat", SearchDirection:=xlNext, SearchOrder:=xlByColumns).Column
                        ws_master.Cells(ir_last, j) = content(i)
                        
                End Select
            Next i
            
        End If
    End If
    Set objAtt = Nothing

Next

wb_master.Close SaveChanges:=True

'Delete the temp file again
For Each objAtt In itm.Attachments
    If FileExists(Path & objAtt.DisplayName) Then
        ' First remove readonly attribute, if set
        SetAttr Path & objAtt.DisplayName, vbNormal
        ' Then delete the file
        Kill Path & objAtt.DisplayName
    End If
Next

End Sub

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

入画浅相思 2025-02-02 11:51:24

有几个方面可以改善代码的整体性能。如果您没有在多台计算机上部署解决方案的计划,则VBA是实施此类任务的有效方法。但是,如果您需要分发解决方案,建议您改用VSTO加载项,请参见练习:创建您的第一个vsto加载项以获取Outlook 以获取更多信息。

首先,我建议在附件存在上过滤项目,以便您可以向限制方法引入更多条件。这是一个示例搜索字符串,该字符串检查主题行和附件:

Filter = "@SQL=" & Chr(34) & "urn:schemas:httpmail:subject" & _
                   Chr(34) & " Like '%training%' AND " & _
                   Chr(34) & "urn:schemas:httpmail:hasattachment" & _
                   Chr(34) & "=1"

其次,我建议在处理Outlook项目时保持Excel应用程序打开。无需每次打开和关闭它。

第三,您可以尝试设置Excel的属性以提高性能,例如secredupdating和等。在最大化Excel/VBA自动化性能文章。

There are several aspects that could improve the overall performance of your code. VBA is a valid way for implementing such tasks if you don't have any plans for deploying the solution on multiple machines. But if you need to distribute your solution I'd recommend creating a VSTO add-in instead, see Walkthrough: Create your first VSTO Add-in for Outlook for more information.

First, I'd suggest filtering items on the attachments presence, so you can introduce one more condition to the Restrict method. Here is a sample search string which checks the Subject line and attachments:

Filter = "@SQL=" & Chr(34) & "urn:schemas:httpmail:subject" & _
                   Chr(34) & " Like '%training%' AND " & _
                   Chr(34) & "urn:schemas:httpmail:hasattachment" & _
                   Chr(34) & "=1"

Second, I'd recommend keeping the Excel application open while processing Outlook items. There is no need to open and close it each time.

Third, you can try to set up Excel's properties to increase performance such as ScreenUpdating and etc. Read more about them in the Maximizing Excel / VBA Automation Performance article.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文