Zur Hauptseite ... Zum Onlinearchiv ... Zum Abonnement ... Zum Newsletter ... Zu den Tools ... Zum Impressum ... Zum Login ...

Gedrucktes Heft

Diesen Beitrag finden Sie in Ausgabe 3/2015.

Unser Angebot für Sie!

Lesen Sie diesen Beitrag und 500 andere sofort im Onlinearchiv, und erhalten Sie alle zwei Monate brandheißes Access-Know-how auf 72 gedruckten Seiten! Plus attraktive Präsente, zum Beispiel das bald erscheinende Buch 'Access 2010 - Das Grundlagenbuch für Entwickler'!

Diesen Beitrag twittern

Outlook-Mails in Access archivieren

»Eine neue .pst-Datei ist wie ein neues Leben ...« – so fühlt es sich an, wenn man sich von einer Outlook-Installation voller Termine, Mails, Kontakte et cetera trennt und einfach einmal neu beginnt. Allerdings wird man einen Teil der Daten ohnehin übernehmen (die Kontakte), und zumindest die Mails sollte man sicherheitshalber noch eine Weile aufbewahren. Nur wo? Wenn Sie die Inhalte von Mails archivieren und für den gelegentlichen Zugriff bereithalten wollen, bietet sich natürlich der Einsatz einer Access-Datenbank an. Dieser Beitrag beleuchtet, wie Sie die Mails archivieren, ein weiterer beschäftigt sich mit der Suche nach und der Wiederherstellung von archivierten E-Mails.

Bevor man seine Outlook.pst in die ewigen Jagdgründe verabschiedet oder die enthaltenen E-Mails löscht, sollte man die Inhalte gegebenenfalls sichern. Was bietet sich da mehr an als eine Access-Datenbank – plus gegebenenfalls eines Ordners, in dem Sie alle Anlagen der E-Mails speichern?

Für den Access-Entwickler ist das eine gute Idee, denn damit kann er, ein entsprechendes Datenmodell vo­rausgesetzt, später auch die E-Mails bestimmter Kunden herausfiltern und etwa mit der Kundendatenbank verknüpfen. Voraussetzung hierfür ist allein, dass die Absender und die Empfänger in der Tabelle mit den E-Mail-Daten gespeichert werden.

Neben den Metadaten einer E-Mail wie Absender, Empfänger, Empfangsdatum, Betreff oder Inhalt wollen wir die Anlagen speichern. Außerdem soll vorsichtshalber auch die komplette Mail im Format .msg in einem Attachment-Feld des Datensatzes mit der E-Mail gespeichert werden. Dies stellt sicher, dass wir die E-Mail mit wenigen Zeilen Code erstens öffnen und zweitens in Outlook wiederherstellen können.

Platzproblemen vorbeugen

Wenn Sie neben den E-Mail-Metadaten auch noch die E-Mail selbst im .msg-Format in der Datenbank speichern wollen, ist diese vermutlich schnell genauso groß wie die .pst-Datei. Meine ist aktuell rund drei Gigabyte groß – so viel passt leider nicht in eine Access-Datenbank. Also bauen wir eine Option ein, die es erlaubt, eine Größenbegrenzung für die in der Datenbank zu speichernden Mails anzugeben. Dann werden alle Mails, deren Größe diesen Wert nicht übersteigt, in der Datenbank gespeichert, die übrigen landen in Dateiform in einem Verzeichnis, das sich im gleichen Ordner wie die Datenbank selbst befindet.

Anlagen speichern

Gegebenenfalls möchten Sie auch die Anlagen schnell zugreifbar machen. In diesem Fall speichern Sie auch diese in einem separaten Verzeichnis und tragen nur den Pfad zur jeweiligen Datei in eine weitere Tabelle der Datenbank ein.

Datenmodell

Damit steht das Datenmodell auch schon fest: Wir benötigen zunächst eine Tabelle namens tblMailItems, welche die Metadaten der eingelesenen E-Mails und gegebenenfalls die .msg-Dateien in einem Anlagefeld speichert.

Die zweite Tabelle heißt tblAnlagen. Da jede E-Mail keine, eine oder mehrere Anlagen enthalten kann, können wir deren Speicherort nicht einfach in einem Feld der Tabelle tblMailItems speichern, sondern müssen dafür eine per 1:n-Beziehung verknüpfte Tabelle anlegen. Diese soll tblAnlagen heißen und ist über das Fremdschlüsselfeld MailItemID mit der Tabelle tblMailItems verknüpft.

Schließlich benötigen wir noch eine dritte Tabelle namens tblOptionen, mit der wir die Einstellungen für den Import sichern.

Die Tabelle tblMailItems sieht im Entwurf wie in Bild 1 aus. Die Tabelle nimmt die wesentlichen Informationen der jeweiligen E-Mail auf. Da wir die E-Mail ja entweder in der Tabelle oder aber im Dateisystem noch als .msg-Datei speichern, die wir jederzeit wiederherstellen oder öffnen können, brauchen wir in der Tabelle nur die Daten zu speichern, nach denen wir die E-Mails durchsuchen wollen.

Die Tabelle tblMailItems in der Entwurfsansicht

Bild 1: Die Tabelle tblMailItems in der Entwurfsansicht

Die zweite Tabelle namens tblAnlagen speichert zu jeder E-Mail die Speicherorte für die Anlagen. Die Datensätze werden dabei über das Feld MailItemID mit der Tabelle tblMailItems verknüpft (s. Bild 2).

Die Tabelle tblAnlagen in der Entwurfsansicht

Bild 2: Die Tabelle tblAnlagen in der Entwurfsansicht

Fehlt noch die Tabelle tblOptionen. Diese sieht wie in Bild 3 aus. Die Bedeutung der einzelnen Felder wird gleich im Anschluss bei der Erläuterung des Einlesevorgangs deutlich werden.

Die Tabelle tblOptionen in der Entwurfsansicht

Bild 3: Die Tabelle tblOptionen in der Entwurfsansicht

Formular zur Steuerung des Einlesevorgangs

Das Formular frmMailimport steuert den Einlesevorgang. Das heißt, dass Sie damit die Optionen einstellen und den Vorgang starten können.

Das Formular sieht im Entwurf wie in Bild 4 aus.

Das Formular frmMailImport in der Entwurfsansicht

Bild 4: Das Formular frmMailImport in der Entwurfsansicht

Das Formular ist an die Tabelle tblOptionen gebunden. Das Textfeld txtVerzeichnis liefert den Wert des Feldes Verzeichnis. Diesen Wert können Sie manuell einstellen oder aber Sie verwenden die Schaltfläche mit den drei Punkten, um den dafür vorgesehenen Outlook-Dialog zu öffnen und den Mail-Ordner auszuwählen, dessen E-Mails eingelesen werden sollen.

Die Schaltfläche heißt cmdVerzeichnisWaehlen und ruft die folgende Prozedur auf:

Private Sub cmdVerzeichnisWaehlen_Click()
     Dim objOutlook As Outlook.Application
     Dim objMAPI As Outlook.NameSpace
     Dim objFolder As Outlook.Folder
     Set objOutlook = New Outlook.Application
     Set objMAPI = objOutlook.GetNamespace("MAPI")
     Set objFolder = objMAPI.PickFolder
     If Not objFolder Is Nothing Then
         Me!txtVerzeichnis = objFolder.FolderPath
     End If
End Sub

Dies zeigt den Dialog aus Bild 5 an. Damit wählt der Benutzer den Mail-Ordner aus, der als Basis für den Einlesevorgang dient. Den Pfad zu diesem Ordner ermittelt die Prozedur mit der Eigenschaft FolderPath des Folder-Objekts.

Dialog zum Auswählen des einzulesenden Mail-Ordners

Bild 5: Dialog zum Auswählen des einzulesenden Mail-Ordners

Für das Formular haben wir die Eigenschaften Datensatzmarkierer, Navigationsschaltflächen, Trennlinien und Bildlaufleisten auf den Wert Nein eingestellt.

Außerdem legen Sie für die Eigenschaft Zyklus den Wert Aktueller Datensatz fest. Der Benutzer kann dann nur den ersten Datensatz der Tabelle tblOptionen bearbeiten und nicht zu einem neuen Datensatz wechseln – mehr benötigt er ja auch nicht.

Damit erscheint das ausgewählte Outlook-Mail-Verzeichnis nun wie in Bild 6.

Das Formular frmMailImport in der Formularansicht

Bild 6: Das Formular frmMailImport in der Formularansicht

Die übrigen Einstellungen der Tabelle tblOptionen bildet das Formular wie in der Abbildung ab – also mit lauter Kontrollkästchen sowie einem Textfeld namens txtGroesse für die Eingabe der maximalen Größe, mit der eine E-Mail direkt in der Tabelle gespeichert werden soll.

Einlesevorgang starten

Ein Klick auf die Schaltfläche cmdImportStarten initialisiert den Einlesevorgang. Dies löst die folgende Prozedur aus:

Private Sub cmdImportStarten_Click()
     Dim lngAnzahl As Long
     SysCmd acSysCmdSetStatus, _
         "Einzulesende Mails werden gezählt"
     lngAnzahl = MailsZaehlen(Me!txtVerzeichnis, _
         Me!chkRekursiv)
     Import Me!txtVerzeichnis, lngAnzahl, _
         Me!txtGroesse, Me!chkNeuEinlesen, _
         Me!chkRekursiv, Me!chkVorhandeneLoeschen, _
         Me!chkAnlagenSpeichern
End Sub

Die Prozedur blendet zunächst einen Text in der Statusleiste von Access ein, der darauf hinweist, dass die Anwendung nun die Anzahl der einzulesenden E-Mails liest. Diesen Wert benötigen wir, um in der Statusleiste den Fortschritt abbilden zu können.

Dann startet die Prozedur den Zählvorgang durch den Aufruf der Funktion MailsZaehlen, der sie lediglich den Verweis auf den Outlook-Pfad sowie den Inhalt des Kon­trollkästchens chkRekursiv übergibt.

Einzulesende Mails zählen

Die Prozedur MailsZaehlen ermittelt zunächst mit der Funktion GetFolderByPath das Folder-Objekt von Outlook für den übergebenen Pfad, also beispielsweise \\Outlook\Posteingang. GetFolderByPath ist eine benutzerdefinierte Funktion, die das Folder-Objekt für den angegebenen Pfad zurückliefert (s. Modul mdlImport).

Die Count-Eigenschaft der Items-Auflistung dieses Folder-Objekts liefert die Anzahl der enthaltenen Elemente. Gegebenenfalls befinden sich dort auch Elemente mit einem anderen Typ als MailItem, aber dies sollte die Ausnahme sein und wir zählen diese einfach mit – sonst müssten wir hier noch eine weitere Prüfung einbauen, die Performance kostet.

Sollte der Benutzer im Formular frmMailimport die Option chkRekursiv gesetzt haben, ruft die Funktion eine weitere Funktion namens MailsZaehlenRek auf und übergibt dieser das Folder-Objekt sowie den Long-Wert lngAnzahl als Parameter. Letzterer ist bereits mit der aktuellen Anzahl gefüllt und soll um die Anzahl der Mails in den untergeordneten Verzeichnissen erhöht werden:

Private Function MailsZaehlen(strVerzeichnis As String, _
         bolRekursiv As Boolean) As Long
     Dim objFolder As Outlook.Folder
     Dim lngAnzahl As Long
     Set objFolder = GetFolderByPath(strVerzeichnis)
     lngAnzahl = objFolder.Items.Count
     If bolRekursiv Then
         MailsZaehlenRek objFolder, lngAnzahl
     End If
     MailsZaehlen = lngAnzahl
End Function

Die Funktion MailsZaehlenRek ist eine rekursiv definierte Funktion, die sich selbst aufruft. Dies geschieht so lange, bis keine untergeordneten Verzeichnisse mehr gefunden werden. Die Variable lngAnzahl wird durch alle Aufrufe geschleppt und jeweils um die Anzahl der E-Mails des aktuell in der For Each-Schleife durchlaufenen Folder-Objekts erhöht:

Private Function MailsZaehlenRek(objParent As _
         Outlook.Folder, lngAnzahl As Long)
     Dim objFolder As Outlook.Folder
     For Each objFolder In objParent.Folders
         lngAnzahl = lngAnzahl + objFolder.Items.Count
         MailsZaehlenRek objFolder, lngAnzahl
     Next objFolder
End Function

Auf diese Weise ermittelt die Funktion MailsZaehlen die Gesamtzahl der E-Mails und liefert diese als Funktionswert an die aufrufende Prozedur cmdImportStarten zurück.

Die Import-Routine

Die Prozedur ruft dann die Routine Import auf und übergibt dieser die Werte aller gebundenen Felder des Formulars frmMailimport (s. Listing 1).

Public Sub Import(strVerzeichnis As String, lngAnzahl As Long, lngSize As Long, bolNeuEinlesen As Boolean, _
         bolRekursiv As Boolean, bolVorhandeneLoeschen As Boolean, bolAnlagenSpeichern As Boolean)
     Dim objFolder As Outlook.Folder
     Dim db As DAO.Database
     Dim lngAnzahlEingelesen As Long
     Set objFolder = GetFolderByPath(strVerzeichnis)
     If Not objFolder Is Nothing Then
         Set db = CurrentDb
         If bolVorhandeneLoeschen Then
             SysCmd acSysCmdSetStatus, "Vorhandene Daten werden gelöscht"
             db.Execute "DELETE FROM tblMailItems", dbFailOnError
             SysCmd acSysCmdSetStatus, "Anlagenverzeichnis wird gelöscht"
             VerzeichnisLoeschen CurrentProject.Path & "\Anlagen"
         End If
         lngAnzahlEingelesen = objFolder.Items.Count
         MailsEinlesen objFolder, db, lngSize, bolNeuEinlesen, bolAnlagenSpeichern
         SysCmd acSysCmdSetStatus, lngAnzahlEingelesen & "/" & lngAnzahl
         If bolRekursiv Then
             UnterordnerEinlesen objFolder, db, lngAnzahl, lngAnzahlEingelesen, lngSize, bolNeuEinlesen, _
                 bolAnlagenSpeichern
         End If
         SysCmd acSysCmdClearStatus
     End If
End Sub

Listing 1: Die Prozedur Import

Die Prozedur ermittelt zunächst das Folder-Objekt für das Startverzeichnis in Outlook – dies wiederum mit der Funktion GetFolderByPath –, und speichert es in der Variablen objFolder. Sollte objFolder den Wert Nothing enthalten, wurde das Verzeichnis nicht gefunden und die Prozedur beendet.

Anderenfalls füllt die Prozedur die Variable db mit einem Verweis auf das aktuelle Database-Objekt. Danach prüft die Prozedur, ob vorhandene E-Mails gelöscht werden sollen. Ist dies der Fall, erscheint zunächst eine neue Statusmeldung unten links im Access-Fenster, dann ruft die Prozedur die DELETE-Anweisung zum Löschen des Inhalts der Tabelle tblMailItems auf. Wenn Sie gerade testweise ein paar hundert Megabyte E-Mails eingelesen haben und diese wieder löschen wollen, kann dies übrigens ein paar Augenblicke dauern.

Danach leert die Prozedur das Verzeichnis, in das gegebenenfalls die Anlagen der E-Mails gespeichert wurden. Dies erledigt die Prozedur VerzeichnisLoeschen, die als Parameter den Namen des Verzeichnisses der aktuellen Datenbank mit dem Unterverzeichnis Anlagen erhält.

Diese Prozedur verwendet das FileSystemObject, um zunächst das Verzeichnis zu ermitteln und mit einem Objekt des Typs Folder zu referenzieren. Dann löscht es dieses Objekt:

Public Sub VerzeichnisLoeschen(strVerzeichnis As String)
     Dim objFSO As Object
     Dim objFolder As Object
     Set objFSO = CreateObject( _
         "Scripting.FileSystemObject")
     On Error Resume Next
     Set objFolder = objFSO.GetFolder(strVerzeichnis)
     objFolder.Delete
     On Error GoTo 0
     Set objFolder = Nothing
     Set objFSO = Nothing
End Sub

Da wir nur dieses eine Mal auf die Bibliothek zugreifen, erstellen wir nicht extra einen Verweis, sondern verwenden Late Binding, um auf die enthaltenen Objekte und Methoden zuzugreifen.

Anschließend setzt die Prozedur Import das Einlesen der E-Mails fort. Sie ermittelt die Anzahl der E-Mails des aktuellen Verzeichnisses und trägt diese in die Variable lngAnzahlEingelesen ein. Diese wird uns noch länger begleiten und jeweils um die Anzahl der eingelesenen E-Mails auch der Unterformulare ergänzt.

Damit folgt der Aufruf der Prozedur MailsEinlesen, welche die E-Mails des Ordners einliest – mehr dazu weiter unten. Das Ergebnis ist, dass die E-Mails des mit dem Objekt objFolder übergebenen Outlook-Verzeichnisses eingelesen wurden.

Anschließend aktualisiert die Prozedur die Statusanzeige, damit der Benutzer erfährt, wie viele E-Mails mittlerweile eingelesen wurden.

Dann kümmert sich die Prozedur um die Unterformulare – aber nur, wenn der Benutzer den Wert des Kontrollkästchens chkRekursiv auf True eingestellt hat. Ist dies der Fall, hat auch bolRekursiv den Wert True und die folgende Anweisung wird ausgeführt. Dies erledigt die Prozedur UnterordnerEinlesen, welche wiederum den Verweis auf den aktuellen Ordner und einige weitere Informationen per Parameter erhält.

Auch diese Prozedur sehen wir uns weiter unten an.

Zu guter Letzt leert die Prozedur die Statusanzeige von Access.

Mails einlesen

Das Einlesen erfolgt in zwei Schritten: Die erste Prozedur namens MailsEinlesen durchläuft alle E-Mails eines Ordners, die zweite namens MailEinlesen liest dann tatsächlich die Daten einer jeden E-Mail in die Datenbank beziehungsweise das Dateisystem ein (s. Listing 2).

Public Sub MailsEinlesen(objFolder As Outlook.Folder, db As DAO.Database, lngSize As Long, bolNeuEinlesen As Boolean, _
         bolAnlagenSpeichern As Boolean)
     Dim objItem As Object
     Dim objMailItem As Outlook.MailItem
     For Each objItem In objFolder.Items
         If TypeName(objItem) = "MailItem" Then
             MailEinlesen objItem, objFolder.FolderPath, db, lngSize, bolNeuEinlesen, bolAnlagenSpeichern
         End If
     Next objItem
End Sub

Listing 2: Die Prozedur MailsEinlesen

Die Prozedur MailsEinlesen erwartet als Parameter unter anderem den Outlook-Ordner, dessen E-Mails eingelesen werden sollen.

Außerdem landen dort ein Verweis auf das aktuelle Database-Objekt sowie auf die maximale Größe der E-Mails (lngSize), der Parameter bolNeuEinlesen, der darauf hinweist, ob auch bereits eingelesene E-Mails erneut eingelesen werden sollen, und der Parameter bolAnlagenSpeichern, der festlegt, ob die Anlagen nochmals separat gespeichert werden sollen, auch wenn diese ja bereits in den .msg-Dateien in der Tabelle oder im Dateisystem gespeichert sind.

Die Prozedur durchläuft alle Elemente der Items-Auflistung des übergebenen Folder-Objekts und ruft für alle Elemente, deren Typ dem Wert MailItem entspricht, die Prozedur MailEinlesen auf. Diese erwartet prinzipiell die gleichen Parameter wie die Prozedur MailsEinlesen.

Eine E-Mail einlesen

Die Prozedur MailEinlesen liest genau die mit dem Parametern objMailItem übergebene E-Mail in die Datenbank ein – vorausgesetzt, diese wurde zuvor noch nicht eingelesen beziehungsweise es sollen ohnehin alle E-Mails nochmals eingelesen werden.

Der erste Teil der Prozedur (s. Listing 3) prüft zunächst, ob die Eigenschaft BillingInformation des MailItem-Objekts den Wert Saved enthält. Dies ist immer der Fall, wenn die Mail noch nicht eingelesen wurde.

Public Sub MailEinlesen(objMailItem As Outlook.MailItem, strFolderpath As String, db As DAO.Database, _
         lngSize As Long, bolNeuEinlesen As Boolean, bolAnlagenSpeichern As Boolean)
     Dim strAbsender As String
     Dim strEmpfaenger As String
     Dim strSQL As String
     Dim objRecipient As Outlook.Recipient
     Dim rst As DAO.Recordset
     Dim i As Integer
     Dim lngError As Long
     Dim lngMailItemID As Long
     With objMailItem
         If Not .BillingInformation = "saved" Or bolNeuEinlesen = True Then
             lngMailItemID = Nz(DLookup("MailItemID", "tblMailItems", "EntryID = '" & .EntryID & "'"), 0)
             If Not lngMailItemID = 0 Then
                 db.Execute "DELETE FROM tblMailItems WHERE EntryID = '" & .EntryID & "'", dbFailOnError
                 On Error Resume Next
                 Kill CurrentProject.Path & "\MSG\" & lngMailItemID & ".msg"
                 On Error GoTo 0
             End If
             strAbsender = .SenderEmailAddress
             For i = 1 To .Recipients.Count
                 Set objRecipient = .Recipients(i)
                 Select Case objRecipient.Type
                     Case olTo
                         strEmpfaenger = strEmpfaenger & ";" & objRecipient.Address
                     Case Else
                 End Select
             Next i
             strEmpfaenger = Mid(strEmpfaenger, 2)
             strSQL = "INSERT INTO tblMailItems(EntryID, Betreff, Body, HTMLBody, Absender, Empfaenger, Pfad, " _
                 & "Erhalten, Groesse) VALUES('" & .EntryID & "', '" & Replace(.Subject, "'", "''") & "', '" _
                 & Replace(.Body, "'", "''") & "', '" & Replace(.HTMLBody, "'", "''") & "', '" _
                 & Replace(strAbsender, "'", "''") & "', '" & Replace(strEmpfaenger, "'", "''") & "', '" _
                 & strFolderpath & "', " & ISODatum(.ReceivedTime) & ", " & .Size & ")"
             On Error Resume Next
             db.Execute strSQL, dbFailOnError
             lngError = Err.Number
             On Error GoTo 0

Listing 3: Die Prozedur MailEinlesen, Teil I

Wenn die Prozedur die Mail eingelesen hat, stellt sie diese Eigenschaft auf den Wert Saved ein. Wurde die Mail bereits gespeichert, kann es immer noch sein, dass der Benutzer das Kontrollkästchen chkNeuEinlesen aktiviert hat – in diesem Fall liest die Prozedur die Mail in jedem Fall neu ein.

Soll die E-Mail neu eingelesen werden, prüft die Prozedur noch, ob die Tabelle tblMailItems bereits einen Eintrag mit der EntryID der neu einzufügenden E-Mail enthält. Die EntryID ist die eindeutige Eigenschaft einer E-Mail unter Outlook. Dazu speichert die Prozedur den Primärschlüsselwert eines eventuell gefundenen Eintrags in der Variablen lngMailItemID. Ist lngMailItemID danach nicht 0, löscht die Prozedur den entsprechenden Datensatz per DELETE-Aktionsabfrage aus der Tabelle tblMailItems.

Außerdem löscht sie eventuell bereits für diese E-Mail angelegte .msg-Dateien aus dem Verzeichnis MSG. Danach liest sie den Absender aus der Eigenschaft SenderEmailAddress in die Variable strAbsender ein und durchläuft alle Empfänger über die Auflistung Recipients. Die Empfänger landen durch Semikola getrennt in der Variablen strEmpfaenger. Das führende Semikolon wird anschließend entfernt.

Schließlich stellt die Prozedur in der Variablen strSQL die SQL-Anweisung zusammen, die den neuen Datensatz mit den Daten der E-Mail in der Tabelle tblMailItems speichern soll. Dort ersetzt die Prozedur in einigen String-Elementen mit der Replace-Funktion einfache Hochkommata durch doppelte Hochkommata, damit diese keinen Fehler auslösen. Der Inhalt der Eigenschaft ReceivedTime wird mit der Funktion ISODatum so formatiert, dass er SQL-kompatibel ist. Die Prozedur führt dann die SQL-Anweisung aus, stellt aber sicher, dass ein eventueller Fehler behandelt wird.

Die Prüfung auf einen bestimmten Fehler erfolgt dann in der Fortsetzung der Prozedur in Listing 4. Der Fehler 3035 (Nicht genügend Systemressourcen) trat auf einem Testsystem mit Windows 7 und Access 2010 auf – die Ursache ist möglicherweise, dass ein zu großer Inhalt in eines der Memofelder eingefügt wurde.

             ...
             If lngError = 3035 Then
                 Set rst = db.OpenRecordset("SELECT * FROM tblMailItems WHERE 1 = 2", dbOpenDynaset)
                 rst.AddNew
                 rst!EntryID = .EntryID
                 rst!Betreff = .Subject
                 rst!Body = .Body
                 rst!HTMLBody = .HTMLBody
                 rst!Absender = strAbsender
                 rst!Empfaenger = strEmpfaenger
                 rst!Pfad = strFolderpath
                 rst!Erhalten = .ReceivedTime
                 rst!Groesse = .Size
                 lngMailItemID = rst!MailitemID
                 rst.Update
             Else
                 lngMailItemID = db.OpenRecordset("SELECT @@IDENTITY").Fields(0)
             End If
             If bolAnlagenSpeichern Then
                 AnlagenSpeichern objMailItem, db, strAbsender, lngMailItemID
             End If
             MailItemSpeichern objMailItem, db, lngMailItemID, lngSize
         End If
     End With
End Sub

Listing 4: Die Prozedur MailEinlesen, Teil II

Tatsache ist, dass wir die Daten in diesem Fall dennoch durch Einfügen per DAO (AddNew...Update) in der Tabelle speichern konnten.

Dies geschieht dann in den folgenden Anweisungen, die nur im Falle des Auftretens von Fehler 3035 ausgeführt werden. Sie legen einen neuen Datensatz mit AddNew im Recordset an, tragen die Werte aus den Eigenschaften der E-Mail ein und speichern den Datensatz mit der Update-Methode. In beiden Fällen speichert die Prozedur den Wert des Primärschlüsselfeldes des neuen Datensatzes in der Variablen lngMailItemID.

Wenn der Benutzer die Option chkAnlagenSpeichern im Formular frmMailimport aktiviert hat, ruft die Prozedur nun noch die Routine AnlagenSpeichern für diese E-Mail auf. Anschließend folgt noch ein Aufruf der Routine MailItem speichern, der sich um das Speichern der .msg-Datei entweder in der Datenbank oder im Dateisystem kümmert.

Speichern der Anlagen

Die Prozedur AnlagenSpeichern aus Listing 5 sichert, wenn der Benutzer dies aktiviert hat, die Anlagen einer E-Mail noch separat im Dateisystem. Die Prozedur prüft zunächst anhand der Eigenschaft Count der Attachments-Auflistung des MailItem-Objekts, ob die Mail überhaupt Anlagen enthält.

Public Sub AnlagenSpeichern(objMailItem As Outlook.MailItem, db As DAO.Database, strAbsender As String, _
         lngMailItemID As Long)
     Dim objAnlage As Outlook.Attachment
     Dim strPfad As String
     Dim strDateiname As String
     If objMailItem.Attachments.Count > 0 Then
         strPfad = CurrentProject.Path & "\Anlagen\" & strAbsender & "\" & lngMailItemID
         On Error Resume Next
         MkDir CurrentProject.Path & "\Anlagen\"
         MkDir CurrentProject.Path & "\Anlagen\" & strAbsender
         MkDir CurrentProject.Path & "\Anlagen\" & strAbsender & "\" & lngMailItemID
         MkDir strPfad
         On Error GoTo 0
         For Each objAnlage In objMailItem.Attachments
             strDateiname = objAnlage.FileName
             objAnlage.SaveAsFile strPfad & "\" & strDateiname
             db.Execute "INSERT INTO tblAnlagen(MailItemID, Anlagepfad, Dateiname) VALUES(" & lngMailItemID & ", '" _
                 & strPfad & "\" & Replace(objAnlage.FileName, "'", "''") & "', '" & Replace(strDateiname, "'", "''") _
                 & "')", dbFailOnError
         Next objAnlage
     End If
End Sub

Listing 5: Die Prozedur AnlagenSpeichern

Falls ja, stellt sie in der Variablen strPfad den Zielpfad für die zu speichernden Anlagen zusammen. Der Pfad beginnt mit dem aktuellen Datenbankverzeichnis und setzt sich aus dem Ordner Anlagen, der E-Mail-Adresse des Absenders und dem Primärschlüsselwert der E-Mail in der Tabelle tblMailitems zusammen. Sollte dieses Verzeichnis noch nicht vorhanden sein, legen die folgenden Anweisungen dieses an. Danach durchläuft die Prozedur alle Elemente der Attachments-Auflistung des MailItem-Objekts und speichert den Dateinamen jeweils in der Variablen strDateiname. Die Methode SaveAsFile speichert den Inhalt des Anlagefeldes schließlich unter dem gewünschten Namen im angegebenen Verzeichnis. Außerdem fügt die Prozedur der Tabelle tblAnlagen einen Eintrag hinzu, der festhält, welche Anlagen zu welcher Mail im Dateisystem hinterlegt wurden.

Speichern der .msg-Datei

Jede E-Mail kann als .msg-Datei gespeichert werden. Mit dem Textfeld txtGroesse gibt der Benutzer an, ab welcher Größe die .msg-Dateien im Dateisystem gespeichert werden sollen. Die übrigen speichert die nachfolgend beschriebene Prozedur direkt in einem Anlagefeld in der Tabelle tblMailitems. Die Prozedur MailItemSpeichern (s. Listing 6) prüft die Größe des MailItem-Objekts und vergleicht sie mit dem Wert des Parameters lngSize. Ist diese kleiner als lngSize, speichert die Prozedur die Mail mit der SaveAs-Methode zunächst im Dateisystem, und zwar unter dem Namen temp.msg im Verzeichnis der Datenbank. Dann erstellt sie ein neues Recordset auf Basis der Tabelle tblMailitems, wobei dieses nur den Datensatz zu der zu speichernden Mail enthält. Der Datensatz wird mit der Edit-Methode zur Verarbeitung freigegeben. Der Inhalt des Anlagefeldes MailItem wird dann als neues Recordset referenziert. Es erhält einen neuen Datensatz, dessen Feld FileData über die Methode LoadFromFile mit der soeben gespeicherten .msg-Datei gefüllt wird. Anschließend werden die verschachtelten Recordsets jeweils mit der Update-Methode gespeichert und die Datei temp.msg gelöscht.

Public Sub MailItemSpeichern(objMailItem As Outlook.MailItem, db As DAO.Database, lngMailItemID As Long, _
         lngSize As Long)
     Dim rst As DAO.Recordset
     Dim rst2 As DAO.Recordset2
     Dim fld2 As DAO.Field2
     With objMailItem
         If objMailItem.Size <= lngSize Then
             .SaveAs CurrentProject.Path & "\temp.msg"
             Set rst = db.OpenRecordset("SELECT MailItem FROM tblMailitems WHERE MailItemID = " & lngMailItemID, _
                 dbOpenDynaset)
             rst.Edit
             Set rst2 = rst.Fields("MailItem").Value
             rst2.AddNew
             Set fld2 = rst2.Fields("FileData")
             fld2.LoadFromFile CurrentProject.Path & "\temp.msg"
             Kill CurrentProject.Path & "\temp.msg"
             rst2.Update
             rst.Update
         Else
             On Error Resume Next
             MkDir CurrentProject.Path & "\MSG\"
             On Error GoTo 0
             .SaveAs CurrentProject.Path & "\MSG\" & lngMailItemID & ".msg"
         End If
         .BillingInformation = "saved"
         .Save
     End With
End Sub

Listing 6: Die Prozedur MailItemSpeichern

Wenn die Größe größer als die zulässige Größe ist, speichert die Prozedur die .msg-Datei einfach im Verzeichnis MSG, das als Unterverzeichnis des aktuellen Datenbankverzeichnisses angelegt wird. Schließlich stellt die Prozedur die Eigenschaft BillingInformation des MailItem-Objekts auf Saved ein und speichert die geänderte Mail mit der Save-Methode.

Einlesen der Unterordner

Fehlt noch die Prozedur UnterordnerEinlesen, welche für das rekursive Einlesen aller Ordner unterhalb des als Startordner angegebenen Ordners sorgt (s. Listing 7).

Public Sub UnterordnerEinlesen(objParent As Outlook.Folder, db As DAO.Database, lngAnzahl As Long, _
         lngAnzahlEingelesen As Long, lngSize As Long, bolNeuEinlesen As Boolean, bolAnlagenSpeichern As Boolean)
     Dim objFolder As Outlook.Folder
     For Each objFolder In objParent.Folders
         lngAnzahlEingelesen = lngAnzahlEingelesen + objFolder.Items.Count
         SysCmd acSysCmdSetStatus, lngAnzahlEingelesen & "/" & lngAnzahl
         MailsEinlesen objFolder, db, lngSize, bolNeuEinlesen, bolAnlagenSpeichern
         UnterordnerEinlesen objFolder, db, lngAnzahl, lngAnzahlEingelesen, lngSize, bolNeuEinlesen, bolAnlagenSpeichern
     Next objFolder
End Sub

Listing 7: Die Prozedur UnterordnerEinlesen

Diese Prozedur erwartet den übergeordneten Ordner als Parameter sowie einige weitere Informationen, die für die nachgeschalteten Routinen benötigt werden. Die Prozedur durchläuft alle Elemente der Folders-Auflistung des mit objParent übergebenen Folder-Objekts und addiert zunächst die Anzahl der in diesem Ordner enthaltenen MailItem-Objekte zur Variablen lngAnzahl­Eingelesen hinzu.

Dann veröffentlicht sie den aktuellen Zwischenstand in der Statusleiste und ruft die Prozedur MailsEinlesen für diesen Ordner auf. Dort beginnt das gleiche Spiel wie bereits weiter oben für den Hauptordner beschrieben von vorn.

Danach ruft die Prozedur sich noch selbst auf, um eventuelle weitere untergeordnete Folder-Objekte zu durchlaufen und die enthaltenen E-Mails einzulesen.

Zusammenfassung und Ausblick

Im zweiten Teil dieser Beitragsreihe sehen wir uns an, wie die mit den hier vorgestellten Methoden gespeicherten Daten aussehen beziehungsweise an welchen Stellen in der Datenbank und im Dateisystem diese gelandet sind. Außerdem entwerfen wir ein Formular, mit dem Sie die archivierten E-Mails nach verschiedenen Kriterien durchsuchen, in Outlook öffnen und sogar wiederherstellen können.

Kompletten Artikel lesen?

Einfach für den Newsletter anmelden, dann lesen Sie schon in einer Minute den kompletten Artikel und erhalten die Beispieldatenbanken.

E-Mail:

Download

Download

Die .zip-Datei enthält folgende Dateien:

MailsImportieren.accdb

Beispieldateien downloaden

© 2003-2015 André Minhorst Alle Rechte vorbehalten.