Im Beitrag „Outlook.com mit Access und VBA: Vorbereitungen“ haben wir gezeigt, wie wir die Voraussetzungen für den Zugriff auf unser Outlook-Konto mit der Rest-API von Microsoft erschaffen. Dabei haben wir eine Anwendung bei Microsoft registriert und die notwendigen Daten wie die Application-ID, die Tenant-ID und die SecretID ermittelt, die wir für den Zugriff auf die Rest-API benötigen. Außerdem haben wir dort die benötigten Berechtigungen eingestellt, hier erst einmal für das Senden von E-Mails. Was wir nun benötigen, sind zwei Dinge: Erstens ein Token, das wir für die Authentifizierung bei der Rest-API benötigen, zweitens den VBA-Code für die Ausführung der eigentlichen Rest-API-Aufrufe. Damit erstellen wir eine erste Prozedur, mit der wir E-Mails über unser Outlook.com-Konto versenden können. Darauf aufbauend werden wir in weiteren Beiträgen zeigen, wie wir weitere Funktionen implementieren können.
Die Ergebnisse des Beitrags Outlook.com mit Access und VBA: Vorbereitungen (www.access-im-unternehmen.de/1531) sehen wie folgt aus:
- Wir haben eine neue App registriert.
- Wir haben für die Anwendung die Anwendungs-ID (ApplicationID), die Verzeichnis-ID (TenantID) und den geheimen Client-Schlüssel (SecretID) ermittelt und in VBA-Konstanten gespeichert.
- Wir haben die Berechtigungen für die neue App so eingestellt, dass wir damit E-Mails versenden können (Mail.Send).
Damit steigen wir nun in die Programmierung des Zugriffs auf die Microsoft Graph API für den Zugriff auf unser Outlook-Konto ein.
Dazu führen wir folgende Schritte durch:
- Wir fügen die notwendigen Verweise hinzu.
- Wir fügen zwei Module hinzu, die Funktionen für den Umgang mit JSON-Dokumenten liefern.
- Wir erstellen eine Basisfunktion zum Durchführen von Rest-API-Aufrufen.
- Wir erstellen eine Funktion, mit der wir den Authentifizierungstoken für den Zugriff auf die Rest-API holen können.
- Wir erstellen eine Funktion, mit der wir eine E-Mail versenden können.
Verweise hinzufügen
Wir benötigen die folgenden beiden Verweise:
- Microsoft Scripting Runtime
- Microsoft XML, v6.0
Der Verweise-Dialog sieht nach dem Hinzufügen dieser Verweise wie in Bild 1 aus.
Bild 1: Verweise, die wir für den Zugriff auf die Rest-API benötigen
Module hinzufügen
Wenn Sie die Beispieldatenbank neu aufbauen wollen, fügen Sie nun aus unserer Datenbank die beiden Module mdlJSON und mdlJSONDOM hinzu.
Das erste enthält Methoden, um JSON-Dokumente in ein Objektmodell zu überführen und um JSON-Dokumente wieder aus diesem Objektmodell auszulesen.
Das zweite bietet die Möglichkeit, die Anweisungen auszugeben, die für den Zugriff aller Elemente dieses Objektmodells nötig sind. Die genaue Funktionsweise zeigen wir gleich im Praxiseinsatz.
Token für die Authentifizierung holen
Es gibt verschieden aufwendige Zugriffsarten für Rest-APIs.
Manche begnügen sich damit, dass man ein API-Kennwort auf der Webseite des Anbieters holt und dieses in seinen Aufruf einbettet.
Andere erfordern es, dass man mit den Daten wie der Anwendungs-ID und einem geheimen Schlüssel erst noch ein Authentifizierungstoken holt, mit dem man dann den eigentlichen Aufruf durchführen kann. Dies ist hier der Fall, da wir im Kontext der Anwendung auf die Methoden wie Mail.Send zugreifen.
Einen Schritt weiter gehen wir, wenn wir eine Anwendung für den Zugriff auf eine Rest-API bauen, die im Kontext eines Benutzers verwendet werden soll. Dann müssten wir zum Holen des Authentifizierungstokens erst noch eine Webseite anzeigen, auf der sich der Benutzer authentifiziert, bevor wir das Token erhalten. Auch dies ist bei der Rest-API möglich, die wir hier ansteuern wollen.
Für unsere Zwecke reicht allerdings die Methode aus, mit der wir auch das Token über die Rest-API holen.
Das erledigen wir mit der Funktion aus Listing 1. Die Funktion hat zwei Parameter:
Function GetAccessToken(strToken As String, strResponse As String) As Boolean Dim objXMLHTTP As MSXML2.XMLHTTP60 Dim objJSON As Object Dim strURL As String Dim strData As String Dim strJSON As String strURL = "https://login.microsoftonline.com/" & cStrTenantID & "/oauth2/v2.0/token" strData = "grant_type=client_credentials" & _ "&client_id=1" & cStrApplicationID & _ "&client_secret=" & cStrSecretValue & _ "&scope=https://graph.microsoft.com/.default" Set objXMLHTTP = CreateObject("MSXML2.XMLHTTP") objXMLHTTP.Open "POST", strURL, False objXMLHTTP.setRequestHeader "Content-Type", "application/x-www-form-urlencoded" objXMLHTTP.Send strData Select Case objXMLHTTP.status Case 200 strJSON = objXMLHTTP.responseText Set objJSON = ParseJson(strJSON) GetAccessToken = True strToken = objJSON("access_token") Case Else strJSON = objXMLHTTP.responseText Set objJSON = ParseJson(strJSON) strResponse = objJSON.Item("error_description") Debug.Print GetJSONDOM(strJSON, True) End Select End Function
Listing 1: Funktion zum Holen des Access-Tokens
- strToken: Wird bei erfolgreichem Aufruf mit dem Token gefüllt.
- strResponse: Wird im Fehlerfall mit der Fehlermeldung gefüllt.
Das Ergebnis der Funktion selbst ist ein Boolean-Wert. Ist dieser True, war der Abruf des Tokens erfolgreich, anderenfalls liefert die Funktion den Wert False zurück.
Die Funktion deklariert zunächst eine Objektvariable des Typs XMLHTTP60. Diese ermöglicht den Zugriff auf die Rest-API. In objJSON speichern wir das Objektmodell der Antwort im JSON-Format. strURL nimmt die Adresse des Endpunktes der Rest-API auf und strData die zu übergebenden Parameter. In strJSON speichern wir schließlich das Ergebnis des Aufrufs.
Die Funktion trägt als Erstes die URL für den Endpunkt der Rest-API in die Variable strURL ein. Diese besteht aus der Zeichenkette https://login.microsoftonline.com/, der Tenant-ID sowie der Zeichenkette /oauth2/v2.0/token.
Insgesamt sieht die URL beispielsweise wie folgt aus:
https://login.microsoftonline.com/dcc87x1c-44xb-43x8-9x0d-xa1cxxxxxxxx/oauth2/v2.0/token
Danach folgt die Variable strData, in der wir die übrigen für die Authentifizierung benötigten Informationen einarbeiten.
Der darin gespeicherte Ausdruck sieht anschließend wie folgt aus:
grant_type=client_credentials&client_id=15bddxdx5-xbf3-x248-bxaa-fd41x6xb18xd&client_secret=6Ax8Q~ZxDxItTxAlycqxPcY6kxZnpfxzitTxca2e&scope=https://graph.microsoft.com/.default
Damit erstellen wir nun eine Instanz von MSXML2.XMLHTTP und referenzieren diese mit der Variablen objXMLHTTP.
Wir rufen die Open-Methode dieses Objekts auf und übergeben drei Parameter:
- bstrMethod: Methode des Zugriffs, in diesem Fall POST
- bstrURL: URL, hier aus der Variablen strURL
- varAsync: Gibt an, ob der Aufruf synchron oder asynchron erfolgen soll, hier False für einen synchronen Aufruf.
Mit der setRequestHeader-Eigenschaft legen wir den Wert für das Attribut Content-Type fest, hier auf application/x-www-form-urlencoded.
Schließlich senden wir die Anfrage mit der Send-Methode und dem Parameter strData ab.
Durch die Angabe, dass wir einen synchronen Aufruf starten wollen, wird der Code erst fortgesetzt, wenn der Aufruf beendet ist und das XMLHTTP-Objekt das Ergebnis enthält.
Wir können dann anhand der Eigenschaft Status ermitteln, ob der Aufruf erfolgreich war oder ob ein Fehler aufgetreten ist. Liefert Status den Wert 200 zurück, war der Aufruf erfolgreich.
In diesem Fall erhalten wir mit objXMLHTTP.responseText die folgende Antwort (hier in gekürzter Form), die wir anschließend in die Variable strJSON schreiben:
{"token_type":"Bearer","expires_in":3599,"ext_expires_in":3599,"access_token":"eyJ0e...5_7xA"}
Wir erstellen daraus mit der Funktion ParseJson ein Objektmodell, das wir mit der Variablen objJSON referenzieren und stellen als Rückgabewert der Funktion den Wert True ein.
Außerdem tragen wir für den Rückgabeparameter strToken das Ergebnis des Ausdrucks objJSON(„access_token“) ein.
Woher wissen wir, dass wir diesen Ausdruck aufrufen müssen, um das Token auszulesen?
Dazu können wir die folgende Zeile zwischenschalten:
Debug.Print GetJSONDOM(strJSON, True)
Dies liefert das folgende Ergebnis im Direktbereich des VBA-Editors:
objJSON.Item("token_type"):Bearer objJSON.Item("expires_in"):3599 objJSON.Item("ext_expires_in"):3599 objJSON.Item("access_token"):eyJ0eXAiOi...jmubh-6KQ
GetJSONDOM hat die Aufgabe, den Inhalt des Objektmodells aus objJSON dahingehend zu analysieren, dass es die Aufrufe ausgibt, die nötig sind, um die entsprechenden Inhalte abzurufen. Durch das Einstellen des zweiten Parameters bolValues auf den Wert True werden wie oben angezeigt auch die Werte ausgegeben.
Wenn wir nun gezielt den Wert des Tokens auslesen wollen, müssen wir also auf objJSON.Item(„access_token“) zugreifen. Wichtig ist, dass wir zuvor mit Set objJSON = ParseJSON(strJSON) das Objektmodell erzeugt haben.
Wenn Status einen anderen Wert als 200 zurückgibt, beispielsweise 400 oder 401, ist offensichtlich ein Problem aufgetreten. In diesem Fall untersuchen wir die Antwort ebenfalls und schreiben den Wert aus objJSON.Item(„error_description“) als Rückgabewert in die Variable strResponse.
Zum Testen dieser Funktion können wir die folgende Prozedur nutzen:
Public Sub Test_GetAccessToken() Dim strToken As String Dim strResponse As String If GetAccessToken(strToken, strResponse) = True Then Debug.Print "Token erfolgreich geholt:" Debug.Print strToken Else Debug.Print "Token nicht geholt:" Debug.Print strResponse End If End Sub
Diese ruft die Funktion GetAccessToken mit den Parametern strToken und strResponse auf, die jeweils leer sind, und gibt die Ergebnisse aus.
E-Mail via Microsoft Graph API versenden
Damit können wir uns der eigentlichen Aufgabe widmen: Einer Prozedur, mit der wir per VBA eine E-Mail versenden und dabei die Microsoft Graph API nutzen.
Diese Prozedur finden wir in Listing 2.
Public Sub SendEmail() Dim objXMLHTTP As MSXML2.XMLHTTP60 Dim strUser As String Dim strURL As String Dim strToken As String Dim strBody As String Dim strResponse As String If GetAccessToken(strToken, strResponse) = True Then ''strURL = "https://graph.microsoft.com/v1.0/me/sendMail" strUser = "andre@andreminhorstverlag.onmicrosoft.com" strURL = "https://graph.microsoft.com/v1.0/users/" & strUser & "/sendMail" strBody = strBody & "{" & vbCrLf strBody = strBody & " ""message"": {" & vbCrLf strBody = strBody & " ""subject"": ""Test E-Mail""," & vbCrLf strBody = strBody & " ""body"": {" & vbCrLf strBody = strBody & " ""contentType"": ""Text""," & vbCrLf strBody = strBody & " ""content"": ""Dies ist eine Test-E-Mail über Microsoft Graph.""" & vbCrLf strBody = strBody & " }," & vbCrLf strBody = strBody & " ""toRecipients"": [" & vbCrLf strBody = strBody & " {" & vbCrLf strBody = strBody & " ""emailAddress"": {" & vbCrLf strBody = strBody & " ""address"": ""andre@minhorst.com""" & vbCrLf strBody = strBody & " }" & vbCrLf strBody = strBody & " }" & vbCrLf strBody = strBody & " ]" & vbCrLf strBody = strBody & " }," & vbCrLf strBody = strBody & " ""saveToSentItems"": ""true""" & vbCrLf strBody = strBody & "}" & vbCrLf Set objXMLHTTP = CreateObject("MSXML2.XMLHTTP") objXMLHTTP.Open "POST", strURL, False objXMLHTTP.setRequestHeader "Authorization", "Bearer " & strToken objXMLHTTP.setRequestHeader "Content-Type", "application/json" objXMLHTTP.Send strBody Select Case objXMLHTTP.status Case 202 MsgBox "E-Mail erfolgreich gesendet." Case Else MsgBox "Fehler beim Senden der E-Mail: " & objXMLHTTP.status & " - " & objXMLHTTP.responseText End Select End If End Sub
Listing 2: Prozedur zum Senden einer E-Mail
Die Prozedur deklariert wieder ein XMLHTTP60-Objekt sowie einige String-Variablen.
Sie ruft die Funktion GetAccessToken auf, um das Authentifizierungstoken zu holen. Gelingt dies, trägt sie die E-Mail-Adresse, die als Absenderadresse verwendet werden soll, in die Variable strUser ein.
Wir verwenden hier die Adresse, unter der auch das Microsoftkonto betrieben wird beziehungsweise die Microsoft für uns angelegt hat.
Diese Adresse fügen wir in die URL ein, die wir der Variablen strURL hinzufügen und die beispielsweise wie folgt aussieht:
https://graph.microsoft.com/v1.0/users/andre@andreminhorstverlag.onmicrosoft.com/sendMail
Dann stellen wir in der Variablen strBody die Eigenschaften und Inhalte der E-Mail zusammen. Der Inhalt sieht in diesem Fall danach wie folgt aus:
{ "message": { "subject": "Test E-Mail", "body": { "contentType": "Text", "content": "Dies ist eine Test-E-Mail über Microsoft Graph." }, "toRecipients": [ { "emailAddress": { "address": "andre@minhorst.com" } } ] }, "saveToSentItems": "true" }
Hier sehen wir bereits die wichtigsten Elemente einer E-Mail:
- subject: Betreff der E-Mail
- body: Inhalt der E-Mail mit einigen Unterelementen
- contentType: Format des Inhalts, hier Text. Alternativ: HTML.
- content: Eigentlicher Inhalt der E-Mail
- toRecipients: Auflistung aller To-Empfänger mit den Unterelementen emailAddress und address.
- saveToSentItems: Gibt an, ob die E-Mail in den gesendeten Objekten gespeichert werden soll.
Danach erstellt die Prozedur das XMLHTTP-Objekt und referenziert es mit der Variablen objXMLHTTP. Es öffnet das Objekt mit der Open-Methode und übergibt die bereits bekannten Parameter.
Sie fügt jedoch einen zusätzlichen RequestHeader namens Authorization hinzu, der die Zeichenkette Bearer und das zuvor ermittelte Token enthält.
Schließlich wird die Anfrage mit der Send-Methode und dem Inhalt aus strBody als Parameter abgesendet.
Das Ergebnis werten wir wieder in einer Select Case-Bedingung aus. Diesmal erhalten wir für die erfolgreiche Ausführung jedoch den Statuswert 202 zurück, was wir entsprechend berücksichtigen. Im Fehlerfall geben wir den Fehler als Meldung aus.
Hier ist der Versand jedoch erfolgreich und wir finden die E-Mail im Postfach des Empfängers wieder (siehe Bild 2).
Bild 2: Die erfolgreich gesendete E-Mail im neuen Outlook
Nächste Schritte
Nachdem wir die erste E-Mail erfolgreich versendet haben, können wir die nächsten Schritte angehen:
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