Lernprogramm: Erstellen eines Outlook-Add-Ins zum Verfassen von Nachrichten
In diesem Lernprogramm erfahren Sie, wie Sie ein Outlook-Add-In erstellen, das im Modus zum Verfassen von Nachrichten verwendet werden kann, um Inhalte in den Text einer Nachricht einzufügen.
In diesem Lernprogramm wird Folgendes vermittelt:
- Erstellen eines Outlook-Add-In-Projekts
- Definieren von Schaltflächen, die im Fenster zum Verfassen von Nachrichten angezeigt werden
- Implementieren eines Eindrucks beim ersten Ausführen, der Informationen vom Benutze erfasst und Daten von einem externen Dienst abruft
- Implementieren einer UI-losen Schaltfläche, die eine Funktion aufruft
- Implementieren eines Aufgabenbereichs, der Inhalte in den Textkörper einer Nachricht einfügt
Tipp
Wenn Sie eine vollständige Version dieses Tutorials benötigen (mit dem reinen Add-In-Manifest), wechseln Sie zum Repository office Add-ins samples (Beispiele für Office-Add-Ins) auf GitHub.
Voraussetzungen
Node.js (die aktuellsteLTS-Version). Besuchen Sie die Node.js Website , um die richtige Version für Ihr Betriebssystem herunterzuladen und zu installieren.
Die neueste Version von Yeoman und des Yeoman-Generators für Office-Add-Ins. Um diese Tools global zu installieren, führen Sie den folgenden Befehl an der Eingabeaufforderung aus.
npm install -g yo generator-office
Hinweis
Selbst wenn Sie bereits den Yeoman-Generator installiert haben, empfehlen wir Ihnen, das npm-Paket auf die neueste Version zu aktualisieren.
Office in Verbindung mit einem Microsoft 365-Abonnement (einschließlich Office im Internet).
Hinweis
Wenn Sie noch nicht über Office verfügen, können Sie sich über das Microsoft 365-Entwicklerprogramm für ein Microsoft 365 E5-Entwicklerabonnement qualifizieren. Weitere Informationen finden Sie in den häufig gestellten Fragen. Alternativ können Sie sich für eine kostenlose 1-monatige Testversion registrieren oder einen Microsoft 365-Plan erwerben.
Visual Studio Code (VS Code) oder Ihr bevorzugter Code-Editor.
Outlook im Web, neues Outlook unter Windows oder Outlook 2016 oder höher unter Windows (verbunden mit einem Microsoft 365-Konto).
Ein GitHub-Konto .
Setup
Das Add-In, das Sie in diesem Lernprogramm erstellen, liest Gists aus dem GitHub-Konto des Benutzers und fügt den ausgewählten Gist zum Textkörper einer Nachricht hinzu. Führen Sie die folgenden Schritte aus, um zwei neue Gists zu erstellen, die Sie verwenden können, um das Add-In zu testen, das Sie erstellen.
Erstellen Sie einen neuen Gist.
Geben Sie im Feld Gist description... den Text Hello Welt (Markdown) ein.
Geben Sie im Feld Filename including extension... den Namen test.md ein.
Fügen Sie das folgende Markdown zu dem mehrzeiligen Textfeld hinzu.
# Hello World This is content converted from Markdown! Here's a JSON sample: ```json { "foo": "bar" } ```
Wählen Sie die Schaltfläche Create public gist aus.
Erstellen Sie einen weiteren neuen Gist.
Geben Sie im Feld Gist description... den Text Hello World Html ein.
Geben Sie im Feld Filename including extension... den Namen test.html ein.
Fügen Sie das folgende Markdown zu dem mehrzeiligen Textfeld hinzu.
<html> <head> <style> h1 { font-family: Calibri; } </style> </head> <body> <h1>Hello World!</h1> <p>This is a test</p> </body> </html>
Wählen Sie die Schaltfläche Create public gist aus.
Erstellen eines Outlook-Add-In-Projekts
Führen Sie den folgenden Befehl aus, um ein Add-In-Projekt mit dem Yeoman-Generator zu erstellen: Ein Ordner, der das Projekt enthält, wird dem aktuellen Verzeichnis hinzugefügt.
yo office
Hinweis
Wenn Sie den
yo office
-Befehl ausführen, werden möglicherweise Eingabeaufforderungen zu den Richtlinien für die Datensammlung von Yeoman und den CLI-Tools des Office-Add-In angezeigt. Verwenden Sie die bereitgestellten Informationen, um auf die angezeigten Eingabeaufforderungen entsprechend zu reagieren.Wenn Sie dazu aufgefordert werden, geben Sie die folgenden Informationen an, um das Add-In-Projekt zu erstellen:
Die Schritte zum Erstellen des Projekts variieren je nach Art des Manifests geringfügig.
Hinweis
Mit dem einheitlichen Manifest für Microsoft 365 können Sie ein Outlook-Add-In mit einer Teams-App als einzelne Entwicklungs- und Bereitstellungseinheit kombinieren. Wir arbeiten daran, die Unterstützung für das einheitliche Manifest auf Excel, PowerPoint, Word, benutzerdefinierte Copilot-Entwicklung und andere Erweiterungen von Microsoft 365 zu erweitern. Weitere Informationen hierzu finden Sie unter Office-Add-Ins mit dem einheitlichen Manifest. Ein Beispiel für eine kombinierte Teams-App und ein Outlook-Add-In finden Sie unter Rabattangebote.
Wir freuen uns, Ihr Feedback zum einheitlichen Manifest zu erhalten. Wenn Sie Vorschläge haben, erstellen Sie ein Problem im Repository für die Office JavaScript-Bibliothek.
Choose a project type -
Office Add-in Task Pane project
Choose a script type -
JavaScript
Wie soll Ihr Add-In heißen? -
Git the gist
Which Office client application would you like to support? -
Outlook
Welches Manifest möchten Sie verwenden? -
unified manifest for Microsoft 365
Nach Abschluss des Assistenten erstellt der Generator erstellt das Projekt und installiert unterstützende Node-Komponenten.
Navigieren Sie zum Stammverzeichnis des Projekts.
cd "Git the gist"
Dieses Add-In verwendet die folgenden Bibliotheken.
- Herunterfahren der Bibliothek zum Konvertieren von Markdown in HTML
- URI.js-Bibliothek zum Erstellen von relativen URLs
- jQuery-Bibliothek zur Vereinfachung von DOM-Interaktionen.
Um diese Tools für Ihr Projekt zu installieren, führen Sie den folgenden Befehl im Stammverzeichnis des Projekts aus.
npm install showdown urijs jquery --save
Öffnen Sie Ihr Projekt in VS Code oder in Ihrem bevorzugten Code-Editor.
Tipp
In Windows können Sie über die Befehlszeile zum Stammverzeichnis des Projekts navigieren und dann
code .
eingeben, um diesen Ordner in VS Code zu öffnen. Auf einem Mac müssen Sie dencode
-Befehl zum Pfad hinzufügenbevor Sie diesen Befehl verwenden können, um den Projektordner in VS Code zu öffnen.
Aktualisieren des Manifests
Das Manifest für ein Add-In steuert, wie dieses in Outlook angezeigt wird. Es definiert, wie das Add-In und die Schaltflächen in der Add-In-Liste angezeigt werden, die Schaltflächen, die im Menüband angezeigt werden, und legt die URL für die HTML- und JavaScript-Dateien fest, die vom Add-In verwendet werden.
Angeben der grundlegenden Informationen
Nehmen Sie die folgenden Aktualisierungen in der Manifestdatei vor, um einige grundlegende Informationen zum Add-In anzugeben.
Suchen Sie die Eigenschaft "description", ersetzen Sie die Standardwerte "short" und "long" durch Beschreibungen des Add-Ins, und speichern Sie die Datei.
"description": { "short": "Gets gists.", "full": "Allows users to access their GitHub gists." },
Speichern Sie die Datei.
Testen des generierten Add-Ins
Bevor Sie fortfahren, sollten Sie das grundlegende Add-In testen, das der Generator erstellt hat, um zu bestätigen, dass das Projekt korrekt eingerichtet ist.
Hinweis
Office-Add-Ins sollten auch während der Entwicklung HTTPS und nicht HTTP verwenden. Wenn Sie aufgefordert werden, ein Zertifikat zu installieren, nachdem Sie einen der folgenden Befehle ausgeführt haben, akzeptieren Sie die Eingabeaufforderung, um das Zertifikat zu installieren, das der Yeoman-Generator bereitstellt. Möglicherweise ist es auch erforderlich, dass Sie Ihre Eingabeaufforderung oder Ihr Terminal als Administrator ausführen, damit die Änderungen vorgenommen werden können.
Wenn Sie zum ersten Mal ein Office-Add-In auf Ihrem Computer entwickeln, werden Sie möglicherweise in der Befehlszeile aufgefordert, Microsoft Edge WebView eine Loopback-Ausnahme zu gewähren ("Localhost-Loopback für Microsoft Edge WebView zulassen?"). Wenn Sie dazu aufgefordert werden, geben Sie ein
Y
, um die Ausnahme zuzulassen. Beachten Sie, dass Sie Administratorrechte benötigen, um die Ausnahme zuzulassen. Sobald dies zulässig ist, sollten Sie nicht zur Eingabe einer Ausnahme aufgefordert werden, wenn Sie Office-Add-Ins in Zukunft querladen (es sei denn, Sie entfernen die Ausnahme von Ihrem Computer). Weitere Informationen finden Sie unter "Wir können dieses Add-In nicht über localhost öffnen", wenn Sie ein Office-Add-In laden oder Fiddler verwenden.
Führen Sie den folgenden Befehl im Stammverzeichnis Ihres Projekts aus. Wenn Sie diesen Befehl ausführen, wird der lokale Webserver gestartet, und Das Add-In wird quergeladen.
npm start
Hinweis
Wenn Ihr Add-In nicht automatisch quergeladen wurde, befolgen Sie die Anweisungen unter Querladen von Outlook-Add-Ins zum Testen , um das Add-In in Outlook manuell querzuladen.
Öffnen Sie in Outlook eine vorhandene Nachricht, und klicken Sie auf die Schaltfläche Aufgabenbereich anzeigen.
Wenn Sie mit dem Dialogfeld WebView beim Laden beenden aufgefordert werden, wählen Sie OK aus.
Hinweis
Wenn Sie Abbrechen auswählen, wird das Dialogfeld nicht mehr angezeigt, solange diese Instanz des Add-Ins ausgeführt wird. Wenn Sie Ihr Add-In jedoch neu starten, wird das Dialogfeld wieder angezeigt.
Wenn alles ordnungsgemäß eingerichtet wurde, wird der Aufgabenbereich geöffnet und die Willkommensseite des Add-Ins gerendert.
Wenn Sie den lokalen Webserver beenden und das Add-In deinstallieren möchten, befolgen Sie die entsprechenden Anweisungen:
Führen Sie den folgenden Befehl aus, um den Server zu beenden. Wenn Sie verwendet haben
npm start
, sollte auch der folgende Befehl das Add-In deinstallieren.npm stop
Wenn Sie das Add-In manuell quergeladen haben, lesen Sie Entfernen eines quergeladenen Add-Ins.
Definieren von Schaltflächen
Da Sie nun überprüft haben, dass das grundlegende Add-In funktioniert, können Sie es anpassen und weitere Funktionen hinzufügen. Das Manifest definiert standardmäßig nur Schaltflächen für das Fenster zum Lesen von Nachrichten. Wir aktualisieren das Manifest so, dass die Schaltflächen aus dem Fenster zum Lesen von Nachrichten entfernt und zwei neue Schaltflächen für das Fenster zum Verfassen von Nachrichten definiert werden:
Insert gist: Eine Add-In-Befehlsschaltfläche, mit der eine Aufgabenbereich geöffnet wird.
Insert default gist: Eine Schaltfläche, die eine Funktion aufruft.
Die Prozedur hängt davon ab, welches Manifest Sie verwenden.
Führen Sie die folgenden Schritte aus:
Öffnen Sie die manifest.json Datei.
Im Array "extensions.runtimes" gibt es zwei Laufzeitobjekte. Ändern Sie bei der zweiten Mit der "id" von "CommandsRuntime" den "actions.id" in "insertDefaultGist". Dies ist der Name einer Funktion, die Sie in einem späteren Schritt erstellen. Wenn Sie fertig sind, sollte das Laufzeitobjekt wie folgt aussehen:
{ "id": "CommandsRuntime", "type": "general", "code": { "page": "https://localhost:3000/commands.html", "script": "https://localhost:3000/commands.js" }, "lifetime": "short", "actions": [ { "id": "insertDefaultGist", "type": "executeFunction", "displayName": "action" } ] }
Ändern Sie das Element im Array "extensions.ribbons.contexts" in "mailCompose". Dies bedeutet, dass die Schaltflächen nur in einem neuen Nachrichten- oder Antwortfenster angezeigt werden.
"contexts": [ "mailCompose" ],
Das Array "extensions.ribbons.tabs.groups" enthält ein Gruppenobjekt. Nehmen Sie die folgenden Änderungen an diesem Objekt vor.
- Ändern Sie die Eigenschaft "id" in "msgComposeCmdGroup".
- Ändern Sie die Eigenschaft "label" in "Git the gist".
Dasselbe Gruppenobjekt verfügt über ein "Controls"-Array mit zwei Steuerelementobjekten. Wir müssen für jeden json-Code Änderungen vornehmen. Führen Sie im ersten Schritt die folgenden Schritte aus.
- Ändern Sie "id" in "msgComposeInsertGist".
- Ändern Sie "label" in "Insert gist".
- Ändern Sie "supertip.title" in "Gist einfügen".
- Ändern Sie "supertip.description" in "Zeigt eine Liste Ihrer Gists an und ermöglicht es Ihnen, deren Inhalt in die aktuelle Nachricht einzufügen".
Führen Sie im zweiten Steuerelementobjekt die folgenden Schritte aus.
- Ändern Sie "id" in "msgComposeInsertDefaultGist".
- Ändern Sie "label" in "Insert default gist".
- Ändern Sie "supertip.title" in "Default gist einfügen".
- Ändern Sie "supertip.description" in "Fügt den Inhalt des Gist ein, den Sie als Standard in die aktuelle Nachricht markieren".
- Ändern Sie "actionId" in "insertDefaultGist". Dies entspricht dem "action.id" der "CommandsRuntime", die Sie in einem früheren Schritt festgelegt haben.
Wenn Sie fertig sind, sollte die Eigenschaft "Menübänder" wie folgt aussehen:
"ribbons": [ { "contexts": [ "mailCompose" ], "tabs": [ { "builtInTabId": "TabDefault", "groups": [ { "id": "msgComposeCmdGroup", "label": "Git the gist", "icons": [ { "size": 16, "file": "https://localhost:3000/assets/icon-16.png" }, { "size": 32, "file": "https://localhost:3000/assets/icon-32.png" }, { "size": 80, "file": "https://localhost:3000/assets/icon-80.png" } ], "controls": [ { "id": "msgComposeInsertGist", "type": "button", "label": "Insert gist", "icons": [ { "size": 16, "file": "https://localhost:3000/assets/icon-16.png" }, { "size": 32, "file": "https://localhost:3000/assets/icon-32.png" }, { "size": 80, "file": "https://localhost:3000/assets/icon-80.png" } ], "supertip": { "title": "Insert gist", "description": "Displays a list of your gists and allows you to insert their contents into the current message." }, "actionId": "TaskPaneRuntimeShow" }, { "id": "msgComposeInsertDefaultGist", "type": "button", "label": "Insert default gist", "icons": [ { "size": 16, "file": "https://localhost:3000/assets/icon-16.png" }, { "size": 32, "file": "https://localhost:3000/assets/icon-32.png" }, { "size": 80, "file": "https://localhost:3000/assets/icon-80.png" } ], "supertip": { "title": "Insert default gist", "description": "Inserts the content of the gist you mark as default into the current message." }, "actionId": "insertDefaultGist" } ] } ] } ] } ]
Speichern Sie die Änderungen im Manifest.
Erneutes Installieren des Add-Ins
Sie müssen das Add-In neu installieren, damit die Manifeständerungen wirksam werden.
Wenn der Webserver ausgeführt wird, führen Sie den folgenden Befehl aus.
npm stop
Führen Sie den folgenden Befehl aus, um den lokalen Webserver zu starten und Ihr Add-In automatisch querzuladen.
npm start
Nachdem Sie das Add-In erneut installiert haben, können Sie überprüfen, ob es erfolgreich installiert wurden, indem Sie nach den Befehlen Insert gist und Insert default gist im Fenster zum Verfassen von Nachrichten suchen. Beachten Sie, dass nichts passiert, wenn Sie eines der folgenden Elemente auswählen, da Sie das Erstellen dieses Add-Ins noch nicht abgeschlossen haben.
Wenn Sie dieses Add-In in Outlook 2016 oder höher unter Windows ausführen, sollten im Menüband des Fensters zum Verfassen von Nachrichten zwei neue Schaltflächen angezeigt werden: Gist einfügen und Standard-Gist einfügen.
Wenn Sie dieses Add-In in Outlook im Web oder einem neuen Outlook unter Windows ausführen, wählen Sie apps im Menüband des Fensters zum Verfassen von Nachrichten aus, und wählen Sie dann Git the gist aus, um die Optionen Gist einfügen und Standard-Gist einfügen anzuzeigen.
Implementieren einer ersten Ausführung
Dieses Add-In muss in der Lage sein, Gists aus dem GitHub-Konto des Benutzers zu lesen und zu identifizieren, welchen der Benutzer als Standard-Gist ausgewählt hat. Um diese Ziele zu erreichen, muss das Add-In den Benutzer auffordern, seinen GitHub-Benutzernamen einzugeben und einen Standard-Gist aus der Sammlung vorhandener Gists auszuwählen. Führen Sie die Schritte in diesem Abschnitt aus, um eine Erstausführung zu implementieren, in der ein Dialogfeld zum Sammeln dieser Informationen vom Benutzer angezeigt wird.
Erstellen der Benutzeroberfläche des Dialogfelds
Beginnen wir mit dem Erstellen der Benutzeroberfläche für das Dialogfeld.
Erstellen Sie im Ordner ./src einen neuen Unterordner mit dem Namen settings.
Erstellen Sie im Ordner ./src/settings eine Datei mit dem Namen dialog.html.
Fügen Sie indialog.htmldas folgende Markup hinzu, um ein einfaches Formular mit einer Texteingabe für einen GitHub-Benutzernamen und einer leeren Liste für Gists zu definieren, die über JavaScript aufgefüllt werden.
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=Edge" /> <title>Settings</title> <!-- Office JavaScript API --> <script type="text/javascript" src="https://appsforoffice.microsoft.com/lib/1.1/hosted/office.js"></script> <!-- For more information on Fluent UI, visit https://developer.microsoft.com/fluentui. --> <link rel="stylesheet" href="https://res-1.cdn.office.net/files/fabric-cdn-prod_20230815.002/office-ui-fabric-core/11.0.0/css/fabric.min.css"/> <!-- Template styles --> <link href="dialog.css" rel="stylesheet" type="text/css" /> </head> <body class="ms-font-l"> <main> <section class="ms-font-m ms-fontColor-neutralPrimary"> <div class="not-configured-warning ms-MessageBar ms-MessageBar--warning"> <div class="ms-MessageBar-content"> <div class="ms-MessageBar-icon"> <i class="ms-Icon ms-Icon--Info"></i> </div> <div class="ms-MessageBar-text"> Oops! It looks like you haven't configured <strong>Git the gist</strong> yet. <br/> Please configure your GitHub username and select a default gist, then try that action again! </div> </div> </div> <div class="ms-font-xxl">Settings</div> <div class="ms-Grid"> <div class="ms-Grid-row"> <div class="ms-TextField"> <label class="ms-Label">GitHub Username</label> <input class="ms-TextField-field" id="github-user" type="text" value="" placeholder="Please enter your GitHub username"> </div> </div> <div class="error-display ms-Grid-row"> <div class="ms-font-l ms-fontWeight-semibold">An error occurred:</div> <pre><code id="error-text"></code></pre> </div> <div class="gist-list-container ms-Grid-row"> <div class="list-title ms-font-xl ms-fontWeight-regular">Choose Default Gist</div> <form> <div id="gist-list"> </div> </form> </div> </div> <div class="ms-Dialog-actions"> <div class="ms-Dialog-actionsRight"> <button class="ms-Dialog-action ms-Button ms-Button--primary" id="settings-done" disabled> <span class="ms-Button-label">Done</span> </button> </div> </div> </section> </main> <script type="text/javascript" src="../../node_modules/jquery/dist/jquery.js"></script> <script type="text/javascript" src="../helpers/gist-api.js"></script> <script type="text/javascript" src="dialog.js"></script> </body> </html>
Möglicherweise haben Sie bemerkt, dass die HTML-Datei auf eine JavaScript-Datei verweist, gist-api.js, die noch nicht vorhanden ist. Diese Datei wird im Abschnitt Daten von GitHub abrufen weiter unten erstellt.
Speichern Sie Ihre Änderungen.
Erstellen Sie als Nächstes eine Datei im Ordner ./src/settings mit dem Namen dialog.css.
Fügen Sie in dialog.css den folgenden Code hinzu, um die Stile anzugeben, die vondialog.htmlverwendet werden.
section { margin: 10px 20px; } .not-configured-warning { display: none; } .error-display { display: none; } .gist-list-container { margin: 10px -8px; display: none; } .list-title { border-bottom: 1px solid #a6a6a6; padding-bottom: 5px; } ul { margin-top: 10px; } .ms-ListItem-secondaryText, .ms-ListItem-tertiaryText { padding-left: 15px; }
Speichern Sie Ihre Änderungen.
Entwickeln der Funktionalität des Dialogs
Da Sie nun die Benutzeroberfläche des Dialogfelds definiert haben, können Sie den Code schreiben, der dazu führt, dass eine Aktion ausgeführt wird.
Erstellen Sie im Ordner ./src/settings eine Datei mit dem Namen dialog.js.
Fügen Sie den folgenden Code hinzu. Beachten Sie, dass dieser Code jQuery verwendet, um Ereignisse zu registrieren, und die
messageParent
-Methode, um die Auswahl des Benutzers zurück an den Aufrufer zu senden.(function() { 'use strict'; // The onReady function must be run each time a new page is loaded. Office.onReady(function() { $(document).ready(function() { if (window.location.search) { // Check if warning should be displayed. const warn = getParameterByName('warn'); if (warn) { $('.not-configured-warning').show(); } else { // See if the config values were passed. // If so, pre-populate the values. const user = getParameterByName('gitHubUserName'); const gistId = getParameterByName('defaultGistId'); $('#github-user').val(user); loadGists(user, function(success) { if (success) { $('.ms-ListItem').removeClass('is-selected'); $('input').filter(function() { return this.value === gistId; }).addClass('is-selected').attr('checked', 'checked'); $('#settings-done').removeAttr('disabled'); } }); } } // When the GitHub username changes, // try to load gists. $('#github-user').on('change', function() { $('#gist-list').empty(); const ghUser = $('#github-user').val(); if (ghUser.length > 0) { loadGists(ghUser); } }); // When the Done button is selected, send the // values back to the caller as a serialized // object. $('#settings-done').on('click', function() { const settings = {}; settings.gitHubUserName = $('#github-user').val(); const selectedGist = $('.ms-ListItem.is-selected'); if (selectedGist) { settings.defaultGistId = selectedGist.val(); sendMessage(JSON.stringify(settings)); } }); }); }); // Load gists for the user using the GitHub API // and build the list. function loadGists(user, callback) { getUserGists(user, function(gists, error) { if (error) { $('.gist-list-container').hide(); $('#error-text').text(JSON.stringify(error, null, 2)); $('.error-display').show(); if (callback) callback(false); } else { $('.error-display').hide(); buildGistList($('#gist-list'), gists, onGistSelected); $('.gist-list-container').show(); if (callback) callback(true); } }); } function onGistSelected() { $('.ms-ListItem').removeClass('is-selected').removeAttr('checked'); $(this).children('.ms-ListItem').addClass('is-selected').attr('checked', 'checked'); $('.not-configured-warning').hide(); $('#settings-done').removeAttr('disabled'); } function sendMessage(message) { Office.context.ui.messageParent(message); } function getParameterByName(name, url) { if (!url) { url = window.location.href; } name = name.replace(/[\[\]]/g, "\\$&"); const regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"), results = regex.exec(url); if (!results) return null; if (!results[2]) return ''; return decodeURIComponent(results[2].replace(/\+/g, " ")); } })();
Speichern Sie Ihre Änderungen.
Aktualisieren der Webpack-Konfigurationseinstellungen
Öffnen Sie abschließend die Datei webpack.config.js im Stammverzeichnis des Projekts, und führen Sie die folgenden Schritte aus.
Suchen Sie das
entry
-Objekt innerhalb desconfig
-Objekts, und fügen Sie einen neuen Eintrag fürdialog
hinzu.dialog: "./src/settings/dialog.js",
Danach sieht das neue
entry
-Objekt folgendermaßen aus:entry: { polyfill: ["core-js/stable", "regenerator-runtime/runtime"], taskpane: ["./src/taskpane/taskpane.js", "./src/taskpane/taskpane.html"], commands: "./src/commands/commands.js", dialog: "./src/settings/dialog.js", },
Suchen Sie das Array
plugins
innerhalb des Objektsconfig
. Fügen Sie impatterns
-Array desnew CopyWebpackPlugin
-Objekts neue Einträge für taskpane.css und dialog.css hinzu.{ from: "./src/taskpane/taskpane.css", to: "taskpane.css", }, { from: "./src/settings/dialog.css", to: "dialog.css", },
Danach sieht das
new CopyWebpackPlugin
Objekt wie folgt aus. Beachten Sie den geringfügigen Unterschied, wenn das Add-In nur das Add-In-Manifest verwendet.new CopyWebpackPlugin({ patterns: [ { from: "./src/taskpane/taskpane.css", to: "taskpane.css", }, { from: "./src/settings/dialog.css", to: "dialog.css", }, { from: "assets/*", to: "assets/[name][ext][query]", }, { from: "manifest*.json", // The file extension is "xml" if the add-in only manifest is being used. to: "[name]" + "[ext]", transform(content) { if (dev) { return content; } else { return content.toString().replace(new RegExp(urlDev, "g"), urlProd); } }, }, ]}),
Fügen Sie im gleichen
plugins
-Array innerhalb desconfig
-Objekts dieses neue Objekt am Ende des Arrays hinzu.new HtmlWebpackPlugin({ filename: "dialog.html", template: "./src/settings/dialog.html", chunks: ["polyfill", "dialog"] })
Danach sieht das neue
plugins
Array wie folgt aus. Beachten Sie den geringfügigen Unterschied, wenn das Add-In nur das Add-In-Manifest verwendet.plugins: [ new HtmlWebpackPlugin({ filename: "taskpane.html", template: "./src/taskpane/taskpane.html", chunks: ["polyfill", "taskpane"], }), new CopyWebpackPlugin({ patterns: [ { from: "./src/taskpane/taskpane.css", to: "taskpane.css", }, { from: "./src/settings/dialog.css", to: "dialog.css", }, { from: "assets/*", to: "assets/[name][ext][query]", }, { from: "manifest*.json", // The file extension is "xml" if the add-in only manifest is being used. to: "[name]." + buildType + "[ext]", transform(content) { if (dev) { return content; } else { return content.toString().replace(new RegExp(urlDev, "g"), urlProd); } }, }, ], }), new HtmlWebpackPlugin({ filename: "commands.html", template: "./src/commands/commands.html", chunks: ["polyfill", "commands"], }), new HtmlWebpackPlugin({ filename: "dialog.html", template: "./src/settings/dialog.html", chunks: ["polyfill", "dialog"] }) ],
Abrufen von Daten aus GitHub
Die Datei dialog.js-, die Sie gerade erstellt haben, gibt an, dass das Add-In Gists laden soll, wenn die Änderungs-Ereignis für das GitHub-Benutzernamenfeld ausgelöst wird. Um die Gists des Benutzers aus GitHub abzurufen, verwenden Sie die GitHub-Gists-API.
Erstellen Sie im Ordner ./src einen neuen Unterordner mit dem Namen helpers.
Erstellen Sie im Ordner ./src/helpers eine Datei mit dem Namen gist-api.js.
Fügen Sie ingist-api.jsden folgenden Code hinzu, um die Gists des Benutzers aus GitHub abzurufen und die Liste der Gists zu erstellen.
function getUserGists(user, callback) { const requestUrl = 'https://api.github.com/users/' + user + '/gists'; $.ajax({ url: requestUrl, dataType: 'json' }).done(function(gists) { callback(gists); }).fail(function(error) { callback(null, error); }); } function buildGistList(parent, gists, clickFunc) { gists.forEach(function(gist) { const listItem = $('<div/>') .appendTo(parent); const radioItem = $('<input>') .addClass('ms-ListItem') .addClass('is-selectable') .attr('type', 'radio') .attr('name', 'gists') .attr('tabindex', 0) .val(gist.id) .appendTo(listItem); const descPrimary = $('<span/>') .addClass('ms-ListItem-primaryText') .text(gist.description) .appendTo(listItem); const descSecondary = $('<span/>') .addClass('ms-ListItem-secondaryText') .text(' - ' + buildFileList(gist.files)) .appendTo(listItem); const updated = new Date(gist.updated_at); const descTertiary = $('<span/>') .addClass('ms-ListItem-tertiaryText') .text(' - Last updated ' + updated.toLocaleString()) .appendTo(listItem); listItem.on('click', clickFunc); }); } function buildFileList(files) { let fileList = ''; for (let file in files) { if (files.hasOwnProperty(file)) { if (fileList.length > 0) { fileList = fileList + ', '; } fileList = fileList + files[file].filename + ' (' + files[file].language + ')'; } } return fileList; }
Speichern Sie Ihre Änderungen.
Führen Sie den folgenden Befehl aus, um das Projekt erneut zu erstellen.
npm run build
Implementieren einer Schaltfläche ohne Benutzeroberfläche
Die Schaltfläche "Standard-Gist einfügen " dieses Add-Ins ist eine Schaltfläche ohne Benutzeroberfläche, die eine JavaScript-Funktion aufruft, anstatt wie bei vielen Add-In-Schaltflächen einen Aufgabenbereich zu öffnen. Wenn der Benutzer die Schaltfläche Standard-Gist einfügen auswählt, überprüft die entsprechende JavaScript-Funktion, ob das Add-In konfiguriert wurde.
Wenn das Add-In bereits konfiguriert wurde, lädt die Funktion den Inhalt des Gist, den der Benutzer als Standard ausgewählt hat, und fügt ihn in den Nachrichtentext ein.
Wenn das Add-In noch nicht konfiguriert wurde, fordert das Einstellungsdialogfeld den Benutzer auf, die erforderlichen Informationen anzugeben.
Aktualisieren der Funktionsdatei (HTML)
Eine Funktion, die von einer Schaltfläche ohne Benutzeroberfläche aufgerufen wird, muss in der Datei definiert werden, die durch das <FunctionFile-Element> im Manifest für den entsprechenden Formfaktor angegeben wird. Das Manifest dieses Add-Ins gibt https://localhost:3000/commands.html
als Funktionsdatei an.
Öffnen Sie ./src/commands/commands.html , und ersetzen Sie den gesamten Inhalt durch das folgende Markup.
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=Edge" /> <!-- Office JavaScript API --> <script type="text/javascript" src="https://appsforoffice.microsoft.com/lib/1.1/hosted/office.js"></script> <script type="text/javascript" src="../../node_modules/jquery/dist/jquery.js"></script> <script type="text/javascript" src="../../node_modules/showdown/dist/showdown.min.js"></script> <script type="text/javascript" src="../../node_modules/urijs/src/URI.min.js"></script> <script type="text/javascript" src="../helpers/addin-config.js"></script> <script type="text/javascript" src="../helpers/gist-api.js"></script> </head> <body> <!-- NOTE: The body is empty on purpose. Since functions in commands.js are invoked via a button, there is no UI to render. --> </body> </html>
Möglicherweise haben Sie bemerkt, dass die HTML-Datei auf eine JavaScript-Datei verweist, addin-config.js, die noch nicht vorhanden ist. Diese Datei wird im Abschnitt Erstellen einer Datei zum Verwalten von Konfigurationseinstellungen weiter unten in diesem Tutorial erstellt.
Speichern Sie Ihre Änderungen.
Aktualisieren der Funktionsdatei (JavaScript)
Öffnen Sie die Datei ./src/commands/commands.js, und ersetzen Sie den gesamten Inhalt durch den folgenden Code. Beachten Sie, dass der Parameter der Dialog-URL hinzugefügt
?warn=1
wird, wenn die insertDefaultGist-Funktion feststellt, dass das Add-In noch nicht konfiguriert wurde. Auf diese Weise rendert das Dialogfeld "Einstellungen" die Meldungsleiste, die in ./src/settings/dialog.html definiert ist, um dem Benutzer mitzuteilen, warum das Dialogfeld angezeigt wird.let config; let btnEvent; // The onReady function must be run each time a new page is loaded. Office.onReady(); function showError(error) { Office.context.mailbox.item.notificationMessages.replaceAsync('github-error', { type: 'errorMessage', message: error }); } let settingsDialog; function insertDefaultGist(event) { config = getConfig(); // Check if the add-in has been configured. if (config && config.defaultGistId) { // Get the default gist content and insert. try { getGist(config.defaultGistId, function(gist, error) { if (gist) { buildBodyContent(gist, function (content, error) { if (content) { Office.context.mailbox.item.body.setSelectedDataAsync( content, { coercionType: Office.CoercionType.Html }, function (result) { event.completed(); } ); } else { showError(error); event.completed(); } }); } else { showError(error); event.completed(); } }); } catch (err) { showError(err); event.completed(); } } else { // Save the event object so we can finish up later. btnEvent = event; // Not configured yet, display settings dialog with // warn=1 to display warning. const url = new URI('dialog.html?warn=1').absoluteTo(window.location).toString(); const dialogOptions = { width: 20, height: 40, displayInIframe: true }; Office.context.ui.displayDialogAsync(url, dialogOptions, function(result) { settingsDialog = result.value; settingsDialog.addEventHandler(Office.EventType.DialogMessageReceived, receiveMessage); settingsDialog.addEventHandler(Office.EventType.DialogEventReceived, dialogClosed); }); } } // Register the function. Office.actions.associate("insertDefaultGist", insertDefaultGist); function receiveMessage(message) { config = JSON.parse(message.message); setConfig(config, function(result) { settingsDialog.close(); settingsDialog = null; btnEvent.completed(); btnEvent = null; }); } function dialogClosed(message) { settingsDialog = null; btnEvent.completed(); btnEvent = null; }
Speichern Sie Ihre Änderungen.
Erstellen einer Datei zum Verwalten von Konfigurationseinstellungen
Erstellen Sie im Ordner ./src/helpers eine Datei namens addin-config.js, und fügen Sie den folgenden Code hinzu. Dieser Code verwendet das RoamingSettings-Objekt, um die Konfigurationswerte abzurufen und festzulegen.
function getConfig() { const config = {}; config.gitHubUserName = Office.context.roamingSettings.get('gitHubUserName'); config.defaultGistId = Office.context.roamingSettings.get('defaultGistId'); return config; } function setConfig(config, callback) { Office.context.roamingSettings.set('gitHubUserName', config.gitHubUserName); Office.context.roamingSettings.set('defaultGistId', config.defaultGistId); Office.context.roamingSettings.saveAsync(callback); }
Speichern Sie Ihre Änderungen.
Erstellen neuer Funktionen zum Verarbeiten von Gists
Öffnen Sie die Datei ./src/helpers/gist-api.js, und fügen Sie die folgenden Funktionen hinzu. Beachten Sie Folgendes:
Wenn der Gist HTML enthält, fügt das Add-In den HTML-Code unverändert in den Text der Nachricht ein.
Wenn der Gist Markdown enthält, verwendet das Add-In die Showdown-Bibliothek , um den Markdown in HTML zu konvertieren, und fügt dann den resultierenden HTML-Code in den Text der Nachricht ein.
Wenn der Gist etwas anderes als HTML oder Markdown enthält, fügt das Add-In diese Elemente als Codeausschnitt in den Text der Nachricht ein.
function getGist(gistId, callback) { const requestUrl = 'https://api.github.com/gists/' + gistId; $.ajax({ url: requestUrl, dataType: 'json' }).done(function(gist) { callback(gist); }).fail(function(error) { callback(null, error); }); } function buildBodyContent(gist, callback) { // Find the first non-truncated file in the gist // and use it. for (let filename in gist.files) { if (gist.files.hasOwnProperty(filename)) { const file = gist.files[filename]; if (!file.truncated) { // We have a winner. switch (file.language) { case 'HTML': // Insert as is. callback(file.content); break; case 'Markdown': // Convert Markdown to HTML. const converter = new showdown.Converter(); const html = converter.makeHtml(file.content); callback(html); break; default: // Insert contents as a <code> block. let codeBlock = '<pre><code>'; codeBlock = codeBlock + file.content; codeBlock = codeBlock + '</code></pre>'; callback(codeBlock); } return; } } } callback(null, 'No suitable file found in the gist'); }
Speichern Sie Ihre Änderungen.
Testen der Schaltfläche "Standardgist einfügen"
Wenn der lokale Webserver noch nicht ausgeführt wird, führen Sie
npm start
an der Eingabeaufforderung aus.Öffnen Sie Outlook, und verfassen Sie eine neue Nachricht.
Klicken Sie im Fenster zum Verfassen der Nachricht auf die Schaltfläche Insert default gist. Es sollte ein Dialogfeld angezeigt werden, in dem Sie das Add-In konfigurieren können, beginnend mit der Aufforderung zum Festlegen Ihres GitHub-Benutzernamens.
Geben Sie im Einstellungsdialogfeld Ihren GitHub-Benutzernamen ein, und klicken Sie dann entweder auf TAB , oder klicken Sie auf eine andere Stelle im Dialogfeld, um das Änderungsereignis aufzurufen, das Ihre Liste der öffentlichen Gists laden sollte. Wählen Sie einen Gist als Standard aus, und klicken Sie auf Done.
Klicken Sie erneut auf die Schaltfläche Insert Default Gist. Dieses Mal sollten Sie den Inhalt des Gists sehen, der in den Textkörper der E-Mail eingefügt wurde.
Hinweis
Outlook für Windows: damit die neuesten Einstellungen in Kraft treten, müssen Sie das Nachrichtenfenster ggfs. schließen und neu öffnen.
Implementieren eines Aufgabenbereichs
Die Schaltfläche Gist einfügen dieses Add-Ins öffnet einen Aufgabenbereich und zeigt die Gists des Benutzers an. Der Benutzer kann dann einen der Gists auswählen, der in den Textkörper der Nachricht eingefügt werden soll. Sofern der Benutzer das Add-in noch nicht konfiguriert ist, wird er dazu aufgefordert.
Angeben des HTML für den Aufgabenbereich
In dem von Ihnen erstellten Projekt wird das Aufgabenbereich-HTML in der Datei ./src/taskpane/taskpane.html angegeben. Öffnen Sie diese Datei, und ersetzen Sie den gesamten Inhalt durch das folgende Markup.
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=Edge" /> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Contoso Task Pane Add-in</title> <!-- Office JavaScript API --> <script type="text/javascript" src="https://appsforoffice.microsoft.com/lib/1.1/hosted/office.js"></script> <!-- For more information on Fluent UI, visit https://developer.microsoft.com/fluentui. --> <link rel="stylesheet" href="https://res-1.cdn.office.net/files/fabric-cdn-prod_20230815.002/office-ui-fabric-core/11.0.0/css/fabric.min.css"/> <!-- Template styles --> <link href="taskpane.css" rel="stylesheet" type="text/css" /> </head> <body class="ms-font-l ms-landing-page"> <main class="ms-landing-page__main"> <section class="ms-landing-page__content ms-font-m ms-fontColor-neutralPrimary"> <div id="not-configured" style="display: none;"> <div class="centered ms-font-xxl ms-u-textAlignCenter">Welcome!</div> <div class="ms-font-xl" id="settings-prompt">Please choose the <strong>Settings</strong> icon at the bottom of this window to configure this add-in.</div> </div> <div id="gist-list-container" style="display: none;"> <form> <div id="gist-list"> </div> </form> </div> <div id="error-display" style="display: none;" class="ms-u-borderBase ms-fontColor-error ms-font-m ms-bgColor-error ms-borderColor-error"> </div> </section> <button class="ms-Button ms-Button--primary" id="insert-button" tabindex=0 disabled> <span class="ms-Button-label">Insert</span> </button> </main> <footer class="ms-landing-page__footer ms-bgColor-themePrimary"> <div class="ms-landing-page__footer--left"> <img src="../../assets/logo-filled.png" /> <h1 class="ms-font-xl ms-fontWeight-semilight ms-fontColor-white">Git the gist</h1> </div> <div id="settings-icon" class="ms-landing-page__footer--right" aria-label="Settings" tabindex=0> <i class="ms-Icon enlarge ms-Icon--Settings ms-fontColor-white"></i> </div> </footer> <script type="text/javascript" src="../../node_modules/jquery/dist/jquery.js"></script> <script type="text/javascript" src="../../node_modules/showdown/dist/showdown.min.js"></script> <script type="text/javascript" src="../../node_modules/urijs/src/URI.min.js"></script> <script type="text/javascript" src="../helpers/addin-config.js"></script> <script type="text/javascript" src="../helpers/gist-api.js"></script> <script type="text/javascript" src="taskpane.js"></script> </body> </html>
Speichern Sie Ihre Änderungen.
Angeben des CSS für den Aufgabenbereich
In dem von Ihnen erstellten Projekt wird das Aufgabenbereich-CSS in der Datei ./src/taskpane/taskpane.css angegeben. Öffnen Sie diese Datei, und ersetzen Sie den gesamten Inhalt durch den folgenden Code.
/* Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. */ html, body { width: 100%; height: 100%; margin: 0; padding: 0; overflow: auto; } body { position: relative; font-size: 16px; } main { height: 100%; overflow-y: auto; } footer { width: 100%; position: relative; bottom: 0; margin-top: 10px;} p, h1, h2, h3, h4, h5, h6 { margin: 0; padding: 0; } ul { padding: 0; } #settings-prompt { margin: 10px 0; } #error-display { padding: 10px; } #insert-button { margin: 0 10px; } .clearfix { display: block; clear: both; height: 0; } .pointerCursor { cursor: pointer; } .invisible { visibility: hidden; } .undisplayed { display: none; } .ms-Icon.enlarge { position: relative; font-size: 20px; top: 4px; } .ms-ListItem-secondaryText, .ms-ListItem-tertiaryText { padding-left: 15px; } .ms-landing-page { display: -webkit-flex; display: flex; -webkit-flex-direction: column; flex-direction: column; -webkit-flex-wrap: nowrap; flex-wrap: nowrap; height: 100%; } .ms-landing-page__main { display: -webkit-flex; display: flex; -webkit-flex-direction: column; flex-direction: column; -webkit-flex-wrap: nowrap; flex-wrap: nowrap; -webkit-flex: 1 1 0; flex: 1 1 0; height: 100%; } .ms-landing-page__content { display: -webkit-flex; display: flex; -webkit-flex-direction: column; flex-direction: column; -webkit-flex-wrap: nowrap; flex-wrap: nowrap; height: 100%; -webkit-flex: 1 1 0; flex: 1 1 0; padding: 20px; } .ms-landing-page__content h2 { margin-bottom: 20px; } .ms-landing-page__footer { display: -webkit-inline-flex; display: inline-flex; -webkit-justify-content: center; justify-content: center; -webkit-align-items: center; align-items: center; } .ms-landing-page__footer--left { transition: background ease 0.1s, color ease 0.1s; display: -webkit-inline-flex; display: inline-flex; -webkit-justify-content: flex-start; justify-content: flex-start; -webkit-align-items: center; align-items: center; -webkit-flex: 1 0 0px; flex: 1 0 0px; padding: 20px; } .ms-landing-page__footer--left:active { cursor: default; } .ms-landing-page__footer--left--disabled { opacity: 0.6; pointer-events: none; cursor: not-allowed; } .ms-landing-page__footer--left--disabled:active, .ms-landing-page__footer--left--disabled:hover { background: transparent; } .ms-landing-page__footer--left img { width: 40px; height: 40px; } .ms-landing-page__footer--left h1 { -webkit-flex: 1 0 0px; flex: 1 0 0px; margin-left: 15px; text-align: left; width: auto; max-width: auto; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } .ms-landing-page__footer--right { transition: background ease 0.1s, color ease 0.1s; padding: 29px 20px; } .ms-landing-page__footer--right:active, .ms-landing-page__footer--right:hover { background: #005ca4; cursor: pointer; } .ms-landing-page__footer--right:active { background: #005ca4; } .ms-landing-page__footer--right--disabled { opacity: 0.6; pointer-events: none; cursor: not-allowed; } .ms-landing-page__footer--right--disabled:active, .ms-landing-page__footer--right--disabled:hover { background: transparent; }
Speichern Sie Ihre Änderungen.
Angeben des JavaScripts für den Aufgabenbereich
In dem von Ihnen erstellten Projekt wird das Aufgabenbereich-JavaScript in der Datei ./src/taskpane/taskpane.js angegeben. Öffnen Sie diese Datei, und ersetzen Sie den gesamten Inhalt durch den folgenden Code.
(function() { 'use strict'; let config; let settingsDialog; Office.onReady(function() { $(document).ready(function() { config = getConfig(); // Check if add-in is configured. if (config && config.gitHubUserName) { // If configured, load the gist list. loadGists(config.gitHubUserName); } else { // Not configured yet. $('#not-configured').show(); } // When insert button is selected, build the content // and insert into the body. $('#insert-button').on('click', function() { const gistId = $('.ms-ListItem.is-selected').val(); getGist(gistId, function(gist, error) { if (gist) { buildBodyContent(gist, function (content, error) { if (content) { Office.context.mailbox.item.body.setSelectedDataAsync( content, { coercionType: Office.CoercionType.Html }, function (result) { if (result.status === Office.AsyncResultStatus.Failed) { showError("Could not insert gist: " + result.error.message); } } ); } else { showError('Could not create insertable content: ' + error); } }); } else { showError('Could not retrieve gist: ' + error); } }); }); // When the settings icon is selected, open the settings dialog. $('#settings-icon').on('click', function() { // Display settings dialog. let url = new URI('dialog.html').absoluteTo(window.location).toString(); if (config) { // If the add-in has already been configured, pass the existing values // to the dialog. url = url + '?gitHubUserName=' + config.gitHubUserName + '&defaultGistId=' + config.defaultGistId; } const dialogOptions = { width: 20, height: 40, displayInIframe: true }; Office.context.ui.displayDialogAsync(url, dialogOptions, function(result) { settingsDialog = result.value; settingsDialog.addEventHandler(Office.EventType.DialogMessageReceived, receiveMessage); settingsDialog.addEventHandler(Office.EventType.DialogEventReceived, dialogClosed); }); }) }); }); function loadGists(user) { $('#error-display').hide(); $('#not-configured').hide(); $('#gist-list-container').show(); getUserGists(user, function(gists, error) { if (error) { } else { $('#gist-list').empty(); buildGistList($('#gist-list'), gists, onGistSelected); } }); } function onGistSelected() { $('#insert-button').removeAttr('disabled'); $('.ms-ListItem').removeClass('is-selected').removeAttr('checked'); $(this).children('.ms-ListItem').addClass('is-selected').attr('checked', 'checked'); } function showError(error) { $('#not-configured').hide(); $('#gist-list-container').hide(); $('#error-display').text(error); $('#error-display').show(); } function receiveMessage(message) { config = JSON.parse(message.message); setConfig(config, function(result) { settingsDialog.close(); settingsDialog = null; loadGists(config.gitHubUserName); }); } function dialogClosed(message) { settingsDialog = null; } })();
Speichern Sie Ihre Änderungen.
Testen der Schaltfläche "Gist einfügen"
Wenn der lokale Webserver noch nicht ausgeführt wird, führen Sie
npm start
an der Eingabeaufforderung aus.Öffnen Sie Outlook, und verfassen Sie eine neue Nachricht.
Klicken Sie im Fenster zum Verfassen der Nachricht auf die Schaltfläche Insert gist. Auf der rechten Seite des Formulars zum Verfassen wird ein Aufgabenbereich angezeigt.
Wählen Sie im Aufgabenbereich den Gist Hello World Html aus, und klicken Sie auf Insert, um diesen Gist in den Textkörper der Nachricht einzufügen.
Nächste Schritte
In diesem Lernprogramm haben Sie ein Outlook-Add-In erstellt, das im Modus zum Verfassen von Nachrichten verwendet werden kann, um Inhalte in den Text einer Nachricht einzufügen. Weitere Informationen zum Entwickeln von Outlook-Add-ins erhalten Sie im folgenden Artikel.
Codebeispiele
- Abgeschlossenes Tutorial zu Outlook-Add-Ins: Das Ergebnis dieses Tutorials.
Siehe auch
Office Add-ins