Language: Deutsch English















Last Update: 2017 - 03 - 20





Serienemail mit Access, VBA und Outlook versenden

by Philipp Stiefel, ursprünglich veröffentlicht am 20. Juni 2016


VBA code und Briefumschläge, article header image

Wie du wahrscheinlich bereits gesehen hast, habe ich einige Beispiele und Artikel zum Versenden von Emails mit Access auf dieser Website. Jene beschäftigen sich mit verschiedenen Herausforderungen dieses Themas. Selbst wenn du noch nicht viel Erfahrung mit Access und VBA hast, kannst du davon profitieren sie zu lesen. Dennoch hast du vielleicht noch Schwierigkeiten alles in den Zusammenhang zu setzen und eine vollständige, funktionierende Lösung zu erstellen, um Email aus deiner Datenbank zu versenden.

Wenn das vertraut klingt, dann ist diese Artikelserie für dich. Ich werde demonstrieren, wie man die Funktionalität um eine Serienemail aus Access zu versenden von Anfang bis Ende aufbauen kann. Angefangen mit dem Speichern der Emailadressen in der Datenbank, über das Abfragen der Adressen und weiterer Daten bis zum Erstellen von individuellen Email-Texten und dem Versenden der Emails über deinen Outlook Email-Account, wird alles behandelt.

Also, lass uns anfangen.

Emailadressen speichern

Emailadressen in einer Access Datenbank zu speichern ist recht einfach. – Solange du der Versuchung widerstehst, sie in einer Hyperlink-Spalte zu speichern.

Ich empfehle dir, den einfachen Kurzer Text Datentyp zu verwenden, um die Emailadressen zu speichern. Seine Maximallänge von 255 Zeichen sollte in der Regel für jede Emailadresse ausreichen.

Wenn du die Emailadressen in der Oberfläche deiner Anwendung klickbar und optisch wie einen Hyperlink darstellen möchtest, kannst du das mit entsprechender Formatierung und wenigen Zeilen VBA-Code erreichen.

Hier ist die Tabelle, die ich für den Rest des Artikels als Datengrundlage verwenden werde.

Datenblattansicht der Beispieltabelle Entwurfsansicht der Beispieltabelle

Eine Basisabfrage für den Newsletter erstellen

Der Rest dieses Artikels wird auf der Kunden-Tabelle basieren, die ich oben gezeigt habe. Weiterhin nehmen wir an, dass wir die Aufgabe haben einen Newsletter an die Kunden zu senden, die in unserer Datenbank gespeichert sind.

Wenn du dir die Tabelle genau angesehen hast, ist dir wahrscheinlich die NewsletterAbonniert-Spalte in der Tabelle aufgefallen. Wir sind keine Spammer. Wir werden unseren Newsletter nur an die Kunden versenden, die ihn auch bestellt haben.

Ein Basisprinzip der Datenbankentwicklung ist: Query only the data you need. – Frage nur die Daten ab, die du benötigst.

Wir wenden dieses Prinzip hier an. Also werden wir nicht einfach alle Kunden abfragen und dann in unserem VBA-Code prüfen, ob wir den Newsletter an den jeweiligen Kunden versenden sollen. Stattdessen verwenden wir eine Abfrage, und verarbeiten nur die Datensätze der Kunden, die den Newsletter abonniert haben.

Wir könnten einfach eine Ad-hoc SQL-Abfrage in unseren VBA-Code schreiben und direkt die Tabelle abfragen. Allerdings können wir eine gespeicherte Abfrage aller Newsletter-Abonnenten sicherlich auch an anderen Stellen in unserer Anwendung wiederverwenden. Daher erstellen wir zuerst diese Abfrage und speichern sie für die spätere Verwendung.

Dafür sind die folgenden Schritte nötig. Im Erstellen Ribbon klicke auf den Abfrageentwurf Button, dann füge die tblKunde zu der Abfrage hinzu und wähle alle Spalten für die Ausgabe aus. Dann erstelle ein Filterkriterium Wahr für die Spalte NewsletterAbonniert. Speichere die fertige Abfrage dann unter dem Name qryKunden_NewsletterAbonniert.

Wenn du Anfänger in der Access-Entwicklung bist und mit dem Vorgehen nicht vertraut bist, kannst du dir dieses kurze Video anschauen in dem ich das Vorgehen aufgezeichnet habe.

Den VBA-Code schreiben

Jetzt kommen wir zum essenziellen Teil des Artikels; der eigentlichen VBA-Programmierung.

Um den Code zu schreiben, öffne den VBA-Editor, erstelle ein neues Modul und speichere es unter dem Namen modSerialEmail. Dann erstelle eine neue Public Sub Prozedur, die du SendSerialEmail nennst.

Ich werde den Code in drei Durchgängen schreiben und mich in jedem Durchgang nur auf einen Aspekt der Funktionalität konzentrieren.

  1. Ein Recordset abrufen und in einer Schleife die Datensätze durchlaufen
  2. String-Variablen für unsere Email mit den Inhalten des aktuellen Datensatzes aufbauen
  3. Die eigentliche Email (Outlook.Mailtitem) erstellen und absenden

Besonders wenn du Anfänger in der Programmierung bist, ist es ein sinnvolles Vorgehen den Code in mehreren Durchgängen zu schreiben. Du kannst dich dann immer ganz auf die jeweils anstehende Teilaufgabe konzentrieren. Darin sehe ich zwei wesentliche Vorteile.

  • Du verminderst das Risiko am Anfang etwas zu vergessen, dass später schwer zu entdecken ist, wenn deine VBA-Prozedur mehr Code enthält.
  • Wenn du mit der Teilaufgabe anfängst, mit der du zumindest ein wenig vertraut bist, kannst du dabei deinen Code besser strukturieren. Dadurch erhältst du ein klareres Bild von der gesamten Prozedur an der du gerade arbeitest.

Kompiliere (Menü DebuggenKompilieren) deinen Code nach jedem Durchgang und führe ihn wenn möglich auch aus. Dabei sollten keine Fehler auftreten. Wenn doch ein Fehler auftritt, kannst du die Ursache einfacher finden, da du dich bei der Fehlersuche primär auf die neu geschriebenen Teile deines Codes konzentrieren kannst.

Die Datensätze in einer Schleife durchlaufen

Um Datensätze aus einer Tabelle oder Abfrage in VBA zu verarbeiten, benötigen wir ein Recordset. Ein Recordset ist ein Objekt, das die Daten einer Abfrage enthält. Es wird mit der OpenRecordset-Methode des Database-Objektes auf Basis einer SQL-Abfrage (oder dem Namen einer Tabelle) erstellt und geöffnet. Wir verwenden die CurrentDb-Methode, um eine Referenz auf die aktuell geöffnete Datenbank zu erhalten.

Als nächstes schreiben wir eine Do-Loop-Schleife, um durch alle Datensätze zu laufen (MoveNext), bis wir das Ende des Recordset (EOF) erreicht haben. Zum Schluss schließen wir das Recordset mit der Close-Methode und zerstören dann unsere Objektvariablen, indem wir sie auf Nothing setzen.

Der resultierende Code sieht dann etwa so aus:

Public Sub SendSerialEmail() Dim db As DAO.Database Dim rs As DAO.Recordset Set db = CurrentDb Set rs = db.OpenRecordset("SELECT Firstname, LastName, EmailAddress, IsVIP " & _ " FROM qryCustomer_SubscribedToNewsletter") Do Until rs.EOF rs.MoveNext Loop rs.Close Set rs = Nothing Set db = Nothing End Sub

Dieser VBA-Code sieht ordentlich aus, kompiliert und läuft ohne Fehler, aber er tut effektiv noch nichts.

Die Texte für Betreff und Emailtext zusammensetzen

Lass uns nun mit dem zweiten Durchgang weitermachen. Wir werden jetzt die Strings, die wir für die Email benötigen, zusammensetzen.

Technisch ist es nicht zwingend erforderlich, die Texte zuerst Variablen zuzuweisen. Wir könnten sie auch direkt den Eigenschaften des Mailitems zuweisen. Variablen zu verwenden, macht unseren Code einfacher verständlich und einfacher zu debuggen, falls etwas nicht so funktioniert, wie wir uns das vorstellen.

Ich empfehle den Ansatz mit Variablen bei der String-Verkettung zu verwenden, außer es handelt sich um ganz einfache Verkettungen.

Ein paar Allgemeine Dinge zur String-Verkettung, die du wissen solltest.

  • In Visual Basic wird das kaufmännische Und-Symbol (&) verwendet, um Strings zu verketten.
  • Du kannst einen Unterstrich an das Zeilenende setzen, um eine Anweisung auf der nächsten Zeile fortzusetzen. Das ist sehr nützlich um lange Anweisungen besser lesbar zu machen.
  • Um Text an eine bereits gefüllte Stringvariable anzuhängen, verkettest du die Variable mit dem neuen Text. Das sieht so aus: meineVariable = meineVariable & "neue Daten".

Nun zur tatsächlichen Programmierung. Ich deklariere die Variablen emailTo, emailSubject und emailText. Alle sind Strings. Dann füge ich den Code ein, um die Variablen mit den Werten aus dem Recordset zu füllen. Das muss innerhalb des Do-Until-Loops passieren, um die Werte aus dem jeweils aktuellen Datensatz zu erhalten.

Es würde ausreichen einfach nur die Emailadresse in emailTo zu speichern, aber es sieht professioneller aus den vollen Namen und die Adresse zu verwenden. Wenn man das so macht, muss jedoch die eigentliche Emailadresse in spitze Klammern eingeschlossen werden.

Der Spalte Vorname in dieser Datenbank lässt Null-Werte zu. Daher könnte es Kunden geben, deren Vorname nicht in der Tabelle gespeichert ist. Das würde zu einem führenden Leerzeichen vor dem Nachnamen in emailTo führen. Da das mistig aussieht, verwende ich die Trim-Funktion, um alle Leerzeichen vor und hinter dem Namen zu entfernen.

Als nächstes kommt der Betreff der Email. Ich füge den Namen des Kunden in den Betreff ein. – Ich bin nicht sicher, ob das eine gute Idee in einer echten Email wäre, aber tue es hier um das Vorgehen zu demonstrieren. Ich verwende eine If-Anweisung mit der IsNull-Funktion um den Namen nur dann hinzuzufügen, wenn auch der Vorname vorhanden ist, nur mit dem Nachnamen würde das zu „spammy“ aussehen.

Zuletzt schreibe ich den beabsichtigten Email-Text in die emailText Variable. Ich spreche den Empfänger mit dem Vornamen an und verwende erneut die Trim-Funktion, um das folgende Leerzeichen bei fehlendem Vornamen zu entfernen. Falls es sich um einen VIP-Kunden handelt (IstVIP), füge ich noch einen Text-Hinweis auf ein spezielles Angebot hinzu. Der danach folgende, eigentliche Email-Text ist nur ein Lorem-Ipsum-Fülltext.

Hier ist der Code dazu:

Public Sub SendSerialEmail()
Dim db As DAO.Database Dim rs As DAO.Recordset
Dim emailTo As String Dim emailSubject As String Dim emailText As String
Set db = CurrentDb Set rs = db.OpenRecordset("SELECT Firstname, LastName, EmailAddress, IsVIP " & _ " FROM qryCustomer_SubscribedToNewsletter") Do Until rs.EOF
emailTo = Trim(rs.Fields("FirstName").Value & " " & rs.Fields("LastName").Value) & _ " <" & rs.Fields("EmailAddress").Value & ">" emailSubject = "Amazing newsletter" If IsNull(rs.Fields("FirstName").Value) Then emailSubject = emailSubject & " for " & _ rs.Fields("FirstName").Value & " " & rs.Fields("LastName").Value End If emailText = Trim("Hi " & rs.Fields("FirstName").Value) & "!" & vbCrLf If rs.Fields("IsVIP").Value Then emailText = emailText & "Here is a special offer only for VIP customers!" & _ "Only this month: Get the foo widget half price!" & vbCrLf End If emailText = emailText & _ "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. " & _ "Maecenas porttitor congue massa. Fusce posuere, magna sed " & _ "pulvinar ultricies, purus lectus malesuada libero, sit amet " & _ "commodo magna eros quis urna."
rs.MoveNext Loop rs.Close Set rs = Nothing Set db = Nothing
End Sub

Der Code sieht immer noch ordentlich aus, lässt sich immer noch ohne Fehler kompilieren und ausführen und tut effektiv immer noch nichts.

Die Email erstellen und senden

Ok, wir sind an dem kritischen Punkt angekommen. Es ist an der Zeit die eigentliche Email zu erstellen und zu senden.

Bevor du irgendwelchen Code schreibst und/oder ausprobierst der Emails verschickt, vergewissere dich, dass…

  • du eine Test-Datenbank mit nur einigen wenigen Datensätzen verwendest oder dass zumindest deine Abfrage nur wenige Test-Datensätze liefert.
  • Outlook so konfiguriert hast, dass Emails nicht automatisch direkt gesendet werden. – Weder sofort noch zeitgesteuert alle x Minuten.

Teste deine Outlook-Konfiguration indem du manuell eine Email an dich selbst oder einen Kollegen sendest, bevor du den Email-Code testest.

Es ist wirklich peinlich, aus Versehen sinnfreie Test-Emails an hunderte deiner Kunden zu senden. – Also sei vorsichtig hier!

Bevor wir richtig loslegen, setzen wir einen Verweis auf die Outlook-Objektbibliothek. Dazu klicke das Menü ExtrasVerweise im VBA-Editor. Suche nach der Microsoft Outlook x.xx Object Library (x.xx ist die Versionsnummer und abhängig davon welche Version von Outlook du installiert hast.), hake diese Bibliothek an und bestätige den Dialog mit OK.

Verweis auf die Outlook Objektbibliothek setzen

Jetzt können wir unsere Variablen deklarieren; outApp (Outlook.Application), outMail (Outlook.MailItem) and outStarted (Boolean). Diese sollten weitgehend selbsterklärend sein. Zu outStarted komme ich gleich.

Wir verwenden die GetObject-Funktion, um eine Referenz auf eine bereits laufende Outlook-Instanz zu bekommen. Dies wird natürlich fehlschlagen, wenn Outlook nicht läuft. Dies berücksichtigend, verwenden wir unmittelbar vorher eine On Error Resume Next Anweisung, um die VBA-Umgebung anzuweisen, den Fehler zu ignorieren und die nächste Anweisung auszuführen. Direkt nach der Anweisung setzen wir den Error-Handler mit On Error Goto 0 zurück.

Wenn GetObject fehlgeschlagen ist, ist unsere outApp Variable nicht gesetzt (= Is Nothing). In diesem Fall erstellen wir eine neue Outlook-Instanz mit der CreateObject-Funktion und setzen outStarted auf True. Letzteres dient nur dem Zweck zu wissen, dass wir (unser Code) Outlook gestartet haben und nicht der Benutzer selbst.

Wir benötigen nur eine einzige Outlook-Application-Instanz für eine beliebige Anzahl an Emails. Daher füge ich diesen Code noch vor der Do-Until-Schleife, direkt nach der Variablendeklaration ein.

Der Code, der jeweils die Email erstellt und sendet, muss für jeden einzelnen Datensatz aus unserer Abfrage erneut ausgeführt werden. Also muss dieser Code innerhalb der Schleife stehen. Da wir in dem Code die Texte aus unseren String-Variablen benötigen, fügen wir den Code am Ende der Schleife ein, wo alle Variablen bereits gesetzt sind.

Wir verwenden die CreateItem-Methode, um ein neues Mailitem-Objekt zu erzeugen. Dann setzen wir die To-, Subject- und Body-Eigenschaft auf die Werte unserer Strings. Zuletzt rufen wir die Send-Methode auf, um die Email zu senden.

In dem Aufräum-Code hinter der Schleife schließen wir Outlook nur dann mit der Quit-Methode, wenn wir (unser Code) es auch gestartet hat. Nur in diesem Fall ist outStarted = True.

Hier ist jetzt endlich der vollständige und funktionierende Code unserer Sub Prozedur.

Public Sub SendSerialEmail()
Dim db As DAO.Database Dim rs As DAO.Recordset Dim emailTo As String Dim emailSubject As String Dim emailText As String
Dim outApp As Outlook.Application Dim outMail As Outlook.MailItem Dim outlookStarted As Boolean On Error Resume Next Set outApp = GetObject(, "Outlook.Application") On Error GoTo 0 If outApp Is Nothing Then Set outApp = CreateObject("Outlook.Application") outlookStarted = True End If
Set db = CurrentDb Set rs = db.OpenRecordset("SELECT Firstname, LastName, EmailAddress, IsVIP " & _ " FROM qryCustomer_SubscribedToNewsletter") Do Until rs.EOF emailTo = Trim(rs.Fields("FirstName").Value & " " & rs.Fields("LastName").Value) & _ " <" & rs.Fields("EmailAddress").Value & ">" emailSubject = "Amazing newsletter" If IsNull(rs.Fields("FirstName").Value) Then emailSubject = emailSubject & " for " & _ rs.Fields("FirstName").Value & " " & rs.Fields("LastName").Value End If emailText = Trim("Hi " & rs.Fields("FirstName").Value) & "!" & vbCrLf If rs.Fields("IsVIP").Value Then emailText = emailText & "Here is a special offer only for VIP customers!" & _ "Only this month: Get the foo widget half price!" & vbCrLf End If emailText = emailText & _ "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. " & _ "Maecenas porttitor congue massa. Fusce posuere, magna sed " & _ "pulvinar ultricies, purus lectus malesuada libero, sit amet " & _ "commodo magna eros quis urna."
Set outMail = outApp.CreateItem(olMailItem) outMail.To = emailTo outMail.Subject = emailSubject outMail.Body = emailText outMail.Send
rs.MoveNext Loop rs.Close Set rs = Nothing Set db = Nothing
If outlookStarted Then outApp.Quit End If Set outMail = Nothing Set outApp = Nothing End Sub

Jetzt nachdem der Code vollständig ist, sieht er immer noch relativ übersichtlich und einfach aus, oder?

Die Strukturierung des Codes zahlt sich jetzt wirklich aus. Wenn du ein Anfänger in der VBA-Programmierung bist, wäre es im Vorfeld evtl. eine einschüchternde Aufgabe gewesen, den Code für den Emailversand zu schreiben. Aber sieh dir nun an, wie wenige Zeilen Programmcode tatsächlich dafür erforderlich sind. Jetzt sollte alles verständlich und wesentlich weniger einschüchternd sein.

Wenn du mir zusehen möchtest, wie ich diesen Code programmiere, dann ist hier ein Video für dich.

If you would like to watch me actually writing the code, then here is a video for you.

Schlusswort

Wir haben funktionierenden Code geschrieben, um mit Outlook eine Email zu erstellen und zu senden. Wenn du aufmerksam auf die ganzen weiterführenden Informationen geachtet hast, die ich hier einbezogen habe, wirst du noch einiges mehr gelernt haben.

Am wertvollsten ist der Ansatz, wie du den Code strukturieren kannst, damit er gut lesbar und einfach zu debuggen ist. Dies wird dir dabei helfen Code für jeden beliebigen Zweck zu schreiben. Selbst wenn du meinen Ansatz nicht direkt vollständig übernimmst, solltest du den Wert darin erkennen, deinen Code über die rein technischen Anforderungen hinaus sinnvoll und nachvollziehbar zu strukturieren.

Vielen Dank fürs Lesen. Wenn dir dieser Artikel gefallen hat, teile Ihn bitte mit deinen Freunden und Kollegen.

Share this article: Share on Facebook Tweet Share on LinkedIn Share on XING

Abonniere meinen Newsletter

*

Ich werde Deine Email-Addresse niemals weitergeben. Du kannst den Newsletter jederzeit abbestellen.



© 1999 - 2016 by Philipp Stiefel