Outlook
Die Herausforderung
Im Outlook dieselbe Ordnerstruktur wie im Dateisystem.
Dazu braucht es eine Routine, welche das Dateisystem ab der
gewünschten Stelle durchsucht und die entsprechenden Ordner in Outlook
erstellt. Eine klassische Rekursion zur Durchwanderung eines Daten-Baums.
Die Prozedur zu erstellen ist eines, wirklich professionell ausprogrammieren
das andere. Darauf erhebe ich keinen Anspruch. Es wurmt mich lediglich, dass
es nicht möglich ist, in Outlook den Common Dialog mit dem Dateisystem
aufzurufen, so muss der Ausgangsordner für die Suche eben direkt eingegeben
werden (bFolder).
Option Explicit
Dim fsObject, fObject, sfObject, sFolder
Dim bFolder As String
Public Sub FolderTransfer()
' Aufruf der rekursiven Funktion CopyFolder mit den
Basis-Elementen
' bFolder: Ordner im Dateisystem, dessen Struktur kopiert werden soll
' olFolder: Ornder in Outlook, wohin die Struktur kopiert werden soll
On Error Resume Next ' keine Lust für ein
Error-Handling
Dim myOlApp As New Outlook.Application
Dim myNameSpace As Outlook.NameSpace
Dim olFolder As Outlook.Folder
Set myNameSpace = myOlApp.GetNamespace("MAPI")
Set olFolder = myNameSpace.PickFolder ' Aufruf des
Fensters zur Zielwahl in Outlook
Set fsObject = CreateObject("Scripting.FileSystemObject")
bFolder = "C:\Data\MeinOrdner"
CopyFolder bFolder, olFolder
' rekursive Funktion, welche die gesamte Ordnerstruktur durchläuft
MsgBox "Datei-Ordner-Struktur von " & bFolder & " nach Outlook-Ordner " &
olFolder.Name & " kopiert.", vbInformation, "Ordnerstruktur synchronisieren"
Set fsObject = Nothing
Set fObject = Nothing
Set sfObject = Nothing
Set sFolder = Nothing
End Sub
Function CopyFolder(fPath, oFolder As Outlook.Folder)
' rekursive Funktion, die alle Unterordner durchläuft
und die entsprechenden Unterordner in Outlook erstellt.
Dim tFolder As Outlook.Folder
Set fObject = fsObject.GetFolder(fPath) ' globale
Variable
Set sfObject = fObject.SubFolders
' globale Variable
On Error Resume Next ' keine Lust für ein Error-Handling
For Each sFolder In sfObject
' suche alle Unterordner des Dateisystems ab
Set tFolder = oFolder.Folders.Add(sFolder.Name)
' füge Outlook-Ordner mit Name des Datei-Ordners hinzu
CopyFolder sFolder.Path, tFolder
' rekursiver Aufruf (auf Ebene des jeweiligen Unterordners)
Next
Set tFolder = Nothing
End Function
Nächste Herausforderung
Lösen und Abspeichern aller Anlagen und E-Mails in allen
Unterordnern in Outlook
Es braucht dazu wiederum eine rekursive Routine, welche die gesamte
Ordnerstruktur in Outlook durchläuft.
Dateinamen beginnen alle mit dem Datum im Format "JJJJ MM TT". Die
verschiedenen Debug.Print-Statements dienten der Programm-Verfolgung bei der
Entwicklung.
Dim nbrMessages, nbrSaved, nbrAttachments As Integer
Private Sub BrowseMail()
' Aufruf der rekursiven Prozedur BrowseSubfolders zur
Suche nach eMails
Dim objInbox As Outlook.MAPIFolder
Dim objMail As MailItem
Dim objC As Integer
On Error Resume Next
MsgBox "Nicht beirren lassen durch Fehlermeldungen wie" & vbCrLf & _
"'Filesystem defekt' oder 'Festplatte voll/ schreibgeschützt':" & vbCrLf & _
"Diese Fehler entstehen, wenn eine Datei mit einer gebrochenen Verknüpfung"
& _
"im RTF-Format gespeichert werden soll." & vbCrLf & _
"Die Datei wird rotzdem korrekt abgelegt.", vbExclamation, "eMail
Management"
' Set objInbox = Application.GetNamespace("MAPI").GetDefaultFolder(olFolderInbox)
' Posteingang selbst wird nicht geprüft
Set objInbox = Application.GetNamespace("MAPI").PickFolder
' gewählter Ordner selbst wird nicht geprüft
nbrMessages = 0
nbrSaved = 0
nbrAttachments = 0
bFolder = "C:\Data\MeinOrdner" ' Stammordner im Dateisystem
Call BrowseSubfolders(objInbox, "", 0)
Set objMail = Nothing
Set objInbox = Nothing
MsgBox nbrMessages & " eMails geprüft" & vbCrLf & _
nbrSaved & " eMails gespeichert" & vbCrLf & _
nbrAttachments & " Anlagen entfernt/ gespeichert", vbInformation, "eMail
Management"
End Sub
Private Sub BrowseSubfolders(cFolder As MAPIFolder, ByVal objPath As String,
ByVal objLevel As Integer)
' Rekursive Prozedur zur Suche nach eMails im
angegebenen cFolder (Outlook) und allen Unterordnern
Dim objSubFolder As MAPIFolder
Dim objMail As MailItem
Dim tmpPath, sPath, sFile, errStr As String
Dim aCount, i As Integer
On Error Resume Next
objLevel = objLevel + 1 ' wird nicht verwendet
For Each objSubFolder In cFolder.Folders
tmpPath = objPath & "\" & objSubFolder
For Each objMail In objSubFolder.Items
nbrMessages = nbrMessages + 1
Debug.Print nbrMessages & " Folder: "
& objSubFolder.Name & " >>>Message: " & objMail.Subject & " >>>Categories: "
& objMail.Categories & " >>>Attachments: " & CStr(objMail.Attachments.count)
If Not IsCategory(objMail, "Saved")
Then ' Prüfe nur, wenn Kategorie "Saved" nicht gesetzt
' falls der Unterordner nicht exisitert, erstell ihn
MakeDir (bFolder & tmpPath)
sPath =
bFolder & tmpPath & "\" & Format(objMail.ReceivedTime, "yyyy mm dd") & " " &
CleanFilename(objMail.SenderName)
aCount =
objMail.Attachments.count
If aCount > 0
Then
For i = 1 To aCount
If CopyAttachment(objMail.Attachments.Item(i).FileName) Then
sFile = " - " & CleanFilename(Trim(Left(objMail.Attachments.Item(i).FileName,
92)))
objMail.Attachments.Item(i).SaveAsFile sPath & sFile
Debug.Print " > Attachment saved: " & sPath & sFile
End If
Next i
For i = 1 To
aCount
nbrAttachments = nbrAttachments + 1
Debug.Print " > Attachment deleted: " & objMail.Attachments.Item(1).FileName
objMail.Attachments.Item(1).Delete ' lösche Anlage
Next i
nbrSaved =
nbrSaved + 1
objMail.Save
End If
sFile = " - "
& CleanFilename(Trim(Left(objMail.Subject, 92)))
sFile = sPath
& sFile
Debug.Print "
> Message to save: " & sFile & ".rtf"
objMail.SaveAs sFile & ".rtf", olRTF ' speichere eMail im Rich Text Format
' objMail.SaveAs sFile & ".msg", olMSG ' speichere eMail im Outlook-Message
Format
Debug.Print "
> Message saved: " & sFile & ".rtf"
Call
SetCategory(objMail, "Saved") ' setze Kategorie "Saved",
um Überprüfung im nächsten Lauf zu vermeiden
End If
Next objMail
Call BrowseSubfolders(objSubFolder, tmpPath, objLevel)
' rekursiver Aufruf für Unterordner
tmpPath = objPath & "\" & objSubFolder
Next objSubFolder
Set objMail = Nothing
Set objSubFolder = Nothing
End Sub
Public Function IsCategory(mItm As MailItem, cat As String) As Boolean
' prüft, ob die Kategorie cat im Mail-Objekt enthalten
ist
On Error Resume Next
IsCategory = False
If InStr(mItm.Categories, cat) > 0 Then IsCategory = True
End Function
Public Sub SetCategory(ByRef mItm As MailItem, ByVal cat As String)
' prüft, ob schon Kategorien gesetzt sind und fügt cat
hinzu
Dim tCat As String
tCat = mItm.Categories
If Len(tCat) = 0 Then
mItm.Categories = cat
Else
mItm.Categories = tCat & ";" & cat
End If
mItm.Save
End Sub
Public Function CleanFilename(ByVal sFilename As String) As String
' entferne unerlaubte/ unerwünschte Zeichen aus
Dateinamen
sFilename = Replace(sFilename, "_", " ") ' ersetze
vorbereitend alle "_" durch " "
sFilename = Replace(sFilename, Chr(9), " ") ' Tabulator
sFilename = Replace(sFilename, "%", "_")
sFilename = Replace(sFilename, "\", "_")
sFilename = Replace(sFilename, "/", "_")
sFilename = Replace(sFilename, ":", "_")
sFilename = Replace(sFilename, ";", "_")
sFilename = Replace(sFilename, "?", "_")
sFilename = Replace(sFilename, "*", "_")
sFilename = Replace(sFilename, "'", "_")
sFilename = Replace(sFilename, Chr(34), "_") '
Anführungszeichen
sFilename = Replace(sFilename, ">", "_")
sFilename = Replace(sFilename, "<", "_")
sFilename = Replace(sFilename, "|", "_")
sFilename = Replace(sFilename, " _", "_")
sFilename = Replace(sFilename, "_ ", "_")
Do While sFilename <> Replace(sFilename, "__", "_") '
ersetze aufeinanderfolgende "__" durch einen einzigen "_"
sFilename = Replace(sFilename, "__", "_")
Loop
Do While sFilename <> Replace(sFilename, " ", " ")
sFilename = Replace(sFilename, " ", " ")
Loop
CleanFilename = sFilename
End Function
Public Function CopyAttachment(ByVal fName As String) As Boolean
CopyAttachment = True
' Wenn eine Datei mit z.B. "2008 02 15 " beginnt, dann
exisitert sie mit grösster Wahrscheinlichkeit schon und muss nicht
gespeichert werden.
If Left(fName, 2) = "20" Then
If IsNumeric(Mid(fName, 3, 2)) And IsNumeric(Mid(fName, 6,
2)) And IsNumeric(Mid(fName, 9, 2)) And Mid(fName, 5, 1) = " " _
And Mid(fName, 8, 1) = " " And Mid(fName, 11, 1) = " " Then
CopyAttachment = False
End If
' Automatische Anlagen aus HTML-Meldungen auf
Text-Systeme, Firmen-Logos etc.
ElseIf InStr(fName, "ATT00") Or InStr(fName, "TXT00") Then
CopyAttachment = False
End If
End Function
Public Sub MakeDir(ByVal dPath As String)
' Kreiert ein Unterverzeichnis
' Falls das Unterverzeichnis schon existiert, wird ein Fehler generiert, der
über 'Resume Next' abgefangen wird.
' Falls das Unterverzeichnis aus einem anderen Grund nicht erstellt werden
konnte, weiss man es leider nicht...
On Error Resume Next
MkDir dPath
End Sub