VisualBasic Mails automatisch bearbeiten Performance

scue

Cadet 4th Year
Registriert
Aug. 2008
Beiträge
68
Hallo,

ich habe ein Makro geschrieben, was meine Mails automatisch verarbeitet, sobald ein bestimmtes Wort im Betreff auftaucht. Dabei wird die angehängte Excel geöffnet und der Inhalt kopiert. Nur leider scheint es ein Performance Problem zu geben, da er erst nach mehrfachen Durchlauf auch wirklich alle Mails bearbeitet hat. Hat jemand eine Ahnung, wie man das Programm flüssiger zum Laufen bekommt, so dass gleich alle Mails berücksichtigt werden? Oder hat es VBA einfach so ansich, dass es mit größeren Datenmengen unsauber wird?

Hier mal mein Code:
PHP:
For Each mailItem In objFolder.Items

    If TypeName(mailItem) = "MailItem" Then
    
        eingangsNachrichtDatumUhrzeit = Split(mailItem.ReceivedTime, " ")
        eingangsNachrichtDatum = Split(eingangsNachrichtDatumUhrzeit(0), ".")
        eingangsNachrichtUhrzeit = Split(eingangsNachrichtDatumUhrzeit(1), ":")
        
        'Prüfen ob Mail nicht außerhalb des Zeitraumes der letzten Aktualisierung liegt
        'LetzteAktualiseriungJahr < Empfangsjahr --> Durchlaufen
        'LetzteaktualisierungJahr = Empfangsjahr & LetzteAktualisierungMonat < Empfangsmonat --> Durchlaufen
        'LetzteAktualisierungJahr = Empfangsjahr & LetzteAktualisierungMonat = Empfangsmonat & LetzteAktualisierungTag < Empfangstag --> Durchlaufen
        'LetzteAktualisierungJahr = Empfangsjahr & LetzteAktualisierungMonat = Empfangsmonat & LetzteAktualisierungTag = Empfangstag & LetzteAktualisierungsstunde < Empfangsstunde --> Durchlaufen
        'LetzteAktualisierungJahr = Empfangsjahr & LetzteAktualisierungMonat = Empfangsmonat & LetzteAktualisierungTag = Empfangstag & LetzteAktualisierungsstunde = Empfangsstunde & LetzteAktualiserungsminute = Empfangsminute --> Durchlaufen
        If ( _
            (letzteaktualisierungdatum(2) < eingangsNachrichtDatum(2)) Or _
            (letzteaktualisierungdatum(2) = eingangsNachrichtDatum(2) And letzteaktualisierungdatum(1) < eingangsNachrichtDatum(1)) Or _
            (letzteaktualisierungdatum(2) = eingangsNachrichtDatum(2) And letzteaktualisierungdatum(1) = eingangsNachrichtDatum(1) And letzteaktualisierungdatum(0) < eingangsNachrichtDatum(0)) Or _
            (letzteaktualisierungdatum(2) = eingangsNachrichtDatum(2) And letzteaktualisierungdatum(1) = eingangsNachrichtDatum(1) And letzteaktualisierungdatum(0) = eingangsNachrichtDatum(0) And letzteAktualisierungUhrzeit(0) < eingangsNachrichtUhrzeit(0)) Or _
            (letzteaktualisierungdatum(2) = eingangsNachrichtDatum(2) And letzteaktualisierungdatum(1) = eingangsNachrichtDatum(1) And letzteaktualisierungdatum(0) = eingangsNachrichtDatum(0) And letzteAktualisierungUhrzeit(0) = eingangsNachrichtUhrzeit(0) And letzteAktualisierungUhrzeit(1) < eingangsNachrichtUhrzeit(1)) _
            ) Then

            'Betreff der Mail erfassen
            Betreff = mailItem.Subject
                   
            'Wenn Betreff für die Datei zutrifft
            If (InStr(1, Betreff, sachverhalt, vbTextCompare)) <> 0 Then
                
                'Betreff aufsplitten und Datum, zu der das File gehört herausfiltern
                betreff_Teile = Split(Betreff, "_")
                datumDerDatei = betreff_Teile(1)
                
                'Überprüfe, ob es die aktuellste Datei zum dazugehörigen Tag ist
                Workbooks(zieldatei).Sheets(sheetNameArchiv).Activate
                i = 2
                
                'Prüfen, ob überhaupt schon ein Tag angelegt worden ist
                    If (Cells(i, 1).Value <> "") Then
                        
                        status = True
                        
                        'Durchgehen der Datumsspalte im Archiv, prüfen ob der Tag, zu dem die Mail gehört bereits vorhanden
                        Do While (Cells(i, 1).Value <> "")
                        
                            'Wenn Tag bereits vorhanden
                            If (Cells(i, 1).Value = datumDerDatei) Then
                                
                                'Prüfen ob die aktuell ausgewählte Mail nicht bereits veraltet ist
                                If (mailItem.ReceivedTime > Cells(i, 2)) Then
                                    
                                    'Falls Tag bereits vorhanden, und die aktuell ausgewählte Mail neuer ist als der bisherige
                                    'Datenbestand, Datum der Mail im Archiv eintragen und einlesen des Anhanges starten
                                    Cells(i, 2).Value = mailItem.ReceivedTime
                                'Aktuellerer Eintrag zu diesem Datum bereits vorhanden
                                Else
                                    mailItem.Move objFolderArchiv
                                    GoTo naechsteMail
                                End If
                                                            
                                Exit Do
                                
                            Else
                                status = False
                            
                            End If
                            
                            i = i + 1
                            
                        Loop
                        
                        'Tag ist noch nicht, anlegen des Tages und Starten des Einlesens des Anhangs
                        If (status = False) Then
                            Cells(i, 1).Value = datumDerDatei
                            Cells(i, 2).Value = mailItem.ReceivedTime
                        End If
               
                    'Falls nein, anlegen des Tages im Archiv und des aktuellen Datum, starten des Einlesens des Datums
                    Else
                        Cells(i, 1).Value = datumDerDatei
                        Cells(i, 2).Value = mailItem.ReceivedTime
                    End If
                    
                    'Zählen der anhänge der Mail
                    anzahl = mailItem.Attachments.Count
                    
                    For i = 1 To anzahl
                        'prüfen, ob es sich um eine CSV oder XLS/XLSX handelt
                        If (InStr(1, mailItem.Attachments.Item(i), ".csv", vbTextCompare) Or InStr(1, mailItem.Attachments.Item(i), ".xls", vbTextCompare) Or InStr(1, mailItem.Attachments.Item(i), ".xlsx", vbTextCompare)) <> 0 Then
                        
                            'speichert den Anhang zwischen im Temporären Ordner
                            
                             dateiname = mailItem.Attachments.Item(i).Filename
                             dateipfad = zwischenSpeicherVerzeichnis & "/" & mailItem.Attachments.Item(i).Filename
                             mailItem.Attachments.Item(i).SaveAsFile dateipfad
                            'Anhang bearbeiten
        
                        
                             'Starten von Excel und Aufruf der Datei
                             Workbooks.Open Filename:=zwischenSpeicherVerzeichnis & "/" & mailItem.Attachments.Item(i).Filename, Local:=True
                             Workbooks(dateiname).Sheets(1).Activate
                             anzahlReihen = Range("A1").CurrentRegion.Rows.Count
                             Range("A2:N" & anzahlReihen).Select
                             'Kopieren der Datensätze
                             Selection.Copy
                             
                             'Wechseln zur Zieldatei
                             Workbooks(zieldatei).Sheets(sheetNameUebersicht).Activate
                             
                             'Prüfen, ob aktuelle Datensätze zu diesem Datum vorhanden sind, falls ja, diese Löschen
                             i = 2
                             
                            Do While (Cells(i, 12).Value <> "")
                                datumInZelle = Cells(i, 12).Value
                                datumInZelleGeteilt = Split(datumInZelle, " ")
                                datumInZelleGeteiltTagesdatum = Split(datumInZelleGeteilt(0), ".")
                                datumFormatiert = datumInZelleGeteiltTagesdatum(0) & datumInZelleGeteiltTagesdatum(1) & datumInZelleGeteiltTagesdatum(2)
                                If (datumFormatiert = datumDerDatei) Then
                                    Rows(i & ":" & i).Select
                                    Selection.Delete Shift:=xlUp
                                Else
                                    i = i + 1
                                End If
                            Loop
                             
                             'Einfügen in Zieldatei
                             anzahlReihen = Range("A1").CurrentRegion.Rows.Count
                             Cells(anzahlReihen + 1, 1).Select
                             ActiveSheet.Paste
                             
                             'Zwischenspeicher Löschen und Workbook schließen
                             Application.CutCopyMode = False
                             Workbooks(dateiname).Close
                            
                             'Workbook löschen aus temporären Verzeichnis
                             Kill dateipfad
                             
                        End If
                    
                    Next i
                'Mail in das Archiv verschieben
                mailItem.Move objFolderArchiv
            End If
           
        End If
     
   End If
     
naechsteMail:

Next mailItem
 
Naja, was dauert sind deine ganzen If-Abfragen, überleg mal, wie oft der da teilweise eine Abfrage macht.
Das kann schon echt lang dauern. Vor allem wenn du dann da anfängst Dateien dazwischen zu kopieren in andere Verzeichnisse...

Also ich habs jetzt nur grob überflogen und auch nicht genau verstanden, was du da mit den ganzen Abfragen bezweckst, aber ich glaub das geht auch einfacher ;)

Sprich einfach wäre für mich:
Emails einlesen - Filter auf Emails anwenden - Anhänge auswerten

Da muss nichts zwischengespeichert werden...
Wenn man das schlau macht kann man das sogar parallelisieren und somit je nach verfügbaren Kernen um ein vielfaches beschleunigen...
Wie groß sind die Excell-Anhänge?
Ich würde nämlich auch soweit gehen, mir ein Objekt mit den Daten zu bauen und das im RAM zu halten um erst ganz zum Schluss Excell-Objekte daraus zu bauen/Excell zu öffnen.
 
Hi,

danke für die Antworten.


flo36 schrieb:
Außerdem hast du einen Fehler drin.

'LetzteAktualiseriungJahr < Empfangsjahr --> Durchlaufen

soll vermutlich

'LetzteAktualisierungJahr < Empfangsjahr --> Durchlaufen
Ja stimmt. Ist aber nur ein Kommentar, von daher hat er keinen Einfluss auf das Programm.

Erdmännchen schrieb:
Naja, was dauert sind deine ganzen If-Abfragen, überleg mal, wie oft der da teilweise eine Abfrage macht.
Das kann schon echt lang dauern. Vor allem wenn du dann da anfängst Dateien dazwischen zu kopieren in andere Verzeichnisse...

Mmh, also ich habe Anfangs auch nach einer Lösung ohne Zwischenzuspeichern gesucht. Leider hab ich keine gefunden. Kann man denn die Anhänge direkt aus Outlook öffnen?

Erdmännchen schrieb:
Also ich habs jetzt nur grob überflogen und auch nicht genau verstanden, was du da mit den ganzen Abfragen bezweckst, aber ich glaub das geht auch einfacher ;)

Sprich einfach wäre für mich:
Emails einlesen - Filter auf Emails anwenden - Anhänge auswerten
Ich bekomme mehrfach am Mails rein mit den ExcelListen. die Listen beziehen sich immer auf einen bestimmten Tag und können eine vorhergehende ersetzen. Beispiel:

14 Uhr Mail --> für 8.02.2011
15 Uhr Mail --> für 9.02.2011
16 Uhr Mail --> für 8.02.2011 (ersetzt damit die 14 Uhr Mail)
usw.

Deswegen auch die If Abfragen.

Erdmännchen schrieb:
Da muss nichts zwischengespeichert werden...
Wenn man das schlau macht kann man das sogar parallelisieren und somit je nach verfügbaren Kernen um ein vielfaches beschleunigen...

so tiefgreifend sind meine VBA Kentnisse leider nicht.


Erdmännchen schrieb:
Wie groß sind die Excell-Anhänge?
Ich würde nämlich auch soweit gehen, mir ein Objekt mit den Daten zu bauen und das im RAM zu halten um erst ganz zum Schluss Excell-Objekte daraus zu bauen/Excell zu öffnen.
Mhh sind relativ klein. 9KB.

Hast du ein Tutorial dafür, dass ich mir einmal anschauen kann?

Vielen Dank schon mal
 
Im ersten Schritt ist das ja nun scheinbar erfolgreich gewesen oder nicht?
Jetzt muss ja nur noch der Ordner auf neue Mails überwacht werden und selbige dann bearbeitet werden.

Wenn die Anhänge wirklich so klein sind, dann kannst du Inhalte wirklich doch komplett im RAM halten. Also ich meine damit, dass du die Anhänge nicht groß rumkopierst, sondern den Anhang öffnest (wird ja eine .csv-Datei sein oder? ) und die Datei ausließt und den Inhalt parst. In der CSV-Datei müsste es ein Trennzeichen geben für die Zellen, ist normaler weise ein ";", einfach mal mit dem Editor öffnen, dann siehst du die Struktur.
Die Listeneinträge würde ich in einem Objekt halten, weiß jetzt nicht, was du da hast, aber das sollte wirklich nicht schwer sein, da dann immer die neuen Daten anzuhängen.
Und wenn du dann die Mails abgearbeitet hast wird zum Schluss das Objekt wieder in eine CSV-Datei abgelegt und du kannst die schön mit Excell aufmachen.

Hatte erst befürchtet, dass das Tabellen mit mehreren hundert Einträgen sind...so aber muss man das wirklich nicht paralellisieren. Performance kostet dich eben dieses Datei-Kopieren und in zweiter Folge dann das ganze If-Abfragen.
Z.B. diese Abfrage nach dem Datum hab ich nicht ganz verstanden und ist bestimmt einfacher zu erledigen.
Erklär das mal genauer, was du da machen willst...
 
Zuletzt bearbeitet:
Erdmännchen schrieb:
Im ersten Schritt ist das ja nun scheinbar erfolgreich gewesen oder nicht?
Jetzt muss ja nur noch der Ordner auf neue Mails überwacht werden und selbige dann bearbeitet werden.
Mmh ja es war erfolgreich. Bis auf dass ich es mehrfach drüber laufen lassen habe am Anfang. Ein automatisches Überwachen ist aber nicht vorgesehen. Viel mehr soll der Benutzer auf Knopfdruck prüfen, ob es neue Mails gibt.

Erdmännchen schrieb:
Wenn die Anhänge wirklich so klein sind, dann kannst du Inhalte wirklich doch komplett im RAM halten. Also ich meine damit, dass du die Anhänge nicht groß rumkopierst, sondern den Anhang öffnest (wird ja eine .csv-Datei sein oder? ) und die Datei ausließt und den Inhalt parst. In der CSV-Datei müsste es ein Trennzeichen geben für die Zellen, ist normaler weise ein ";", einfach mal mit dem Editor öffnen, dann siehst du die Struktur.
Ja es sind .csv Datein. durch
PHP:
 Workbooks.Open Filename:=zwischenSpeicherVerzeichnis & "/" & mailItem.Attachments.Item(i).Filename, Local:=True
wird bewirkt, dass nach einem ; der Wert in eine neue Zelle geschrieben wird.

Erdmännchen schrieb:
Die Listeneinträge würde ich in einem Objekt halten, weiß jetzt nicht, was du da hast, aber das sollte wirklich nicht schwer sein, da dann immer die neuen Daten anzuhängen.
Und wenn du dann die Mails abgearbeitet hast wird zum Schluss das Objekt wieder in eine CSV-Datei abgelegt und du kannst die schön mit Excell aufmachen.
Du meinst also, zwischenspeichern in einem Objekt und nicht gleich eintragen. Das soll ich dann erst einmal zum Schluss machen? Derzeit öffne ich die Datei, selektiere den Inhalt, kopiere, wechsel die Datei und füge ein. und das datei für datei.
Erdmännchen schrieb:
Hatte erst befürchtet, dass das Tabellen mit mehreren hundert Einträgen sind...so aber muss man das wirklich nicht paralellisieren. Performance kostet dich eben dieses Datei-Kopieren und in zweiter Folge dann das ganze If-Abfragen.
Z.B. diese Abfrage nach dem Datum hab ich nicht ganz verstanden und ist bestimmt einfacher zu erledigen.
Erklär das mal genauer, was du da machen willst...
also in der zieldatei schreibe ich ein datum der letzten Aktualisierung rein. Eigentlich ist das überflüssig, da alle alten Mails sowieso immer verschoben werden. Aufgesplittet ist es deswegen, weil der Wert zum beispiel 03.02.2011 02:10 und 03.02.2010 02:10 nicht richtig miteinander vergleichbare waren wenn ich geschrieben habe 03.02.2011 02:10 < 03.02.2010 02:10, da ist er noch mehr übergangen.

Mmh wenn ich so darüber nachdenke, könnten die paar Zeilen wirklich weg. Am Anfang als ich es geschrieben hatte, gab es noch kein Archiv. Das hatte ich dann drum herum gebastelt. Ich teste es mal.
 
Ich dachte, du könntest komplett weg von Excell beim auslesen und das direkt mit nem FileStream einfach auslesen, was drinn steht...das müsste schon schneller gehen...
Ansonsten teste erst mal, es gibt auch die möglichkeit, das Datum aus dem String zu einem echten Datums-Typ zu machen und diese dann echt zu vergleichen.
 
Wenn immernoch nicht alle deine Emails bearbeitet werden, dann liegt das an deiner Abfrage zum Prüfen, ob die Email bearbeitet wird und nicht an irgendwelchen Datei-Operationen.

Wenn du mir mal genau erklären könntest, wie du prüfst, warum eine Email bearbeitet werden soll...
 
sagt mal kann es daran liegen, dass er bei for each durcheinander kommt, wenn ich innerhalb der for each etwas verschiebe?

ansonsten erläutere ich gleich mein problem
Ergänzung ()

Hi,

also Problem gelöst.

Für alle die es interessiert:
Man darf während dem Durchlauf einer for each keine elemente verschieben, da sonst das Programm durcheinander kommt. Wer das umgehen will, nutzt eine For-Schleife. Dazu vorher einfach die Elemente zählen und dann ein Inkrement hochzählen. Wenn nun ein Element verschoben wird, sowohl das Inkrement um eins verringern, als auch die Gesamtanzahl. et Voila, es funktioniert.

Thx nochmal
 
ah du meinst, dass du während der Schleife die Elemente in ihrer Reihenfolge neu angeordnet hast?
Ja, dass sollte man beachten ;)
Hab ich aber auch nicht gesehen muss ich zugeben, weil ich dauernd nur versucht hab, diese If-Bedingungen zu verstehen...
 
Zurück
Oben