Office 365: Mails auslesen
Nachfolgend ein kleines Tutorial, was gemacht werden muss und benötigt wird, um Mails mit Hilfe eines C#-Services und einer Azure App aus unterschiedlichen Office365-Mandanten auszulesen. Dabei werde ich auch auf ein paar relevante Details in Azure eingehen, die hierfür benötigt werden.
Alles, was nicht unbedingt wichtig ist, werde ich in diesem Tutorial nicht erwähnen, um es kurz zu halten (wie z. B. Einstellungen unter Branding, …).
Azure App erstellen
Als erstes muss im Azure Portal unter „Azure Active Directory“ ⇒ „App registration“ eine neue App erstellt werden. Dieser wird ein Name gegeben und der passende „Supported account type“ ausgewählt.
Accounts in this organizational directory only: Die Anwendung steht nur dem aktuellen Mandat zur Verfügung.
Accounts in any organizational directory: Die Anwendung steht allen Business-Kunden zur Verfügung.
Accounts in any organizational directory and personal Microsoft accounts: Die Anwendung kann zusätzlich zur vorherigen Einstellung auch von privaten Microsoft-Accounts verwendet werden.
Anschließend kann diese mit Klick auf „register“ erstellt werden.
Unter „Overview“ wird die „Application (client) ID“ angezeigt. Diese können wir uns schon mal auf die Seite kopieren, da wir sie später im C#-Programm benötigen.
Nun müssen die benötigten Berechtigungen hinterlegt werden. Dies wird im Punkt „API permissions“ ⇒ „Add a permission“ gemacht. Nachdem die Mails mit Hilfe von „Microsoft Graph“ ausgelesen werden, muss dieses unter „Microsoft APIs“ angeklickt werden.
Nun kommt eine Abfrage, welche Art von Berechtigung benötigt wird.
Delegated Permissions: Diese werden für Anwendungen mit angemeldetem Benutzer verwendet (= on behalf of). Der Benutzer selbst oder der Administrator bestätigt die von der Anwendung gewünschten Berechtigungen. Hierbei handelt es sich um die initialen Berechtigungen (auch Scopes genannt).
Benötigt die Anwendung zu einem späteren Zeitpunkt mehr Rechte, dann müssen diese ebenfalls zusätzlich vom Benutzer bestätigt werden. Hierfür ist es allerdings nicht notwendig, dass diese zwingend in der Application Registration hinterlegt sind.
Application Permissions: Diese Berechtigungen sind bspw. für Hintergrundanwendungen gedacht, bei denen es keinen angemeldeten Benutzer gibt.
Da unsere C#-Anwendung im Hintergrund arbeitet, verwenden wir hier „Application permissions“. Nun können unter „Mail“ die Rechte gesetzt werden. Im Normalfall ist es sinnvoll, zusätzlich unter „User“ noch den Punkt „User.Read.All“ auszuwählen, damit die Benutzer des Mandanten abgefragt werden können.
Das Ergebnis sollte dann in etwa so aussehen (je nachdem, was die Anwendung konkret macht):
Als letzten Schritt erstellen wir noch einen Secret, mit dem sich unsere C#-Anwendung zukünftig anmelden kann. Dies wird unter „Certificates & secrets“ ⇒ „New client secret“ gemacht. Wichtig: der Value muss direkt nach dem Erstellen des Secrets irgendwo sicher gespeichert werden, da dieser zukünftig nicht mehr ausgelesen werden kann.
Das war auch schon der Teil, der in Azure gemacht werden muss.
C#-Anwendung erstellen
Als Nächstes erstellen wir unsere C#-Anwendung. In diese müssen folgende NuGet-Pakete eingebunden werden:
- Microsoft.Graph
- Microsoft.Identity.Client
Und hier der benötigte Code:
var clientId = "";
var clientSecret = "";
var tenant = "";
var scopes = new string[] { "https://graph.microsoft.com/.default" };
var confidentialClient = ConfidentialClientApplicationBuilder
.Create(clientId)
.WithAuthority($"https://login.microsoftonline.com/{tenant}/v2.0")
.WithClientSecret(clientSecret)
.Build();
var client = new GraphServiceClient(new DelegateAuthenticationProvider(async (requestMessage) =>
{
var authResult = await confidentialClient
.AcquireTokenForClient(scopes)
.ExecuteAsync();
requestMessage.Headers.Authorization = new AuthenticationHeaderValue(
"Bearer",
authResult.AccessToken);
}));
var users = await client
.Users
.Request()
.GetAsync();
var user = users.FirstOrDefault();
var messages = await client
.Users[user.Id]
.MailFolders["inbox"]
.Messages
.Request()
.GetAsync();
Wer genau aufgepasst hat, dem sollte aufgefallen sein, dass uns in dem Code ein Wert fehlt: „tenant“. Nachdem wir die Emails nicht aus unserem eigenen Office365 auslesen möchten, sondern aus anderen (z. B. dem unserer Kunden), benötigen wir hier den Tenant von diesem. Das alleine reicht allerdings noch nicht, zuerst muss ein Administrator von diesem unserer Azure App die Rechte geben, damit wir das dürfen.
Azure App berechtigen
Dieser Vorgang ist denkbar einfach. Der Administrator des Kunden muss die folgende URL öffnen (die zwei Parameter natürlich entsprechend ersetzt):
https://login.microsoftonline.com/common/adminconsent?client_id={CLIENT_ID}&state={IRGENDWAS}
Im Produktivfall würde man die URL noch um „&redirect_uri=https://myurl/response-irgendwas“ erweitern. Diese URL muss allerdings in der Azure App Registrierung ebenfalls angegeben werden. Dadurch sendet Azure nach erfolgreicher Authentifizierung die Tenant-ID des Kunden an diese URL. Alternativ kann unser Kunde uns diese bekanntgeben („Azure Active Directory“ ⇒ Overview).
Die Logik dahinter ist ebenfalls recht einfach. Bei der Registrierung der App wird eine „Enterprise Application“ erstellt – diese ist eigentlich nichts anderes als ein Service Principal. Im Zuge der Bestätigung im vorherigen Schritt wird erhält der Service Principal die Rechte zugeordnet.
Fazit
Eigentlich ist das Ganze nicht schwierig, wenn man weiß, was man wie/wo machen muss ;).
Der C#-Code stellt selbstverständlich keine fertige Lösung dar. Beispielsweise würde nicht bei jedem Request der Token neu ermittelt, sondern auf die Gültigkeit dieses geprüft und nur dann erneuert, wenn notwendig.
Nachtrag
Wer statt Microsoft Graph den Zugriff über EWS (Exchange Web Services) möchte, muss in der Azure App unter Manifest im Bereich „requiredResourceAccess“ folgenden Eintrag einfügen:
{
"resourceAppId": "00000002-0000-0ff1-ce00-000000000000",
"resourceAccess": [
{
"id": "dc890d15-9560-4a4c-9b7f-a736ec74ec40",
"type": "Role"
}
]
}
Dies erzeugt den Eintrag „Office 365 Exchange Online“ => „full_access_as_app“.
Der Zugriff kann dann bspw. mit Aspose.Email oder Independentsoft.Exchange gemacht werden oder noch besser direkt über Microsoft Graph, wofür es das NuGet-Paket Microsoft.Graph gibt.