Based on Set custom header (x-header) on Outlook compose mail with JS addin post, I used the following code to set a custom x-header when composing emails in OWA or Outlook 2019.
function addCustomHeadersAsync(classificationMarking) {
return new Office.Promise(function (resolve, reject) {
try {
/* The itemId property is not available in compose mode. If an item identifier is required,
the saveAsync method can be used to save the item to the store, which will return the item identifier in the asyncResult.value parameter in the callback function.*/
Office.context.mailbox.item.saveAsync(function (saveAsyncResult) {
/* The getCallbackTokenAsync method makes an asynchronous call to get an opaque token from the Exchange Server that hosts the user's mailbox.
The lifetime of the callback token is 5 minutes. The token is returned as a string in the asyncResult.value property.*/
Office.context.mailbox.getCallbackTokenAsync({ isRest: true }, function (getCallbackTokenAsyncResult) {
var ewsId = saveAsyncResult.value;
var token = getCallbackTokenAsyncResult.value;
var restId = Office.context.mailbox.convertToRestId(ewsId, Office.MailboxEnums.RestVersion.v2_0);
var getMessageUrl = Office.context.mailbox.restUrl + '/v2.0/me/messages/' + restId;
// The PropertyId for PS_INTERNET_HEADERS is {00020386-0000-0000-C000-000000000046}.
// https://learn.microsoft.com/en-us/office/client-developer/outlook/mapi/commonly-used-property-sets?redirectedfrom=MSDN
// https://stackoverflow.com/questions/38214197/set-a-custom-header-with-outlook-office-365-rest
var securityHeaders = JSON.stringify({
SingleValueExtendedProperties: [
{
PropertyId: "String {00020386-0000-0000-C000-000000000046} Name X-Custom-header",
Value: classificationMarking
}
]
});
// https://learn.microsoft.com/en-us/previous-versions/office/office-365-api/api/version-2.0/extended-properties-rest-operations#ExtendedpropertyoperationsCreateextendedpropertyinanewitem
// PATCH request is required to create an extended property in an existing item
var xhr = new XMLHttpRequest();
xhr.open('PATCH', getMessageUrl);
xhr.setRequestHeader("Accept", "application/json");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader("Authorization", "Bearer " + token);
xhr.onload = function (e) {
//console.log(this.response);
resolve();
}
xhr.send(securityHeaders);
});
});
}
catch (error) {
reject("Unable to set email custom security headers");
}
})
}
As on-premises Office 2019 + Exchange 2016 only supports API 1.5, I'm not able to use the new setCustomHeaders function which has been available since API 1.8 (https://learn.microsoft.com/en-us/office/dev/add-ins/outlook/internet-headers)
Everything works in https://outlook.office.com/mail/inbox & on-premises OWA (Exchange2016).
When using Outlook 2019 (online mode) :
The saveAsync function saves the draft
The XMLHttpRequest correctly sets the X-Custom-header : when calling the Exchange 2016 REST just after trying to set the XMLHttpRequest with a GET request, Exchange correctly reports the SingleValueExtendedProperties beeing set
After this step, when manually saving or sending the email, the SingleValueExtendedProperties seems to be removed or overwritten by Outlook which doesnt seems to be aware of this SingleValueExtendedProperties having been added to the draft email.
Same behavior noticed with Oulook 2019 on Office 365
Is this code correct to set custom email headers using SingleValueExtendedProperties with Outlook 2019 ?
How can I make Outlook 2019 aware of the new SingleValueExtendedProperties / x-header added to the draft message though the Exchange REST API ?
Edit 11/10/2021 : tested with makeEwsRequestAsync & test summary
Outlook 2019 build 2108 (Office 365)
Outlook on the web
Outlook 2019 build 1808 (Exchange 2016)
OWA Exchange 2016
Exchange REST API XMLHttpRequest
X-Custom-header correctly set server side but removed when sending the draft email from Outlook. If opening and sending the draft from OWA after having set the X-header from the addin in Outlook, X-Custom-header is preserved
OK
X-Custom-header correctly set server side but removed when sending the draft email from Outlook. If opening and sending the draft from OWA after having set the X-header from the addin in Outlook, X-Custom-header is preserved
OK
makeEwsRequestAsync()
OK
OK
X-Custom-header correctly set server side but removed when sending the draft email from Outlook. If opening and sending the draft from OWA after having set the X-header from the addin in Outlook, X-Custom-header is preserved
EWS request proxy error
What you are trying to do is not possible on Win32 Outlook Client. Your Step #2 (XMLHttpRequest) effectively creates two version of the item, one on the client and one on the server. When the item is eventually sent, one will overwrite the other (most likely the one sent from the client), and overrides the changes that you made.
setCustomHeaders in 1.8 was created to address this problem. setCustomHeaders, actually does not rely on the server for it's functionality, so it should work as long as your client supports 1.8.
Office 2019 (retail) does support 1.8. Office 2019 (volume-licensing) does not.
https://learn.microsoft.com/en-us/office/dev/add-ins/reference/requirement-sets/outlook-api-requirement-sets
Users on the volume licensed version will need to upgrade to get this support.
Related
I'm writing an Outlook OnSend addin (new style web addin, not old style COM), and would like to use a Service Worker to provide functionality when the user is offline. I've written an addin, and when I hit the addin's html page in Edge, I can see the service worker being installed and caching the addin files successfully.
However, when I run the addin in Outlook Desktop, it appears that the service worker is not being installed. I'm testing this by running Fiddler, and I can see that the adding files are being requested on each run, rather than coming from the cache that the service worker should be creating.
My addin HTML references a main.js (see below), which attempts to register the service worker. To provide some tracing/troubleshooting ability, I make an ajax call to a service. What this tells me is that:
The check for service worker support returns true
The call to navigator.serviceWorker.register never returns (successfully or otherwise)
Using Fiddler, I never see a request for the referenced "sw.js" file. I do see an edge process (microsoftedgesh) attempt to open an https connection to my server, but this doesn't request any files. All other traffic in fiddler is from the web view host component
Are service workers supported for outlook addins? I'm running Outlook version 2004 (12730.20270 click to run) and Windows 1909, so I'd expect Outlook to be using Edge rather than IE 11, and therefore to have service worker support.
For reference, my main.js looks like this:
if ('serviceWorker' in navigator) {
sendMessage('1');
try {
navigator.serviceWorker.register('sw.js').then(function(registration) {
sendMessage('2'); // Never sent
}).catch(function(error) {
sendMessage('3'); // Never sent
});
}
catch(err) {
sendMessage(err.message);
}
}
else {
sendMessage('4');
}
function sendMessage(message) {
$.ajax({
url: "../api/schedule",
type: "POST",
crossDomain: true,
//contentType: "jsonp",
contentType: 'application/json; charset=utf-8',
data: message
});
}
Service Workers are currently unsupported in addins and any Service Workers usage will be disabled in the near future.
We track add-in feature requests on our user-voice page. Please add your request there. Feature requests on user-voice are considered, when we go through our planning process
see update: Partial Solution
I'm using dailogflow and twilio to make whatsapp chatbot.
Text messages appears normally in both dialogflow and whatsapp.
Images appears only in dialogflow chatbot, but it is not working in whatsapp chatbot and makes error in twilio
This is the part of code which I'm adding to Inline Editor of DialogFlow fulfillment:
agent.add(new Card({
title: `Title: this is a card title`,
imageUrl: 'http://examplesitelink.com/image_name.png',
})
below the error message which I receive in twilio
MESSAGE
The URI scheme, of the URI null, must be equal (ignoring case) to 'http', 'https', 'ws', or 'wss'
......
HTTP retrieval failure
......
Possible Causes
Web server returned a 4xx or 5xx HTTP response to Twilio
Misconfigured Web Server
Network disruptions between Twilio and your web server
No Content-Type header attached to response
Content-Type doesn't match actual content, e.g. an MP3 file that is being served with Content-Type: audio/x-wav, instead of Content-Type: audio/mpeg
Is there anything I can do to solve this problem?
Partial Solution
Below a partial solution
I became able to send images to whats app via dialogflow fulfillment
First, in the 'package.json' I added twilio in dependencies, "twilio": "3.37.1" (check the latest version on npm twilio)
Second I added below code to send an image to whatsapp using its url, and it works
const client = require('twilio')('YOUR_ACCOUNT_SID', 'YOUR_AUTH_TOKEN'); /* change YOUR_ACCOUNT_SID and YOUR_AUTH_TOKEN to your own twilio account data */
client.messages
.create({
to: 'whatsapp:+13233633791', /* change it to your the number which you want to send the image to*/
from: 'whatsapp:+18007778888', /* change it to your the number which twilio sandbox provide, you can find it here: https://www.twilio.com/console/sms/whatsapp/sandbox */
body: "Hi Joe! Please find your boarding pass attached. Flight OA2345 departs at 11 pm PST.",
mediaUrl: 'https://emerald-coral-3661.twil.io/assets/2-OwlAir-Upcoming-Trip.PNG',
})
.then((message) => console.log(message.sid));
the problem now is:
In previous code, to is required, which means I have to specify the number which I want to send the image to, that looks odd, but the code will not work if I didn't specify to.
What I need to know is, how can I change: to: 'whatsapp:+13233633791', to any code can send the message to the current user who use whatsapp
I have also faced the same problem of not being able to send the media messages to any user that is using the chatbot currently. I found the solution to that in a youtube video, in which they have extracted the receiver mobile no. from the request object like below -
const data = request.body.originalDetectIntentRequest.payload;
const To = data.From;
const From = data.To;
Here the request object is the one you get when you create your dialogflow agent using the code below 'req' here-
app.post("/", express.json(), (req, res) => {
-------------------
-------------------
function handler() {
----------
}
intentMap.set("intent", handler);
}
I try to get event list from outlook with using Outlook REST API.
According to Microsoft document firstly; i need to subscribe outlook
Endpoint is: https://outlook.office.com/api/v2.0/me/subscriptions
It needs NotificationURL parameter to send notification when an event is changed.
I should implement a REST API(for NotificationURL) to pass outlook as parameter but i couldn't find any document.
What parameters should get my REST endpoint or what it is type(post,get,put etc...)
i appreciate your help
thank you!
My REST API Specifications that talk with Outlook API
If you wish to get a list of events you do not need to use subscriptions at all. Just use the procedure described here.
Microsoft has push notification api aka webhook for outlook events. For that you need to first register (create subscription for resource) webhook.
check out below code snippet that allows to send notification when any event created or updated on notification url.
doc here https://learn.microsoft.com/en-us/graph/webhooks#notification-endpoint-validation
POST https://graph.microsoft.com/v1.0/subscriptions
Content-type: application/json
{
"changeType": "created,updated",
"notificationUrl": "<YOUR-notification api endpoint>/api/notify",
"resource": "me/events",
"expirationDateTime":"2019-03-3T18:23:45.9356913Z",
"clientState": "myOutlookEvents"
}
You can use clientState to verify endpoint request that comes from MS Graph.
MS will POST data in below format
{
"value": [
{
"subscriptionId":"<subscription_guid>",
"subscriptionExpirationDateTime":2019-03-3T18:23:45.9356913Z",
"clientState": "myOutlookEvents",
"changeType":"created",
"resource":"users/{user_guid}#<tenant_guid>/event/{long_id_string}",
"resourceData":
{
"#odata.type":"#Microsoft.Graph.Event",
"#odata.id":"Users/{user_guid}#<tenant_guid>/event/{long_id_string}",
"#odata.etag":"W/\"CQAAABYAAADkrWGo7bouTKlsgTZMr9KwAAAUWRHf\"",
"id":"<long_id_string>"
}
}
]
}
After this you need to get the event from id that received from graph api
I was developing a few Office Outlook Web Add-ins and in none of them could I receive an response error message. Independently of the error that API returns I receive the following data object in fail function:
readyState: 0
responseText: ""
status: 0
statusText: "error"
withCredentials: true
Moreover in the Visual Studio or Browser JavaScript Console console I get:
Origin https://localhost:44347 not found in Access-Control-Allow-Origin header.
XMLHttpRequest: Network Error 0x80700013, Could not complete the operation due to error 80700013.
I would like to point out that CORS is enabled on the server, and I got this error independently from the action taken. It is the same when I give wrong parameter or make a typo in url.
I would also like to point out that API is OK, and such a thing does not happen when I request using JS in the browser (out of Office) or applications. I get a normal error messages from the server then.
In the example above the test is from localhost, but exactly the same situation is when hosted on remote web server.
What is wired about this is that I normally get success replies (with code and message).
What I would like to achieve is to get an error response as the server returns them. It is really hard to notify user what may be wrong with his request without this info.
[Edit]
For example, when I do the following request in a Outlook Add-in and I set the fake token I receive the mentioned error (or rather no error):
$.ajax({
type: 'GET',
url: API_URL + "/api/rooms/",
beforeSend: function (xhr) {
$.ajaxSettings.beforeSend(xhr);
xhr.setRequestHeader("Authorization", "Bearer " + token);
},
contentType: "application/json",
});
However, when I do the save request using Advanced REST Client I got 403:
"description": "You do not have permission to perform this action.",
"message": "",
"code": "permission-denied",
"status": "fail"
It happens in all Outlook version for me.
The issue is that the office add-in is sending a request to your web application over HTTP and the web project that gets created (I'm assuming you're using the Office add-in templates from visual studio) is by default configured for SSL, i.e an HTTPS connection. Whilst this is recommended for production apps, for debugging purposes you can simply click on your web project, then in visual studio click view on the Menu Bar - > then select the properties window -> then set SSL enabled to false. (see attached Image)
https://i.stack.imgur.com/Lvybn.png
Hope this helps!
I'm using Office JavaScript API to edit and save emails through an Add-in.
To get all attachments of an email, I use makeEwsRequestAsync. Most of the time the method is successful but sometimes it returns this error:
Failed to make a request via HttpWebRequest.
Exception: Unable to write data to the transport connection: An existing connection was forcibly closed by the remote host.
{
"value": null,
"status": "failed",
"error": {
"name": "GenericResponseError",
"message": "Failed to make a request via `HttpWebRequest`. Exception: Unable to write data to the transport connection: An existing connection was forcibly closed by the remote host.",
"code ": 9020
}
}
I'm working with Outlook 2016 Online (Office 365 ProPlus Version 1711) and I got the error on Windows 10 machine using both Chrome and Edge browsers.
EDIT:
Here is the full scenario:
Create new email
Hit send button
Add-in will intercept send event
Add-in saves email under draft using Office.context.mailbox.item.saveAsync that will return itemId
Once itemId is returned, try to load email headers and attachments (in parallel) by calling two makeEwsRequestAsync methods (using itemId with properly formated XML)
I can only think about 3 issues:
Is it possible that saveAsync returns an itemId that does not exist yet?
But in this case, I'm expecting a different error message.
Does calling 2 makeEwsRequestAsync simultaneously is problematic?
I don't think so. JavaScript is single threaded and the 2 methods are never called at the same time.
Is there a session timeout to communicate with EWS API?
Also, The error happens in different mailboxes and there is no other prior or post error.