Ticketsystem, Teil VI

In den vorherigen Teilen dieser Beitragsreihe haben wir den Aufbau einiger Funktionen eines Ticketsystems beschrieben. Es fehlt noch der letzte Feinschliff: Wir wollen die erneuten Antworten von Kunden auf unsere als Antwort versendeten E-Mails automatisch in die Ticketverwaltung aufnehmen. Wie dies gelingt und wie Sie etwa nach Tickets filtern können oder per Ticketsystem erstellte E-Mails in Outlook einzusehen sind, zeigen wir in dieser letzten Folge der Beitragsreihe.

In diesem letzten Teil kümmern wir uns um drei noch offene Aufgaben:

  • Zu den einzelnen per Neue Aktion hinzugefügten Aktio-nen soll es möglich sein, die entsprechenden -E-Mails in Outlook anzuzeigen.
  • Die Antworten des Benutzers sollen erkannt werden. Dazu soll der Benutzer die Markierung im Betreff (etwa [Ticketx] mit x für die Nummer des Tickets) in der Antwort beibehalten. Solche E-Mails sollen dann ebenfalls in den Ticketverwaltungs-Ordner von Outlook verschoben werden, wo sie dann direkt dem jeweiligen Ticket zugeordnet werden.
  • Außerdem wollen wir das Formular frmTickets noch so anpassen, dass Sie nach Tickets filtern können – nach verschiedenen Kriterien wie dem Kunden, der Bezeichnung, dem Inhalt, dem Datum oder auch dem Status.

E-Mails zu den Aktionen einsehen

Im Formular frmTicket werden in einem Unterformular alle Aktionen angezeigt, die im Zusammenhang mit dem Ticket durchgeführt wurden. In der Tabelle tblAktionen, deren Datensätze in diesem Unterformular angezeigt werden, befindet sich bereits ein Feld namens MailItemID.

Dieses wird allerdings beim Verwenden einer Mail, die mit dieser Aktion zusammenhängt, noch nicht gefüllt. Dies müssten wir als Erstes bewerkstelligen, danach könnten wir dann ein Steuer-element hinzufügen, mit dem wir die entsprechende E-Mail öffnen können. Das wäre der einfache Weg, wenn man nur das Öffnen der E-Mail betrachtet – mit der EntryID könnte man dies einfach über die Methode GetItemFromID des Namespace-Objekts erledigen.

Allerdings ist es relativ kompliziert, per VBA an die Entry-ID der soeben versendeten E-Mail zu gelangen. Dazu deklarieren wir im Klassenmodul des Formulars frmTicket zunächst eine Variable, mit der wir später den Ordner mit den gesendeten Objekten referenzieren wollen, und zwar mit dem Schlüsselwort WithEvents:

Public WithEvents objFolderItems As Outlook.Items

Diese Variable füllen wir in der Prozedur, die durch das Anstoßen einer neuen Aktion ausgelöst wird. Damit stellen wir sicher, dass die Variable mit hoher Wahrscheinlichkeit auch noch nach dem Senden und damit beim Verschieben der E-Mail in den Ordner der gesendeten Elemente mit einem Verweis auf diesen Ordner gefüllt ist:

Private Sub cboNeueAktion_AfterUpdate()
     ...
     Set objFolderItems =  GetMAPI.GetDefaultFolder(olFolderSentMail).Items
     ...
End Sub

Warum der ganze Aufwand Weil wir irgendwie an die soeben versendete E-Mail herankommen müssen. Und das können wir, indem wir das Ereignis nutzen, das beim Verschieben einer E-Mail in den Ordner Gesendete Elemente ausgelöst wird.

Dazu legen wir dafür ein Ereignis an, indem wir im linken Kombinationsfeld des Codefensters des Klassenmoduls des Formulars den Eintrag objFolderItems Auswählen, wodurch im rechten Kombinationsfeld automatisch der Eintrag ItemAdd erscheint – und gleichzeitig wird die Ereignisprozedur mit der Signatur objFolder-Items_ItemAdd im Code hinterlegt.

Diese haben wir wie in Listing 1 gefüllt. Dort ermitteln wir zunächst das mit dem Parameter Item ermittelte Element und weisen es einer Objektvariablen des Typs MailItem zu, damit wir seine Eigenschaften per IntelliSense nutzen können.

Private Sub objFolderItems_ItemAdd(ByVal Item As Object)
     Dim db As DAO.Database
     Dim objMailItem As Outlook.MailItem
     Dim lngMailItemID As Long
     Set db = CurrentDb
     Set objMailItem = Item
     With objMailItem
         db.Execute "INSERT INTO tblMailItems(EntryID) VALUES('" & objMailItem.EntryID & "')", dbFailOnError
         lngMailItemID = db.OpenRecordset("SELECT @@IDENTITY").Fields(0)
         db.Execute "UPDATE tblAktionen SET MailItemID = " & lngMailItemID & " WHERE AktionID = " _
             & lngNeuesteAktionID, dbFailOnError
     End With
End Sub

Listing 1: Speichern der EntryID einer frisch verschickten E-Mail

Dann führen wir eine INSERT INTO-Abfrage aus, mit der wir der Tabelle tblMailItems einen neuen Eintrag zuweisen. Dabei tragen wir nur den Wert der Eigenschaft EntryID des MailItem-Objekts in das Feld EntryID ein.

Den Primärschlüsselwert des neu angelegten Datensatzes ermitteln wir danach mit der Abfrage SELECT @@IDENTITY und tragen diesen dann für den Datensatz der Tabelle tblAktionen ein, in dessen Kontext die E-Mail verschickt wurde. Den dabei verwendeten Wert für das Feld AktionID haben wir dabei in einer modulweit deklarierten Variablen namens lngNeuesteAktion zwischengespeichert:

Dim lngNeuesteAktionID As Long

Diesen Wert weisen wir der Variablen in der Prozedur cboNeueAktion zu, nachdem wir den entsprechenden Eintrag zur Tabelle tblAktionen hinzugefügt haben.

Mehr Informationen dazu wollen wir dem Datensatz der Tabelle tblMailItems gar nicht hinzufügen – wir wollen nur die EntryID vorhalten, um gleich schnell per Mausklick unsere Antwort im E-Mail-Format öffnen zu können.

Wo wollen wir diesen Mausklick im Formular frmTicket platzieren Am einfachsten wäre eine Schaltfläche, mit der wir den aktuellen Eintrag im Unterformular mit den Aktionen auslesen und die entsprechende E-Mail öffnen können. Diesen fügen wir wie in Bild 1 gezeigt ein.

Anlegen der Prozedur, die beim Start von Outlook ausgelöst wird

Bild 1: Anlegen der Prozedur, die beim Start von Outlook ausgelöst wird

Diese Schaltfläche soll die Ereignisprozedur aus Listing 2 auslösen. Diese prüft zunächst, ob aktuell ein Eintrag im Unterformular sfmAktionen markiert ist, dessen Feld MailItemID einen Wert enthält. Ist das der Fall, ermitteln wir den Wert des Feldes EntryID zu dem Datensatz der Tabelle tblMailItems, dessen Feld MailItemID dem gleichnamigen Feld des aktuell markierten Datensatzes im Unterformular entspricht.

Private Sub cmdEMailAnzeigen_Click()
     Dim strEntryID As String
     Dim objMailitem As Outlook.MailItem
     If Not IsNull(Me!sfmAktionen.Form!MailitemID) Then
         strEntryID = DLookup("EntryID", "tblMailItems", "MailItemID = " & Me!sfmAktionen.Form!MailitemID)
         Set objMailitem = GetMAPI.GetItemFromID(strEntryID)
         objMailitem.Display
     Else
         MsgBox "Zu dieser Aktion ist keine E-Mail verfügbar."
     End If
End Sub

Listing 2: Anzeigen einer E-Mail, die im Rahmen einer Aktion versendet wurde

Dann weisen wir der Variablen objMailItem mit der GetItemFromID-Funktion das MailItem-Objekt zu, das zu dieser EntryID gehört und öffnen es mit der Display-Methode.

Auf diese Weise können Sie die an den Kunden oder an andere beteiligte Personen verschickten E-Mails über Outlook öffnen.

Antworten der Benutzer automatisch erkennen

Wenn der Benutzer auf eine der E-Mails antwortet, die sie ihm geschickt haben, sollte er diesen Teil in eckigen Klammern im E-Mail-Betreff beibehalten.

Wenn Sie eine solche E-Mail dann aus dem Posteingang in den Ordner der Ticketverwaltung ziehen, sollte automatisch erkannt werden, zu welchem Ticket die E-Mail gehört und diese sollte dann zu dem Ticket hinzugefügt werden.

Wir erinnern uns: Wenn eine E-Mail vom Posteingang in den als Ordner der Ticketverwaltung angegebenen Ordner gezogen wird, löst das die Ereignisprozedur objItems_Item-Add aus. In dieser rufen wir dann die Prozedur Mail-Einlesen auf, in der wir die Informationen aus der E-Mail verarbeiten und diese dann in die Tabelle tblMailItems eintragen. Wenn ein Benutzer eine E-Mail schickt, mit der er auf eine unserer Antworten antwortet, sollte diese im Betreff einen Text wie [Ticketx] enthalten, wobei x für die Ticketnummer steht.

Dies wollen wir in der Prozedur Mail-Einlesen nun vorab prüfen, um die Mail direkt als Antwort in einem vorhandenen Ticket einpflegen zu können.

Dazu erweitern wir die Prozedur MailEinlesen zunächst wie folgt:

Public Sub MailEinlesen(...)
     ...
     If InStr(1, objMailItem.Subject, "[Ticket") = 0 Then
         ...
     Else
         AntwortZuTicketZuordnen objMailItem
     End If
End Sub

Wir fassen also die bestehenden Anweisungen in den If-Teil einer If…Then-Bedingung ein, in der wir prüfen, ob der Betreff der E-Mail den Text [Ticket enthält. Ist dies nicht der Fall, verarbeiten wir die Mail wie bisher als mögliches neues Ticket. Anderenfalls rufen wir im Else-Teil die Prozedur AntwortZuTicketZuordnen auf und übergeben dieser einen Verweis auf das MailItem-Objekt.

Diese Prozedur finden Sie in Listing 3. Sie nimmt das MailItem-Objekt als Parameter entgegen. Dann liest Sie den Inhalt der Eigenschaft Subject der E-Mail in die Variable strBetreff ein. Sie ermittelt mit der InStr-Funktion die Position der Zeichenfolge [Ticket und speichert diese in der Variablen intStart. Dann sucht sie im Betreff nach der schließenden eckigen Klammer und trägt die Position in die Variable intEnde ein.

Public Sub AntwortZuTicketZuordnen(objMailItem As Outlook.MailItem)
     Dim db As DAO.Database
     Dim strBetreff As String
     Dim intStart As String
     Dim intEnde As String
     Dim lngTicketID As Long
     Dim lngAktionKundenantwortID As Long
     Dim lngMailItemID As Long
     strBetreff = objMailItem.Subject
     intStart = InStr(1, strBetreff, "[Ticket")
     intEnde = InStr(intStart + 7, strBetreff, "]")
     lngTicketID = Mid(strBetreff, intStart + 7, intEnde - intStart - 7)
     m_db.Execute "INSERT INTO tblMailItems(EntryID) VALUES('" & objMailItem.EntryID & "')", dbFailOnError
     lngMailItemID = m_db.OpenRecordset("SELECT @@IDENTITY").Fields(0)
     lngAktionKundenantwortID = m_db.OpenRecordset("SELECT AktionstypID FROM tblAktionstypen " _
         & "WHERE Aktionstyp='Kundenantwort'", dbOpenDynaset).Fields(0)
     m_db.Execute "INSERT INTO tblAktionen(TicketID, AktionstypID, Betreff, Inhalt, Aktionsdatum, MailItemID) " _
         & "VALUES(" & lngTicketID & ", " & lngAktionKundenantwortID & ", '" & objMailItem.Subject & "', '" _
             & objMailItem.Body & "', " & SQLDatum(objMailItem.ReceivedTime) & ", " & lngMailItemID & ")", dbFailOnError
    MsgBox "Die Antwort wurde als Aktion zum Ticket mit der Nummer '" & lngTicketID & "' hinzugefügt."
End Sub

Listing 3: Hinzufügen einer Antwort zu einem Ticket

Damit ausgestattet ermittelt sie den Zahlenwert zwischen der Zeichenfolge [Ticket und ] und speichert diese in der Variablen lngTicketID.

Nachdem wir nun wissen, zu welchem Ticket diese Antwort gehört, erledigen wir allerdings noch einen Zwischenschritt: Wir legen einen neuen Datensatz für diese E-Mail in der Tabelle tblMailItems an.

Diesem weisen wir lediglich den Wert der Eigenschaft EntryID der E-Mail für das gleichnamige Feld zu, damit wir von der Mail-ItemID auf die EntryID schließen und die Mail damit öffnen können. Den Primärschlüsselwert des neu angelegten Datensatzes in der Tabelle tblMailItems ermitteln wir wieder mit der Abfrage SELECT @@IDENTITY.

Wir wollen den neuen Eintrag in der Tabelle tblAktionen mit der AktionstypID versehen, welcher dem Aktionstyp Kundenantwort entspricht. Deshalb ermitteln wir zunächst die passende AktionstypID.

Das machen wir diesmal nicht mit der DLookup-Anweisung, da wir den Code ja in einem Modul des VBA-Projekts von Outlooks ausführen – und da gibt es keine Domänenfunktionen.

Also nutzen wir eine SELECT-Anweisung, die allerdings genauso gut funktioniert und uns die ID des Aktionstyps liefert und in die Variable lngAktionKundenantwortID schreibt.

Damit können wir dann einen neuen Eintrag zur Tabelle tblAktionen hinzufügen, dem wir die zuvor ermittelten Werte für die Felder TicketID, AktionstypID, Betreff, Inhalt, Aktionsdatum und MailItemID zuweisen.

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