Currently, OpenFin does not provide a direct mechanism to interoperate with Microsoft Outlook Client. However, it is possible to achieve data sharing between OpenFin and Outlook through MIME (Multipurpose Internet Mail Extensions). MIME is a user-readable, well-documented text-based format defined by a set of Internet standards that extend the email message format. It is fully supported by Outlook. This document provides a recipe to automate the process of creating Text/HTML emails programmatically and passing them to Outlook for editing.
Message structure
In this document, we use an example of an email message with an embedded image in it. We show how to generate a MIME message, which is essential a very long string with a specific structure.
The following data structure represents the email message that we want to generate.
export interface IEmail {
from: string;
to: string;
subject: string;
date: string;
image: {
cid: string; // an ID for this image unique within this message
base64: string; // image data encoded as base64
}
}
Generating a MIME string
The MIME string we want to generate consists of the following parts:
- MIME header
- Multipart boundary definition
- Message body part
- Image attachment part
- Closing boundary
MIME header
MIME-Version: 1.0
From: ${email.from}
To: ${email.to}
Subject: ${email.subject}
Date: ${email.date}
X-Unsent: 1
Note: Setting the X-Unsent
field tells Outlook to open this message in editor mode instead of viewer mode.
Multipart boundary definition
The message contains an embedded image and refers to this image from HTML in the message body. For MIME, non-text content (such as images, audio, and video) is defined via media types. For this example, we will be using the multipart/related
content type with a named boundary marker. After the definition of the boundary, use ‘--’ followed by the boundary name to mark the boundary for each part. Choose a string for the boundary name that would never appear in a message body.
Content-Type: multipart/related;
boundary="my_boundary_name"
Message body part
The first part of the MIME content for the message contains the HTML code, which will be displayed by the recipient’s email program as the styled message body.
--my_boundary_name
Content-Type: text/html; charset="utf-8"
<html>
<head></head>
<body>
Some Text
<img src="cid:${email.image.cid}"/>
</body>
</html>
Note: cid: property
in the img
element tells Outlook to look for an embedded image with the specified content ID.
Image attachment part
The next part of the MIME string contains the data definition for the embedded image and is encoded as base64. We can replicate this part to embed multiple images or alternative media supported by MIME in our message and refer them within the HTML body.
--my_boundary_name
Content-Type: IMAGE/PNG; name="${email.image.cid}.png"
Content-ID: <${email.image.cid}>
Content-Transfer-Encoding: base64
Content-Disposition: inline; filename="${email.image.cid}.png"
${email.image.base64}
Note: The Content-ID
field uses the same string value as the image source in the HTML body.
Closing boundary
We finalize the MIME string with a closing boundary delimiter:
--my_boundary_name
Passing MIME from OpenFin to Outlook for editing
The following code passes the generated MIME as an eml
file from an OpenFin window to Outlook.
This code does the following:
- Registers a listener to track downloads within the OpenFin window.
- Triggers a download for the MIME string as an eml file.
- Passes the downloaded eml file to Outlook for editing.
Note: generateMime()
is not defined here. It is a function that generates a MIME string as described in the preceding sections.
// Path to Downloads folder
const downloadPath = 'C:/Users/username/Downloads';
// Generate mime string
const mime: string = generateMime(email);
// Callback for file download listener
const onDownloadComplete = async (event) => {
if (event.state === 'completed') {
// Launch outlook with downloaded eml file as the parameter
await fin.System.launchExternalProcess({
path: 'outlook.exe',
arguments: `/eml ${downloadPath}/email.eml`
});
}
// Cleanup
window.removeListener('file-download-completed',
onDownloadComplete);
};
// Download mime string as an eml file
const triggerDownload = () => {
const element = document.createElement('a');
// Encode mime string as octet-stream
element.setAttribute('href',
`data:application/octet-stream,${encodeURIComponent(mime)}`);
element.setAttribute('download', `email.eml`);
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
};
// Trigger
const window = await fin.Window.getCurrent();
window.addListener('file-download-completed', onDownloadComplete);
triggerDownload(mime);
Permissions
The launchExternalProcess()
call in the onDownloadComplete()
callback method is a secured API method and must be declared in the application manifest. Therefore, we add the following definition to the app manifest:
"permissions": {
"System": {
"launchExternalProcess": true
}
}
Note: Starting in v20 of OpenFin, the Desktop Owner Settings must grant permission to use this API method. That is, the app manifest requests the permission and the DOS grants it.
See also
Comments
0 comments
Please sign in to leave a comment.