We’re creating an app that accesses email-accounts via imap to import mails into our app to document what is happening in a project. The same with sending, we can send information from our system via the mailserver the customer uses.
We use the mailpro plugin to access the accounts and folders, and the user only has to enter infos about the server, like name, port and his username and password.
Beginning October 2022 Microsoft will remove the option to login with name and password (”basic authentication”) and will only allow users to login with “modern authentication” (OAuth).
Sending mail via SMTP can still be used, so customers with scanners / multi-function-devices that send scans via email will still work, but this has to be activated manually.
Microsoft will not offer the “application password” system like apple or google do to enable access to the account.
So we (and everyone else that uses imap with Office 365) will have to switch to the new authentification-flow described here: [Authenticate an IMAP, POP or SMTP connection using OAuth | Microsoft Learn](https://learn.microsoft.com/en-us/excha … cess-token)
An example with a postman-demonstration is found here: [OAuth 2.0 client credentials flow on the Microsoft identity platform - Microsoft identity platform | Microsoft Learn](https://learn.microsoft.com/en-us/azure … grant-flow)
So basically we are doing this:
we registered an app on [portal.azure.com](http://portal.azure.com) after creating a free account / using our existing Office 365 - Account
We got an app-id and a secret for accessing the app
we adapted the workflow from the postman-flow linked above for Servoy:
/**
* generated secret
* temporary key, works till 2022-10-01
* @type {String}
*
* @properties={typeid:35,uuid:"6534DE9D-2D01-4D93-BC45-BE8D011CF357"}
*/
var clientSecret = 'ZWt8Q~VS~HN_dE.Qrrmq4ymf-X5c0AesQBNgIcSf';
/**
* client-id, generated by Azure unpon registration
* @type {String}
*
* @properties={typeid:35,uuid:"F4FC6CD6-0814-4F12-A5F8-262B51FDF5DF"}
*/
var clientId = '1c62cf99-7745-4589-8f89-55f084f4d2a4';
/**
* @type {String}
*
* @properties={typeid:35,uuid:"8B665560-A9C8-4385-8EEE-53D59E4E6846"}
*/
var state = 'SecretSauce22';
/**
* @type {String}
*
* @properties={typeid:35,uuid:"2DF578C4-E259-46DF-83E1-A216A68567D5"}
*/
var scope = 'openid offline_access https://graph.microsoft.com/mail.read';
/**
* @type {String}
*
* @properties={typeid:35,uuid:"2E35486A-93C9-4C24-86A9-05EA139FFD7C"}
*/
var redirectUrl = 'http://localhost:8183/solutions/office365_test/m/onO365Authorize';
/**
* @type {String}
*
* @properties={typeid:35,uuid:"BE03A4A2-851D-4F19-AB0F-A19B21BDA5A6"}
*/
var user_email = 'Robert.Edelmann@BauProCheck.de';
/**
* Callback function, receives informations after users accepts login via OAuth
* has to be in scopes.globals of the main solution
* information should be transferred to the correct scope via
* scopes.office365.onO365Authorize(a,args);
* @param a
* @param args
*
* @properties={typeid:24,uuid:"D824F716-F42F-4525-8314-CBD408F3A547"}
*/
function onO365Authorize (a, args) {
if (args && args.hasOwnProperty('code') && args['code']) {
// application.output('found code: ' + args['code']);
getImapLoginToken(args['code']);
}
}
/**
* the function that starts it all;
* @properties={typeid:24,uuid:"004FDE7C-780E-4DAD-961C-BD1B30365919"}
*/
function authO365_idToken() {
var authURL = 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize?';
authURL += 'client_id=' + clientId;
authURL += '&response_type=code';
authURL += '&redirect_uri=' + redirectUrl;
authURL += '&response_mode=query';
authURL += '&scope=' + scope;
authURL += '&state='+state;
application.output('URL: ' + authURL);
application.showURL(authURL, '_blank');
}
/**
* @param {String} code code from authorization
* @properties={typeid:24,uuid:"87743126-4782-4CCD-AEEE-B5376C5FB1B2"}
*/
function getImapLoginToken(code) {
if (!code) {
return;
}
var httpClient = plugins.http.createNewHttpClient();
var request = httpClient.createPostRequest('https://login.microsoftonline.com/common/oauth2/v2.0/token');
request.addHeader('Content-Type', 'application/x-www-form-urlencoded');
var bodyContent = 'client_id='+clientId;
bodyContent += '&scope=https://outlook.office365.com/.default';
bodyContent += '&redirect_uri='+redirectUrl;
bodyContent += '&grant_type=authorization_code';
bodyContent += '&client_secret='+clientSecret;
bodyContent += '&code=' + code;
request.setBodyContent(bodyContent);
var response = request.executeRequest();
var statusCode = response.getStatusCode()
if (statusCode != 200) {
application.output('Error processing request, Statuscode ' + statusCode.toString() + '\n' + response.getResponseBody());
return;
} else {
// application.output(response.getResponseBody());
/** @type {{token_type: String, scope: String, expires_in: String, ext_expires_in: String, access_token: String, refresh_token: String, id_token: String}} */
var imapLoginObject = JSON.parse(response.getResponseBody());
if (imapLoginObject && imapLoginObject.hasOwnProperty('access_token') && imapLoginObject.access_token) {
getImapInbox(imapLoginObject.access_token);
}
}
}
/**
* uses the access_token to authenticate
* @param {String} [accessToken]
*
* @properties={typeid:24,uuid:"94418998-58D5-48A5-A448-A4CCC45BBD39"}
*/
function getImapInbox(accessToken) {
if (!accessToken) {
return;
}
var imapAccount = plugins.MailPro.ImapAccount('emailaccount', 'outlook.office365.com', user_email, accessToken);
imapAccount.port = 993
var props = {
"mail.imap.fetchsize": java.lang.Integer.parseInt('1048576'),
"mail.imaps.fetchsize": java.lang.Integer.parseInt('1048576'),
"mail.imap.connectionpoolsize": "10",
"mail.imaps.connectionpoolsize": "10",
'mail.imaps.starttls.enable': true,
'mail.imap.starttls.enable': true,
"mail.imap.ssl.enable": true,
"mail.imaps.ssl.enable": true,
"mail.imap.auth.mechanisms": "XOAUTH2",
"mail.imap.auth.plain.disable": true,
"mail.imaps.auth.mechanisms": "XOAUTH2",
"mail.imaps.auth.plain.disable": true
};
var rootFolder = imapAccount.connect(props);
if (!rootFolder || !imapAccount.connected) {
if (imapAccount.getLastError()) {
throw imapAccount.getLastError();
} else {
return;
}
}
var folder = imapAccount.getRootFolder()
var subFoldees = folder.getSubfolders();
for (var iFolders = 0; iFolders < subFoldees.length; iFolders++) {
try {
application.output(subFoldees[iFolders].name + ' -> ' + subFoldees[iFolders].getMessageCount().toString());
} catch (e) {
application.output('Error Accessing Folder: ' + e.name + ' -> ' + e.message + '\n' + e.stack,LOGGINGLEVEL.ERROR)
break;
}
}
}
The code has to be in the globals scope of a solution named office365_test for the callback to work.
The project can be found on [GitHub - RobertEdelmann1974/office365_test](https://github.com/RobertEdelmann1974/office356_test)
This works somehow, but the the accessToken for imap only has a very limited duration, after about 2 minutes we are no longer authenticated.
We have heard from other users who can access imap longer, but not really for more than 1 oder 2 hours.
Does anyone else have information about this workflow, if and where I am wrong or any other way, apart from going the route of using graph instead of imap when accessing emails?