# JavaScript

Source: https://docs.interop.io/adapters/ms-office/outlook/javascript/index.html

## Library Usage

The [`@interopio/office`](https://www.npmjs.com/package/@interopio/office) library provides the necessary instrumentation for your web apps to interoperate with Outlook when the Outlook Adapter is installed and running. The library is available as an NPM package and is also distributed as JavaScript files with **io.Connect Desktop**. The files are located in the `<installation_location>/interop.io/io.Connect Desktop/SDK/ioOfficeJS/js/web-bundle` folder.

To install the `@interopio/office` library, execute the following command:

```cmd
npm install @interopio/office
```

You can now import the factory function exposed by the library:

```javascript
import IOConnectOffice from "@interopio/office";
```

You can also reference the library as a JavaScript file in the HTML file of your web app using a `<script>` tag:

```html
<script type="module" src="./office.min.js"></script>
```

The `@interopio/office` library exposes a global factory function called [`IOConnectOffice`](https://docs.interop.io/adapters/reference/javascript/io.connect%20office/ioconnectoffice/index.md) which you must invoke to initialize the library in your app. The factory function accepts an optional [`Config`](https://docs.interop.io/adapters/reference/javascript/io.connect%20office/config/index.md) which you can use to configure various features of the library.

The following sections provide examples which demonstrate how to initialize the `@interopio/office` library and access the [Outlook API](https://docs.interop.io/adapters/reference/javascript/outlook/api/index.md) in JavaScript, React, and Angular apps. It's generally recommended to expose a reference to the API object returned when the `IOConnectOffice` factory function resolves and then render your app.

### JavaScript

Initializing the `@interopio/office` library in a JavaScript app:

```javascript
import IOConnectOffice from "@interopio/office";

// Optional configuration for the library.
const config = {
    // Disabling the Excel and Word APIs.
    excel: false,
    word: false
};

// Initializing the library and obtaining a reference to the API object.
const office = await IOConnectOffice(config);

// Now the Outlook API is accessible via the `office.outlook` object.
```

### React

Initializing the `@interopio/office` library in a React app:

```javascript
import { createRoot } from "react-dom/client";
import IOConnectOffice from "@interopio/office";
import App from "./App";

// Expose the API object as a global variable which you can use in all your components.
// The Outlook API will then be accessible via the `office.outlook` object.
window.office = await IOConnectOffice();

const domElement = document.getElementById("root");
const root = createRoot(domElement);

root.render(<App />);
```

### Angular

Initializing the `@interopio/office` library in an Angular app:

```javascript
import { bootstrapApplication } from "@angular/platform-browser";
import { appConfig } from "./app/app.config";
import { App } from "./app/app";
import IOConnectOffice from "@interopio/office";

// Expose the API object as a global variable which you can use in all your components.
// The Outlook API will then be accessible via the `office.outlook` object.
window.office = await IOConnectOffice();

bootstrapApplication(App, appConfig);
```

## Tracking Outlook Adapter Status Changes

When **io.Connect Desktop** is initialized, you can check whether Outlook is running and the Outlook Adapter is loaded:

```javascript
console.log(`The Outlook Adapter is ${outlook.addinStatus ? "available" : "unavailable"}`);
```

You can use the [`onAddinStatusChanged()`](https://docs.interop.io/adapters/reference/javascript/outlook/api/index.md#API-onAddinStatusChanged) method to track the availability of the Outlook Adapter. You may find this useful if you need to track when to enable or disable certain elements of your app user interface.

```javascript
const handler = ({ connected }) => console.log(`The Outlook Adapter is ${connected ? "available" : "unavailable"}.`);

const unsubscribe = outlook.onAddinStatusChanged(handler);
```

The `connected` argument passed to your callback will be `true` if and only if:

- Outlook is running.
- The Outlook Adapter is installed and enabled in Outlook.
- The Outlook Adapter and your app are using the same connectivity configuration and are connected to the same io.Connect Gateway.

In any other case, the `connected` flag will be `false`.

To stop listening for connection status changes, simply call the returned function:

```javascript
unsubscribe();
```

## Working with Emails

### Default Settings

**Default Email Account**

By default, the Outlook Adapter picks the first email account and uses that for all API calls.

**Default Monitored Folder in Outlook**

By default, the Outlook Adapter is set up to monitor a folder at the level of your Inbox, called `GlueHandleEmail` (you have to create that folder yourself in Outlook). You can configure the Outlook folder monitoring (rename the default folder, add more custom monitored folders) by changing the settings in the `foldermonitor.yaml` located in `<installation_location>/interop.io/io.Connect Desktop/Outlook/UserConfig`.

**Allowed Folders**

Due to security reasons, **io.Connect Desktop** is configured to have access only to specific folders. Keep that in mind when you want to create attachments, save files, etc. Folder access can be customized by changing the settings in the `whitelist.yaml` file located in `<installation_location>/interop.io/io.Connect Desktop/config/enterprise`

### Creating New Emails

While there is no technical limitation for the Outlook Adapter to send an email, there are many reasons while this isn't a good idea. So, "creating a new email" actually means that the Outlook Adapter will create a new email window and populate it, but it won't send the email automatically and will instead let the user press the "Send" button. You can, however, track whether the user sends or cancels the email, as explained below in this document.

To create an email, use the [`newEmail()`](https://docs.interop.io/adapters/reference/javascript/outlook/api/index.md#API-newEmail) method and pass one or more email properties in an [`EmailParams`](https://docs.interop.io/adapters/reference/javascript/outlook/emailparams/index.md) object. The example below creates a new email with plain text. As with any email client, everything is optional - recipients, subject, body, etc.:

```javascript
const emailParams = {
    to: "someone@domain.com",
    cc: ["another@domain.com", "yetanother@domain.com"],
    subject: "Interesting topic",
    body: "Some plain text"
};

await outlook.newEmail(emailParams);

console.log("A New Email window has been shown");
```

> ⚠️ *Note that `to`, `cc` and `bcc` allow you to set a single recipient (in a single string) or multiple recipients in an array.*

> ⚠️ *Note that you can't specify the sender of the email. The Outlook Adapter will automatically use your email account and set it up as a sender.*

### Construct Emails with HTML

If you want to create an email with an HTML body, instead of setting `body`, set the `bodyHtml` property of the [`EmailParams`](https://docs.interop.io/adapters/reference/javascript/outlook/emailparams/index.md) object:

```javascript
const emailParams = {
    to: "manager@domain.com",
    subject: "Interesting report",
    bodyHtml: document.getElementById("reportTable").innerHTML
};

await outlook.newEmail(emailParams);
```

If you set both the `body` and `bodyHtml` properties, the `bodyHtml` property will take precedence.

### Tracking Sent or Canceled Emails

> ⚠️ *Note that when the `Promise` of [`newEmail()`](https://docs.interop.io/adapters/reference/javascript/outlook/api/index.md#API-newEmail) resolves, it means that the call from your web app to the Outlook Adapter has succeeded and it is guaranteed that the user will see a new email window populated with the parameters, as in the example above. However, this doesn't necessarily mean that the user will press the "Send" button.*

In order to track whether the user has sent the email or dismissed the window and discarded the email, you need to pass one or two optional callbacks (`onSent` and `onCanceled`) in the [`NewEmailOptions`](https://docs.interop.io/adapters/reference/javascript/outlook/newemailoptions/index.md) object to get notified whether the user has sent or canceled the email:

```javascript
const emailParams = {
    to: "someone@domain.com",
    subject: "Interesting topic",
    body: "Some plain text"
};

const options = {
    onSent: email => console.log("The user has sent the email", email),
    onCanceled: () => console.warn("The user has canceled the email")
};

await outlook.newEmail(emailParams, options);

console.log("A New Email window has been shown");
```

The `onSent` callback will pass you the email object which is of type [`T42Email`](https://docs.interop.io/adapters/reference/javascript/outlook/t42email/index.md). This object has a property `ids` which contains a set of IDs uniquely identifying the email in multiple systems (e.g., CRMs), including Outlook.

If you save the email IDs in your app, you can later use them to display the email in Outlook. Take a look at [Showing Emails](#working_with_emails-showing_emails) to see how.

### Creating Attachments

To attach files to a new email, you need to set the `attachments` property. There are two ways to add attachments to your emails:

- creating attachments directly from your app content;
- attaching existing files;

#### App Content

Suppose your app is displaying a list of customers, received as a `JSON` from a backend call. You can create a file from this data (e.g., CSV or HTML) and attach it to an email:

```javascript
const emailParams = {
    to: "someone@domain.com",
    subject: "Interesting topic",
    body: "Some plain text",
    attachments: [
        {
            // the "data" property expects base64 encoded data
            data: window.btoa(document.getElementById("customerList").innerHTML),
            fileName: "customers.html"
        }
    ]
};

await outlook.newEmail(emailParams);

console.log("A New Email window has been shown");
```

#### Existing Files

If you are using the Excel or Word Adapters and have created a file for which you know the file path, you can attach the file by specifying the file paths in the `attachments` property:

```javascript
const emailParams = {
    to: "someone@domain.com",
    // ...
    attachments: [pathToExcelWorkbook, pathToWordFile]
};

await outlook.newEmail(emailParams);

console.log("A New Email window has been shown");
```

### Email Monitoring & Notifications

Whenever an email arrives in a monitored folder, (e.g., from an Outlook rule which copies it from "Inbox"), your app can be notified about it. In order to subscribe for such events, you can use [`onEmailReceived()`](https://docs.interop.io/adapters/reference/javascript/outlook/api/index.md#API-onEmailReceived):

```javascript
const handler = email => console.log("An email arrived", email);

outlook.onEmailReceived(handler);
```

The `email` parameter is of type [`T42Email`](https://docs.interop.io/adapters/reference/javascript/outlook/t42email/index.md) and contains the standard `sender`, `to`, `subject`, etc. properties. This object has a property `ids` which contains a set of IDs uniquely identifying the email in multiple systems (e.g., CRMs), including Outlook.

If you save the email IDs in your app, you can later use them to display the email in Outlook. Take a look at [Showing Emails](#working_with_emails-showing_emails) to see how.

When an email arrives in the monitored folder, the Outlook Adapter will try to map the email addresses to Outlook contacts, so `sender`, `to`, `cc` and `bcc` will contain instances of [`T42Contact`](https://docs.interop.io/adapters/reference/javascript/outlook/t42contact/index.md).

In addition, any attachments in the `attachments` property will be instances of [`T42Attachment`](https://docs.interop.io/adapters/reference/javascript/outlook/t42attachment/index.md).

> ⚠️ *Note that the data in the attachments can be quite large and is delivered to your app on demand. If you need to get hold of the attachment data (encoded in Base64), you can call the [`getData()`](https://docs.interop.io/adapters/reference/javascript/outlook/attachment/index.md#Attachment-getData) method.*

```javascript
const handler = async (email) => {
    const imageAttachment = email.attachments.filter(a => a.name === "icon.png")[0];
    const imageData = await imageAttachment.getData();
    const img = document.getElementById("image");

    img.src = `data:image/png;base64,${imageData}`;
};

outlook.onEmailReceived(handler);
```

The attachment data is received in chunks, visible to your app, as it could be quite large. You might want to let the user view the progress or even cancel the download. The [`getData()`](https://docs.interop.io/adapters/reference/javascript/outlook/attachment/index.md#Attachment-getData) method allows you to pass an optional callback to report the progress and cancel the download if you return `true` from the callback:

```javascript
const handler = (percent) => {
    console.log(`Downloaded ${percent}%`);
    return userPressedCancelButton;
};

const data = await attachment.getData(handler);
```

### Saving Emails

If you have created a new email, the user has sent it and you want to save it in your app backend database, you can call the [`getAsMsg()`](https://docs.interop.io/adapters/reference/javascript/outlook/email/index.md#Email-getAsMsg) method of the [`Email`](https://docs.interop.io/adapters/reference/javascript/outlook/email/index.md) object and retrieve the message, including its attachments, as an Outlook MSG file, encoded in Base64:

```javascript
const emailParams = {
    subject: "...",
    attachments: [ ... ]
};

const options = {
    onSent: async (email) => {
        const msgData = await email.getAsMsg();
        saveEmail(msgData);
    }
};

await outlook.newEmail(emailParams, options);
```

You can use the same method if you want to save an email received from a monitored folder:

```javascript
const handler = async (email) => {
    const msgData = await email.getAsMsg();
    saveEmail(msgData);
};

outlook.onEmailReceived(handler);
```

### Showing Emails

If you have saved the IDs (the `ids` property in [`T42Email`](https://docs.interop.io/adapters/reference/javascript/outlook/t42email/index.md)) of an email either after the user has sent a new email, or when your app has received an email from a monitored folder, you can instruct Outlook to display this email using the [`showEmail()`](https://docs.interop.io/adapters/reference/javascript/outlook/api/index.md#API-showEmail) method. The `Promise` will resolve with the loaded email object:

```javascript
const email = await outlook.showEmail(ids);

console.log("Email shown", email);
```

## Working with Tasks

### Creating New Tasks

The call for creating a new task is very similar to the one for creating emails. You just need to call [`newTask()`](https://docs.interop.io/adapters/reference/javascript/outlook/api/index.md#API-newTask) and pass one or more task properties in a [`TaskParams`](https://docs.interop.io/adapters/reference/javascript/outlook/taskparams/index.md) object:

```javascript
const taskParams = {
    subject: "Go to gym tomorrow",
    startDate: new Date("2019-07-19"),
    dueDate: new Date("2019-07-19"),
    reminderTime: new Date("2019-07-19 12:45 UTC"),
    body: "Sweat is fat crying!",
    priority: "high"
};

await outlook.newTask(taskParams);

console.log("A New Task window has been shown");
```

Similarly to the [`newEmail()`](https://docs.interop.io/adapters/reference/javascript/outlook/api/index.md#API-newEmail) call, by default the Outlook Adapter won't create and save the task automatically but will display the task creation window. You can change the behavior and create and save the task automatically by setting the `noUI` to `true`.

If you want to be notified when the user saves or cancels the task, you need to pass one or two optional callbacks (`onSaved` and `onCanceled`) in the [`NewTaskOptions`](https://docs.interop.io/adapters/reference/javascript/outlook/newtaskoptions/index.md) object to be notified if the user has saved the task or this or another user has canceled it:

```javascript
const taskParams = {
    subject: "Go to gym tomorrow",
    startDate: new Date("2019-07-19"),
    dueDate: new Date("2019-07-19"),
    reminderTime: new Date("2019-07-19 12:45 UTC"),
    body: "Sweat is fat crying!",
    priority: "high"
};

const options = {
    onSaved: task => console.log("The user saved the task", task),
    onCanceled: () => console.warn("The user canceled the task")
};

await outlook.newTask(taskParams, options);

console.log("A New Task window has been shown");
```

The `onSaved` callback will pass you the task object which is of type [`T42Task`](https://docs.interop.io/adapters/reference/javascript/outlook/t42task/index.md). This object has a property `ids` which contains a set of IDs uniquely identifying the task in multiple systems (e.g., CRMs), including Outlook.

If you save the task IDs in your app, you can later use them to display the task in Outlook. Take a look at [Showing Tasks](#working_with_tasks-showing_tasks) to see how.

### Task Attachments

Task attachments work in the same way as email ones - to attach files to a new task, you need to set the `attachments` property. Again, just like for emails, the property supports:

- creating attachments directly from your app content;
- attaching existing files;

There are at least three kinds of attachments that can be added to a task - Word documents, created using the Word Adapter; Excel documents, created using the Excel Adapter; and Outlook MSG files, created by the Outlook Adapter.

Below is an example which saves an email as a task attachment:

```javascript
// task creation rule
async function createTaskByCEO(email) {
    if (email.sender.emails.includes("company.ceo@company.com")) {
        const data = await email.getAsMsg();

        const taskParams = {
            subject: `Review ${email.subject}`,
            body: email.body,
            startDate: new Date(),
            attachments: [{ data, fileName: `${email.subject}.msg` }],
            priority: "high"
        };

        await outlook.newTask(taskParams);
    }
}

const handler = (email) => {
    createTaskByCEO(email);
};

outlook.onEmailReceived(handler);
```

### Saving Tasks

If you have created a new task, the user has saved it and you want to save it in your app backend database, you can call the [`saveToFile()`](https://docs.interop.io/adapters/reference/javascript/outlook/task/index.md#Task-saveToFile) method of the [`Task`](https://docs.interop.io/adapters/reference/javascript/outlook/task/index.md) object and retrieve the task, including its attachments, as an Outlook MSG file, encoded in Base64:

```javascript
const taskParams = {
    subject: "...",
    attachments: [ ... ]
};

const options = {
    onSaved: async (task) => {
        const uri = await task.saveToFile();
        console.log(uri);
    }
};

await outlook.newTask(taskParams, options);
```

### Showing Tasks

If you have saved the IDs (the `ids` property in [`T42Task`](https://docs.interop.io/adapters/reference/javascript/outlook/t42task/index.md)) of a task after the user has saved it, you can instruct Outlook to display this task using the [`showTask()`](https://docs.interop.io/adapters/reference/javascript/outlook/api/index.md#API-showTask) method. The `Promise` will resolve with the loaded task object:

```javascript
const task = await outlook.showTask(ids);

console.log("Task shown", task);
```

## Reference

For a complete list of the available Outlook Adapter API methods and properties, see the [Outlook Adapter Reference Documentation](https://docs.interop.io/adapters/reference/javascript/outlook/index.md).
