Outlook: Mails nach dem Senden per VBA verschieben

Möchtest Du den gesamten Artikel lesen? Und vielleicht sogar den Artikel im PDF-Format und die Beispieldateien herunterladen? Dann hole Dir den Artikel gleich hier - völlig kostenlos!

Anlegen einer neuen Regel für eingehende Nachrichten

Bild 1: Anlegen einer neuen Regel für eingehende Nachrichten

Für eingehende E-Mails gibt es unter Outlook die Regel-Funktion, mit der man einstellen kann, unter welchen Umständen eine E-Mail, die im Posteingang landet, in einen anderen Ordner verschoben werden soll. Das kann man beispielsweise nutzen, um immer wiederkehrende Rechnungen direkt in den entsprechenden Ordner zu verschieben. Wünschenswert wäre, wenn es eine solche Funktion auch für versendete E-Mails gäbe. Da Outlook hier aber keine eingebaute Funktion bereitstellt, schauen wir uns das Thema einmal genauer an und entwickeln VBA-Code, mit dem wir diese Aufgabe selbst steuern können. Dabei wollen wir sowohl über die Benutzeroberfläche gesendete E-Mails erfassen als auch E-Mails, die wir per VBA absenden.

Wenn wir in Outlook mit der rechten Maustaste auf eine E-Mail in einem beliebigen Ordner klicken, erscheint das Kontextmenü und offeriert uns den Eintrag Regeln|Regel erstellen … (siehe Bild 1).

Anlegen einer neuen Regel für eingehende Nachrichten

Bild 1: Anlegen einer neuen Regel für eingehende Nachrichten

Damit öffnen wir einen Dialog namens Regel erstellen, mit dem wir genauer festlegen können, wann die Regel ausgelöst werden soll und was wir damit bewirken wollen (siehe Bild 2). Wir können hier zum Beispiel angeben, dass nur E-Mails mit einem bestimmten Betreff, für einen bestimmten Empfänger oder von einem bestimmten Absender verarbeitet werden sollen. Außerdem geben wir an, was mit der E-Mail geschehen soll. Hier reichen die Möglichkeiten von einer Benachrichtigung über die Ausgabe eines Sounds bis hin zum Verschieben in einen bestimmten Ordner.

Dialog zum Erstellen einer Regel

Bild 2: Dialog zum Erstellen einer Regel

Diese Regel gelten jedoch nur für Elemente, die frisch im Posteingang gelandet sind. Wenn wir also eine E-Mail erstellen und diese versenden, wird die Regel nicht ausgelöst. Genau diese fehlende Funktion wollen wir im vorliegenden Artikel nachreichen. Dabei gibt es zwei Ansätze:

  • Wir erstellen eine E-Mail automatisiert per VBA, beispielsweise von einer Datenbankanwendung aus, und wollen dafür sorgen, dass diese direkt aus dem Ordner Gesendete Elemente in einen vordefinierten Ordner verschoben wird.
  • Oder wir erstellen eine E-Mail auf herkömmliche Art über die Benutzeroberfläche von Outlook und versenden diese. Auch hier wollen wir, dass diese E-Mails nach vorgegebenen Regeln in andere Ordner verschoben werden.

Da die erste Lösung wesentlich einfacher zu programmieren ist, starten wir mit dieser. Die Programmierung erledigen wir der Einfachheit halber innerhalb des VBA-Projekts von Outlook. Wir verwenden jedoch die volle Referenzierung der Klassen, damit diese auch in anderen Anwendungen eingesetzt werden können. Dort müssen wir lediglich noch einen Verweis auf die Bibliothek Microsoft Outlook 16.0 Object Library hinzufügen. Diesen Verweis legen wir im Verweise-Dialog an, den wir im VBA-Editor der jeweiligen Anwendung mit dem Menübefehl Extras|Verweise öffnen.

Per VBA gesendete E-Mails in anderen Ordner verschieben

Das Versenden eine E-Mail per VBA ist keine Raketentechnik. Und spannenderweise benötigen wir nur noch eine kleine Änderung, damit die gesendete E-Mail nicht im Ordner Gesendete Elemente landet, sondern in einem beliebigen anderen Ordner Deiner Wahl.

Dann verwenden wir die Prozedur aus Listing 1. Die Prozedur deklariert zunächst die benötigen Objektvariablen. objOutlook füllen wir hier mit einem Verweis auf eine neue Instanz von Outlook, die bei Vorhandensein einer Instanz jedoch mit der bestehenden Instanz gefüllt wird. Mit objMAPI referenzieren wir den MAPI-Namespace von Outlook.

Public Sub EMailSendenUndVerschieben()
     Dim objOutlook As Outlook.Application
     Dim objMAPI As Outlook.NameSpace
     Dim objMailItem As Outlook.MailItem
     Dim objFolder As Outlook.Folder
         
     Set objOutlook = New Outlook.Application
     Set objMAPI = objOutlook.GetNamespace("MAPI")
     Set objFolder = objMAPI.PickFolder
         
     Set objMailItem = Application.CreateItem(olMailItem)
     With objMailItem
         .To = "Info@amvshop.de"
         .Subject = "Betreff der E-Mail"
         .Body = "Dies ist der Inhalt der E-Mail."
         Set .SaveSentMessageFolder = objFolder
         .Send
     End With
End Sub

Listing 1: Senden einer neuen E-Mail und Verschieben in einen zuvor gewählten Ordner

Dieser wiederum erlaubt uns, die PickFolder-Funktion zu nutzen, um den Dialog aus aufzurufen, der uns die Auswahl eines beliebigen Ordners erlaubt. Hier wählen wir den Ordner Posteingang aus (siehe Bild 3), der nun mit der Variablen objFolder referenziert wird.

Auswahl des Zielordners

Bild 3: Auswahl des Zielordners

Anschließend erstellen wir ein neues MailItem-Objekt mit der CreateItem-Methode und dem Parameter olMailItem. Für diese legen wir die üblichen Eigenschaften To, Subject und Body fest. Außerdem stellen wir mit der Eigenschaft SaveSendMessageFolder auf den zuvor ausgewählten und mit objFolder referenzierten Ordner ein. Schließlich rufen wir die Send-Methode auf und senden die E-Mail somit.

Sofern wir gerade den Posteingang angezeigt haben, erscheint dort umgehend die gesendete E-Mail (außer, es dauert in Deinem System etwas länger, bis E-Mails den Postausgang verlassen).

Zielordner ohne Auswahldialog festlegen

Normalerweise möchtest Du nicht immer erneut den Zielordner auswählen. Daher kannst Du diesen auch direkt angeben. Dazu sind zwei Schritte nötig:

  • Du musst einmalig den Pfad des Zielordners ermitteln, beispielsweise in der Form \\Outlook\Posteingang.
  • Dann benötigen wir eine Funktion, die auf Basis dieser Pfadangabe den zugrunde liegenden Ordner in Form eines Folder-Objekts ermittelt und zurückgibt.

Die erste Aufgabe können wir leicht mit der folgenden Prozedur erledigen:

Public Function GetPickFolderPath() As String
     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
         GetPickFolderPath = objFolder.FolderPath
     End If
End Function

Diese öffnet den bereits weiter oben vorgestellten Dialog zur Auswahl eines Ordners und gibt den Pfad zu dem gefundenen Order als Zeichenkette zurück. Falls der Benutzer die Auswahl durch Anklicken der Abbrechen-Schaltfläche abbricht, wird eine leere Zeichenkette zurückgegeben.

Mit diesem Ausdruck, zum Beispiel \\Outlook\Posteingang, können wir mit der Funktion GetFolderFromPath aus Listing 2 ein Folder-Objekt ermitteln. Leider gibt es keine direkte Funktion etwa des NameSpace-Objekts, um auf Basis eines Pfades ein Folder-Objekt zurückzuliefern. Deshalb holen wir es uns mit einer selbst entwickelten Funktion.

Public Function GetFolderFromPath(strPath As String) As Outlook.Folder
     Dim objOutlook As Outlook.Application
     Dim objMAPI As Outlook.NameSpace
     Dim objFolder As Outlook.Folder
     Dim strFolders() As String
     Dim strFolderNames() As String
     Dim i As Integer
     Dim j As Integer
     strFolders = Split(strPath, "\")
     For i = LBound(strFolders) To UBound(strFolders)
         If Not Len(strFolders(i)) = 0 Then
             ReDim Preserve strFolderNames(j)
             strFolderNames(j) = strFolders(i)
             j = j + 1
         End If
     Next i
     Set objOutlook = New Outlook.Application
     Set objMAPI = objOutlook.GetNamespace("MAPI")
     Set objFolder = objMAPI.Folders(strFolderNames(0))
     For j = LBound(strFolderNames) + 1 To UBound(strFolderNames)
         Set objFolder = objFolder.Folders(strFolderNames(j))
     Next j
     Set GetFolderFromPath = objFolder
End Function

Listing 2: Ermitteln eines Folder-Objekts auf Basis des Pfades

Wir übergeben dieser den Pfad zum gewünschten Ordner. Die Funktion deklariert zwei Arrays. Das erste Array benötigen wir für das Ergebnis der Split-Funktion, die wir mit dem Trennzeichen \ auf den mit strPath gelieferten Pfad anwenden. Damit erzeugen wir ein Array, dass die an den Backslash-Zeichen aufgesplittete Zeichenketten aus strPath erhält. Bei \\Outlook\Posteingang ist das Element mit dem Index 0 eine leere Zeichenkette, das mit dem Index 1 auch, der Index 2 enthält Outlook und der Index 3 enthält Posteingang.

Das zweite Array soll alle Elemente des ersten Arrays erhalten, die keine leere Zeichenkette enthalten. Dazu durchlaufen wir eine For…Next-Schleife über alle Elemente aus strFolders und prüfen, ob das aktuelle Element eine leere Zeichenkette enthält. Falls nicht, dimensionieren wir das Array strFolderNames in der entsprechenden Größe und hängen das aktuelle Element des ersten Arrays hinten an.

Nun können wir auf Outlook zugreifen, uns das MAPI-Namespace holen und erst einmal den Ordner referenzieren, der den Namen aus dem ersten Element von strFolderNames enthält. Danach durchlaufen wir die übrigen Elemente des Arrays strFolderNames und ermitteln das jeweils nächste untergeordnete Element aus der Folders-Auflistung. Dieses weisen wir wieder der Variablen objFolder zu. Auf diese Weise arbeiten wir uns bis zum untersten Folder-Element durch und geben dieses schließlich als Funktionsergebnis zurück.

Damit ausgestattet können wir die eingangs beschriebene Prozedur wie folgt anpassen, wenn wir wollen, dass die versendete E-Mail direkt im Posteingang landet:

Public Sub EMailSendenUndVerschiebenNachPfad()
     ...
     Set objFolder = _
         GetFolderFromPath("Outlook\Posteingang\")
     ...
End Sub

Statt dem Posteingangsordner können wir hier auch jeden anderen Ordner angeben.

Damit haben wir das Verschieben von per VBA erstellten E-Mails in den gewünschten Ordner bereits programmiert und können uns nun einer anspruchsvolleren Aufgabe zuwenden – dem Verschieben E-Mails, die wir über die Benutzeroberfläche von Outlook gesendet haben.

Per Outlook gesendete E-Mails in anderen Ordner verschieben

Warum ist das anspruchsvoller? Weil es nicht ausreicht, sich einfach nur in den Prozess reinzuhängen, mit dem die E-Mail verschickt wird. Sondern wir müssen irgendwie ein Ereignis abfangen, das ausgelöst wird, wenn der Benutzer die E-Mail versendet hat. Welches nutzen wir hier optimalerweise? Woran erkennen wir, dass eine E-Mail versendet wurde?

Offensichtlich ist eine E-Mail erst dann erfolgreich versendet worden, wenn sie im Ordner Gesendete Objekte gelandet ist. Wir müssen also ein Ereignis definieren, das ausgelöst wird, wenn ein Element zu diesem Ordner hinzugefügt wird. Dann brauchen wir noch eine Möglichkeit, die Regeln festzulegen, nach denen wir bestimmte E-Mails vom Ordner Gesendete Objekte in den gewünschten Ordner übertragen.

Wir schauen uns zunächst einmal die Basisversion ohne Regeln an. Während es beim ersten Beispiel keine Rolle spielte, ob wir den Code in einem Standardmodul oder einen Klassenmodul wie ThisOutlookSession angelegt haben, kommt dies nun zum Tragen. Wir wollen eine Objektvariable mit dem Schlüsselwort WithEvents deklarieren, damit wir seine Ereignisse implementieren wollen.

Deshalb fügen wir den Code in das Modul ThisOutlookSession im VBA-Projekt von Outlook ein. Wenn Du diesen Code im VBA-Projekt einer anderen Anwendung nutzen möchtest, musst Du die folgenden Elemente in ein Klassenmodul einfügen, das Du dann initialisierst – wir zeigen später, wie das gelingt.

Wir deklarieren erst einmal die Objektvariable für eine Items-Auflistung, über die wir die im Ordner Gesendete Elemente enthaltenen Elemente referenzieren:

Public WithEvents objItems As Outlook.Items

Dann rufen wir eine Prozedur namens Aktivieren auf. Diese referenziert die aktuelle Outlook-Instanz und darüber den MAPI-Namespace und den Ordner Gesendete Elemente, den wir mit der Funktion GetDefaultFolder mit dem Parameter olFolderSentMail holen. Dessen Items-Auflistung weisen wir schließlich der oben definierten Variablen objItems zu:

Public Sub Aktivieren()
     Dim objOutlook As Outlook.Application
     Dim objMAPI As Outlook.NameSpace
     Dim objFolder As Outlook.Folder
     Set objOutlook = Application ''New Outlook.Application
     Set objMAPI = objOutlook.GetNamespace("MAPI")
     Set objFolder = _
         objMAPI.GetDefaultFolder(olFolderSentMail)
     Set objItems = objFolder.Items
End Sub

Schließlich implementieren wir das Ereignis ItemAdd der Objektvariablen objItems. Dazu wählen wir objItems im linken Listenfeld des VBA-Fensters aus und erhalten so automatisch eine neue, leere Ereignisprozedur für das Standardereignis ItemAdd dieser Klasse. Diese füllen wir wie folgt:

Private Sub objItems_ItemAdd(ByVal Item As Object)
     Dim objMailitem As Outlook.MailItem
     Dim objFolder As Outlook.Folder
     Select Case TypeName(Item)
         Case "MailItem"
             Set objMailitem = Item
             Set objFolder = _
                 GetFolderFromPath("Outlook\Posteingang")
             objMailitem.Move objFolder
     End Select
End Sub

Diese Ereignisprozedur liefert mit dem Parameter Item einen Verweis auf das zum Ordner Gesendete Elemente hinzugefügten Elements. Wir prüfen, ob es sich dabei um ein Element des Typs MailItem handelt. Falls ja, referenzieren wir es mit der Variablen objMailItem und ermitteln für objFolder den Zielordner, in diesem Fall \\Outlook\Posteingang (nicht, dass dieser Zielordner sinnvoll wäre, aber wie sehen diesen beim Experimentieren direkt).

Dann rufen wir die Methode Move auf und übergeben als Parameter den Verweis auf den Ordner, in den die E-Mail verschoben werden soll.

Wenn wir nun eine E-Mail senden, wird diese automatisch direkt in den Posteingang verschoben.

Beim Start automatisch aktivieren

Nun wird die Objektvariable objItems beim Beenden von Outlook automatisch geleert und beim Neustart nicht automatisch wieder gefüllt. Das können wir jedoch erreichen, indem wir die Funktion Aktivieren automatisch beim Start von Outlook aufrufen. Das erledigen wir, indem wir den Aufruf einfach in die folgende Prozedur eintragen:

Private Sub Application_Startup()
     Call Aktivieren
End Sub

Diese Prozedur wird, wenn sie in der Klasse ThisOutlookSession platziert ist, beim Start von Outlook gestartet.

Damit fehlt uns noch die Möglichkeit, verschiedene Bedingungen hinzuzufügen und festzulegen, in welchen Ordner die E-Mails je nach Bedingung landen sollen.

Hier müssen wir uns erst einmal überlegen, welche Bedingungen wir nutzen wollen. Typischerweise ist oft der Adressat der E-Mail interessant für eine solche Bedingung. Manche Adressaten sind mit speziellen Rollen verknüpft, in deren Kontext es oft entsprechende Ordner in Outlook gibt. Ein Beispiel: E-Mails an die Steuerberaterin sollen im Ordner Buchhaltung landen. Oder E-Mails an Partner oder Partnerin in einem Ordner namens Privat. Manchmal gibt es auch Ordner für den E-Mail-Austausch mit bestimmten Dienstleistern – auch hier ist es sinnvoll, diese E-Mails am Empfänger zu identifizieren und sie gleich in den entsprechenden Ordner zu verschieben.

E-Mail des Adressaten auslesen

Auch wenn wir die E-Mail-Adresse des Adressaten einer E-Mail mit der To-Eigenschaft angegeben haben, können wir diese noch längst nicht über diese Eigenschaft auslesen.

Wenn wir die E-Mail-Adresse des Empfängers in die E-Mail eingeben, erscheinen in der Regel Vorschläge für dem Empfänger. Hier wird neben der E-Mail-Adresse manchmal auch noch eine weitere Information angezeigt (siehe Bild 4). Wenn wir diese auswählen oder die dort verwendete E-Mail-Adresse eingeben, stellt Outlook den Wert für To automatisch auf den oben angezeigten Wert ein. Wir sollten die Bedingung also nicht so gestalten, dass wir das To-Feld nach einer E-Mail durchsuchen. Tatsächlich kann To sogar mehrere E-Mail-Adressen aufnehmen.

Ein Alias für die E-Mail-Adresse

Bild 4: Ein Alias für die E-Mail-Adresse

Um an die tatsächlich hinter der Adresse steckende E-Mail-Adresse zu kommen, verwenden wir die Recipients-Auflistung des MailItem-Objekts. Wenn wir für To/An mehrere Empfänger eingegeben haben, enthält die Recipients-Auflistung entsprechend viele Einträge. Wir müssten also eigentlich alle Einträge durchlaufen und dann prüfen, ob die gesuchte E-Mail-Adresse in der Auflistung enthalten ist. Das lassen wir an dieser Stelle aus und prüfen stattdessen nur die erste darin enthaltene E-Mail-Adresse. Das sollte für unseren Fall ausreichen, denn die meisten E-Mails in Zusammen mit Buchhaltung oder bestimmten Geschäftspartnern werden meist an einen Ansprechpartner geschickt. Sollen noch weitere Personen informiert werden, nutzt man normalerweise das Feld Cc.

Betrachten wir nur diesen Fall, können wir die Version der Prozedur objItems_ItemAdd aus Listing 3 verwenden. Hier untersuchen wir die verschiedenen Bedingungen in einer Select Case-Bedingung. Da wir als Vergleichskriterium den Wert True angegeben haben, können wir in die Case-Zweige Bedingungen wie die folgende einfügen:

Private Sub objItems_ItemAdd(ByVal Item As Object)
     Dim objMailitem As Outlook.MailItem
     Dim objFolder As Outlook.Folder
     Select Case TypeName(Item)
         Case "MailItem"
             Set objMailitem = Item
             Select Case True
                 Case Not InStr(1, objMailitem.Recipients(1).Address, "info@amvshop.de") = 0
                     Set objFolder = GetFolderFromPath("Outlook\Posteingang\Bestellungen")
                 Case Not InStr(1, objMailitem.Recipients(1).Address, "andre@minhorst.com") = 0
                     Set objFolder = GetFolderFromPath("Outlook\Posteingang\Buchhaltung")
             End Select
             If Not objFolder Is Nothing Then
                 objMailitem.Move objFolder
             End If
     End Select
End Sub

Listing 3: Verschieben von E-Mails mit verschiedenen Bedingungen

Not InStr(1, objMailitem.Recipients(1).Address, _
     "info@amvshop.de") = 0

Wir prüfen hier zum Beispiel, ob innerhalb der Adresse des ersten angegebenen Empfängers die E-Mail-Adresse info@amvshop.de befindet. Ist das der Fall, füllen wir die objFolder-Variable mit dem Ordner, in den E-Mails mit dieser Empfängeradresse landen sollen.

Nach der Select Case-Bedingung prüft die Prozedur, ob objFolder einen Verweis auf einen Ordner enthält und verschiebt die E-Mail in diesen Ordner.

Auf die gleiche Weise haben wir noch einen Case-Zweig für die E-Mail-Adresse andre@minhorst.com hinzugefügt. Mails an diese Adresse sollen in den Ordner \\Outlook\Posteingang\Buchhaltung verschoben werden.

Nun können wir sicher für unsere eigenen Zwecke die Bedingungen zum Verschieben versendeter E-Mails wie hier geschehen direkt im Quellcode verwalten. Unseren Benutzern sollten wir das aber nicht zumuten. Daher suchen wir nun nach einem Weg, um die Bedingungen anderweitig zu verwalten. Optimal wäre ein Formular, in das wir in einer Liste jeweils links die Empfänger-E-Mail-Adresse speichern könnten und rechts den Ordner, in den diese E-Mails nach dem Senden verschoben werden sollen.

Allerdings bietet Outlook keine einfache Möglichkeit, dies zu erledigen. Ein Kompromiss könnte eine Textdatei sein, in die der Benutzer die verschiedenen Kombinationen aus Empfängeradressen und Ordnern eintragen kann – getrennt durch ein Zeichen wie beispielsweise das Pipe-Zeichen (|).

Diese Textdatei soll beispielsweise wie in Bild 5 aussehen. Nun benötigen wir noch zwei Dinge:

Textdatei mit den Zuordnungen der E-Mails zu den Ordnern

Bild 5: Textdatei mit den Zuordnungen der E-Mails zu den Ordnern

  • Eine Möglichkeit, wo wir die Textdatei speichern beziehungsweise wo der Benutzer diese schnell finden und öffnen kann und
  • eine Prozedur, welche die Daten aus der Textdatei einliest und diese nutzt, um später die gesendeten E-Mails den entsprechenden Ordnern zuzuordnen.

Wo wir diese Datei speichern, können wir dem Benutzer überlassen – er muss dann einmalig im Code in einer Konstanten den Speicherort festlegen. Diesen kann er dann nach Bedarf anpassen.

Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...

den kompletten Artikel im PDF-Format mit Beispieldatenbank

diesen und alle anderen Artikel mit dem Jahresabo

Schreibe einen Kommentar