Table of Contents

pitFM Add-on - Microsoft Graph (MsGraphClient.dll)

Dieses Add-on dient zum Empfangen, Lesen und Verschieben von E-Mails über die Microsoft Graph API.

Technisches

Code-Respository: https://dev.azure.com/pit-cup/pitFM_Addons/_git/pitFM_MsGraphClient

Releaseverzeichnis: X:\FM\AddOns\MsGraphClient pitftp.de/pitFM_AddOns/MsGraphClient

Dieses Add-on wird vorerst als Merged-DLL geliefert, da pit erst ab Version 27 die Unterverzeichnisse für Add-ons unterstützt. Im AppConfig-Branch wird der Stand gehalten, mit welchem keine Merged-DLL erstellt wird. Dafür wird die AppConfig mit den Binding-Redirects erzeugt welche in die pitfm.exe.config übernommen werden können.

Info zum Common-Namespace

Alles, was unter Common liegt, soll ggf. mal in eine allgemeine pit-Bibliothek ausgelagert werden, da es in mehreren Addons benötigt wird. Hier ist es aktuell das Logging, was ggf. herausgelöst werden soll.

Logging

Ebene Aufgabe Welche Logs? Log-Level
Adapter Direkte Kommunikation mit der API - Request-Daten (ohne sensible Infos)
- Response-Statuscodes
- Fehler (Timeouts, Bad Requests, Server Errors)
Info (Erfolgreiche Requests)
Warning (Fehlerhafte Antworten)
Error (Timeouts, unerwartete Fehler)
Service Geschäftslogik und Fehlerhandling - Wichtige Aktionen in der App
- Ob API-Call erfolgreich war oder eine andere Strategie nötig ist
- Kontext der API-Nutzung (Warum wird der Call gemacht?)
Info (Erfolgreiche Verarbeitung)
Warning (Fehlversuche mit Fallback-Strategie)
Error (Wenn API-Fehler die Funktionalität beeinträchtigen)

WICHTIG

Folgendes muss beachtet werden, wenn pitFM nicht als strong named Variante verwendet wird. Die CliDefines.dll im pit-bin-Verzeichnis muss durch die strong named Variante ersetzt werden. Die notwendige strong named CliDefines.dll ist unter X:\FM\AddOns_CliDefines_strong_named zu finden. Diese ist kompatibel mit pitFM v21 - v26.

Release Notes

Version 1.1.0

  • Addon wurde in pitFM_MsGraphClient umbenannt.
  • E-Mails versenden inkl. Attachments. Inlinebilder werden nicht unterstützt.
  • Das Add-on unterstützt auch Proxy's.

Version 1.0.4

  • Inlinebilder werden als Attachments verfügbar gemacht.

Version 1.0.3

  • Die CliDefines wird unterstützt. Dadurch unterstützen die Pit-Funktionen das FctExport-Attribut.

Version 1.0.2

  • Das Logging/Tracing des Add-ons kann aktiviert und ein Log-Level definiert werden.
  • Das Error-Handling der pit-Methoden vervollständigt.

Version 1.0.1

  • Add-on wird als Merged-DLL geliefert

Version 1.0.0

  • Das Abfragen von E-Mails über MS Graph API ist implementiert.
  • Authentifizierung mittels Client-Secret und User-Login möglich.
  • E-Mails aus einem Postfach-Verzeichnis abrufen.
  • Gelesen-Status der E-Mail setzen.
  • Löschen der E-Mail verschiebt diese in den Ordner "Gelöschte Nachrichten".
  • Das Abrufen und Ablegen der E-Mail-Anhänge ist implementiert.
  • E-Mail-Anhänge werden mit gültigen Dateinamen im lokalen Dateisystem abgelegt. Ungültige Sonderzeichen werden aus dem Dateinamen entfernt.
  • Jede E-Mail bekommt im User-Temp ein separates Verzeichnis, falls dafür Anhänge abgelegt werden müssen.

Funktionen

Logging de-/aktivieren

Das Logging wird mit dem Setzen eines gültigen Log-Levels aktiviert. Dann werden alle Meldungen in den Windows-Trace geschrieben. Diese Meldungen können mit einem TraceListener gelesen werden. Windows stellt mit DebugView ein Tool zur Verfügung, welches die Traces anzeigen und speichern kann. Gültige Log-Level sind der Summary unten zu entnehmen.

/// <summary>
/// Legt das globale Log-Level fest.
/// Wird das Log-Level auf einen ungültigen Wert gesetzt, wird das Logging deaktiviert.
/// </summary>
/// <param name="level">Das Log-Level: Trace=0, Debug=1, Info=2, Warning=3, Error=4, Fatal=5.</param>
public static void MsGraphClientSetLogLevel(int level);

Fehlerbehandlung

Wenn bei einer Funktion ein Fehler auftritt, wird dieser mit dem ReturnCode false angezeigt. Der Fehler kann danach mit folgenden Befehlen abgefragt werden.

/// <summary>
/// Liefert den letzten aufgetretenen Fehler zurück.
/// </summary>
/// <returns>Fehlermeldung als Text.</returns>
public static string MsGraphClientGetLastError();

Es kann auch eine Fehlerhistorie abgefragt werden. Diese enthält alle Fehler die seit der Initialisierung mit MsGraphClientInitializeViaClientSecret und MsGraphClientInitializeViaUserLogin aufgetreten sind.

/// <summary>
/// Liefert alle aufgetretenen Fehler seit der Initialisierung zurück.
/// </summary>
/// <returns>Die Fehlermeldungen sind zeilenweise enthalten. Trenner ist "\r\n".</returns>
public static string MsGraphClientGetErrorHistory()

E-Mails abrufen

E-Mails werden immer Ordnerbezogen abgerufen. Es muss beim Abrufen von E-Mails der Ordner mit seinem Namen angegeben werden, aus welchem die E-Mails abgerufen werden sollen. Wenn kein Ordername angegeben wird, wird der Posteingang als Ordner angenommen. Statt den Ordnernamen können auch die Ordner-Ids angegeben werden.

/// <summary>
/// Ruft alle Nachrichten aus dem angegebenen E-Mailordner ab.
/// Wenn für <see cref="folderName"/> null übergeben wird, wird die Inbox/Posteingang als Standardorder gesetzt.
/// </summary>
/// <param name="folderName">Name/Id des E-Mailordners.</param>
/// <returns>Gibt die Anzahl der abgerufenen Nachrichten zurück.</returns>
public static int MsGraphClientReadMessages(string folderName);

ACHTUNG: Bei der Angabe von Ordnernamen müssen die Standard-Ordner-Bezeichnungen verwendet werden. Siehe Tabelle unten. Da die Ordner in den Postfächern nach ihrer gesetzten Ländersprache dargestellt werden. Bsp.: Der "Posteingang" in Deutsch heißt "Inbox" in Englisch und "Posta in arrivo" in Italienisch und kann nur mit den Standardnamen Sprachenübergreifend ermittelt werden.

Folgende Standardordner bietet die MS Graph-API an. Quelle

Standardname Description
inbox The inbox folder.
outbox The outbox folder.
archive The archive folder messages are sent to when using the One_Click Archive feature in Outlook clients that support it. Note: this isn't the same as the Archive Mailbox feature of Exchange online.
sentitems The sent items folder.
deleteditems The folder items are moved to when they're deleted.
drafts The folder that contains unsent messages.
junkemail The junk email folder.
conflicts The folder that contains conflicting items in the mailbox.
conversationhistory The folder where Skype saves IM conversations (if Skype is configured to do so).
msgfolderroot The "Top of Information Store" folder. This folder is the parent folder for folders that are displayed in normal mail clients, such as the inbox.
scheduled The folder that contains messages that are scheduled to reappear in the inbox using the Schedule feature in Outlook for iOS.
searchfolders The parent folder for all search folders defined in the user's mailbox.
serverfailures The folder that contains items that exist on the server but couldn't be synchronized to the local client.
syncissues The folder that contains synchronization logs created by Outlook.

Eine E-Mail mit seinen Daten abrufen

Um den Inhalt einer E-Mail in pit zu erhalten, müssen die E-Mails zuvor Ordnerbezogen abgerufen werden. Siehe E-Mails abrufen. Danach kann unter Angabe des Index die E-Mail mit seinem gesamten Inhalt aus pit abgefragt werden.

/// <summary>
/// Ruft die Daten einer E-Mail mittels Index ab und schreibt die Werte in die Parameter.
/// Falls diese E-Mail Anhänge besitzt werden diese vom Server geladen und lokal abgelegt.
/// Sonderfall Inline-Images: Inline-Images werden immer vom Server geladen. Die Images werden entweder in den Mail-Body
/// direkt eingebettet oder wie eine Attachment Datei übergeben. Wird über <paramref name="embedInlineImages"/> gesteuert.
/// Zuvor muss <see cref="MsGraphClientReadMessages"/> gerufen werden um die E-Mails abzurufen.
/// Index muss gültig sein.
/// </summary>
/// <param name="index">Der Index der Mail.</param>
/// <param name="embedInlineImages">Bei true werden Inline-Images direkt in den Mail-Body eingebettet.
/// Bei false werden die Dateinamen in die Inline-Images des Mail-Bodys geschrieben. Die Dateien sind dann über
/// <paramref name="inlineImages"/> zu bekommen.</param>
/// <param name="mailId">Die eindeutige Id der Mail.</param>
/// <param name="from">Die Mailadresse des Versenders.</param>
/// <param name="to">Die Mailadressen der Empfänger. Semikolon separierter String.</param>
/// <param name="cc">Die Mailadressen der CC-Empfänger. Semikolon separierter String.</param>
/// <param name="bcc">Die Mailadressen der BCC-Empfänger. Semikolon separierter String.</param>
/// <param name="attachments">Die Dateipfade zu den lokal gespeicherten Anhängen. Semikolon separierter String.</param>
/// <param name="subject">Das Mail-Subject.</param>
/// <param name="bodyType">Der Body-Type.</param>
/// <param name="bodyContent">Der Inhalt des Bodys.</param>
/// <param name="inlineImages">Dieses Feld ist nur gefüllt, wenn <paramref name="embedInlineImages"/>=false gesetzt ist.
/// Dann sind alle Inline-Images mit ihrem Dateipfad enthalten. Semikolon separierter String.</param>
/// <param name="receivedTime">Das Datum wann die Mail empfangen wurde.</param>
/// <returns>Liefert true, wenn alles funktioniert hat und false bei einem Fehler.</returns>
public static bool MsGraphClientGetMessage(
    int index,
    bool embedInlineImages,
    ref string mailId,
    ref string from,
    ref string to,
    ref string cc,
    ref string bcc,
    ref string attachments,
    ref string subject,
    ref string bodyType,
    ref string bodyContent,
    ref string inlineImages,
    ref DateTime receivedTime);

Attachments in der E-Mail

Bei der Abfrage der E-Mail werden alle Anhänge der E-Mail vom Server geladen und in dem lokalen User-Temp-Verzeichnis abgelegt. Wenn der Anhang eine E-Mail ist, wird dieser Anhang als MIME-Datei mit all seinen internen Anhängen in die Datei geschrieben. Die Datei wird mit der Erweiterung ".eml" geschrieben und kann mit Outlook geöffnet werden.

E-Mail verschieben

E-Mails können in andere E-Mail-Ordner verschoben werden. Zum Verschieben muss der Index der E-Mail angegeben werden und der Name bzw. die Id des E-Mail-Ordners.

/// <summary>
/// Verschiebt die E-Mail in den angegebenen Ordner.
/// </summary>
/// <param name="index">Der Index der Mail.</param>
/// <param name="targetFolder">Name/Id des Mail-Ordners.</param>
/// <returns>Liefert true, wenn alles funktioniert hat und false bei einem Fehler.</returns>
public static bool MsGraphClientMoveMessage(int index, string targetFolder);

E-Mail löschen

E-Mails werden nicht gelöscht, sondern in den Mailordner "Gelöschte Elemente" verschoben. Dies ist Standardverhalten bei E-Mail-Clients.

/// <summary>
/// Verschiebt die E-Mail in den Ordner "Gelöschte Elemente".
/// </summary>
/// <param name="index">Der Index der Mail.</param>
/// <returns>Liefert true, wenn alles funktioniert hat und false bei einem Fehler.</returns>
public static bool MsGraphClientDeleteMessage(int index);

E-Mail als gelesen oder ungelesen setzen

/// <summary>
/// Setzt den Gelesen-Status einer E-Mail.
/// </summary>
/// <param name="index">Der Index der Mail.</param>
/// <param name="isRead">Der zu setzende Gelesen-Status der Mail.</param>
/// <returns>Liefert true, wenn alles funktioniert hat und false bei einem Fehler.</returns>
public static bool MsGraphClientSetMessageReadState(int index, bool isRead);

Proxy-Server angeben

Der Proxy-Server muss vor der Initialisierung des Add-Ons angegeben werden.

/// <summary>
/// Erstellt die Proxykonfiguration.
/// Diese Funktion muss vor den Initialize-Funktionen <see cref="MsGraphClientInitializeViaClientSecret"/> bzw. <see cref="MsGraphClientInitializeViaUserLogin"/> aufgerufen werden.
/// </summary>
/// <param name="proxyAddress">Die Adresse des Proxyservers.</param>
/// <param name="username">Optional: Der UserName zur Authentifizierung am Proxy.</param>
/// <param name="password">Optional: Das Passwort zur Authentifizierung am Proxy.</param>
/// <param name="domain">Optional: Die Domäne, die diesen Anmeldeinformationen zugeordnet.</param>
/// <returns>Liefert true, wenn alles funktioniert hat.
/// Bei false wird der Proxy trotzdem gesetzt. Es muss dann jedoch nochmal die Initialisierung mit den Login-Informationen durchgeführt werden.</returns>
[FctExport(Const = true, Interactive = false, Category = AddonCategoryName, Description = "/// <summary>\n/// Erstellt die Proxykonfiguration.\n/// Diese Funktion muss vor den Initialize-Funktionen <see cref=\"MsGraphClientInitializeViaClientSecret\"/> bzw. <see cref=\"MsGraphClientInitializeViaUserLogin\"/> aufgerufen werden.\n/// </summary>\n/// <param name=\"proxyAddress\">Die Adresse des Proxyservers.</param>\n/// <param name=\"username\">Optional: Der UserName zur Authentifizierung am Proxy.</param>\n/// <param name=\"password\">Optional: Das Passwort zur Authentifizierung am Proxy.</param>\n/// <param name=\"domain\">Optional: Die Domäne, die diesen Anmeldeinformationen zugeordnet.</param>\n/// <returns>Liefert true, wenn alles funktioniert hat.\n/// Bei false wird der Proxy trotzdem gesetzt. Es muss dann jedoch nochmal die Initialisierung mit den Login-Informationen durchgeführt werden.</returns>")]
public static bool MsGraphClientDefineWebProxy(string proxyAddress, string username = null, string password = null, string domain = null);

Add-On initialisieren

Das Add-On muss vor der Nutzung mit den notwendigen Daten initialisiert werden.

/// <summary>
/// Initialisiert den GraphClient mittels ClientSecret.
/// </summary>
/// <param name="tenantId">Die Tenant-/Mandant-/Verzeichnis-ID.</param>
/// <param name="clientId">Die Client-/Anwendungs-/App-ID.</param>
/// <param name="clientSecret">Das Client-Secret.</param>
/// <param name="emailAddress">Die Mailbox von welcher die E-Mails abgerufen werden sollen.</param>
/// <returns>Liefert true, wenn alles funktioniert hat und false bei einem Fehler.</returns>
public static bool MsGraphClientInitializeViaClientSecret(string tenantId, string clientId, string clientSecret, string emailAddress);

/// <summary>
/// Initialisiert den GraphClient mittels Nutzername und Passwort.
/// </summary>
/// <param name="tenantId">Die Tenant-/Mandant-/Verzeichnis-ID.</param>
/// <param name="clientId">Die Client-/Anwendungs-/App-ID.</param>
/// <param name="user">Der Nutzername bzw. die E-Mail-Adresse des Nutzers.</param>
/// <param name="password">Das Passwort zu dem Nutzeraccount.</param>
/// <returns>Liefert true, wenn alles funktioniert hat und false bei einem Fehler.</returns>
public static bool MsGraphClientInitializeViaUserLogin(string tenantId, string clientId, string user, string password);

E-Mail erstellen und versenden

Eine neue E-Mail muss initialisiert werden. Mit der Initialisierung werden alle bisher gesetzten Werte gelöscht.

/// <summary>
/// Initialisiert ein Mailobjekt.
/// Dadurch wird das vorherige Mailobjekt ersetzt und die bisherigen Anhänge/Attachments entfernt.
/// </summary>
/// <param name="subject">Der Betreff der E-Mail.</param>
/// <param name="body">Der Inhalt der E-Mail.</param>
/// <param name="bodyTypeIsHtml">Die Inhaltsart: True ist HTML-Content, False ist TEXT-Content.</param>
/// <param name="senderAddress">Optional: Die E-Mail-Adresse des Absenders.</param>
/// <param name="senderDisplayname">Optional: Der Anzeigename des Absenders.</param>
/// <returns>Liefert true, wenn alles funktioniert hat und false bei einem Fehler.</returns>
public static bool MsGraphClientMailInitialize(
    string subject,
    string body,
    bool bodyTypeIsHtml,
    string senderAddress = null,
    string senderDisplayname = null);

/// <summary>
/// Eine Empfängerin hinzufügen.
/// </summary>
/// <param name="recipientType">Die Empfängerart: TO = 1, CC = 2, BCC = 3.</param>
/// <param name="displayName">Der Anzeigename des Kontakts.</param>
/// <param name="mailAddress">Die E-Mail-Adresse des Kontakts.</param>
/// <returns>Liefert true, wenn alles funktioniert hat und false bei einem Fehler.</returns>
public static bool MsGraphClientMailAddRecipient(int recipientType, string displayName, string mailAddress);

/// <summary>
/// Ein Anhang/Attachment hinzufügen.
/// </summary>
/// <param name="name">Name des Anhangs.</param>
/// <param name="filePath">Vollständiger Dateipfad der Datei.</param>
/// <returns>Liefert true, wenn alles funktioniert hat und false bei einem Fehler.</returns>
public static bool MsGraphClientMailAddAttachment(string name, string filePath);

/// <summary>
/// Versendet die konfigurierte E-Mail.
/// </summary>
/// <returns>Liefert true, wenn alles funktioniert hat und false bei einem Fehler.</returns>
public static bool MsGraphClientMailSend();