OAuth 2, gSuite.gmail, Mail Plugin

Questions and answers on developing, deploying and using plugins and JavaBeans

OAuth 2, gSuite.gmail, Mail Plugin

Postby doctorface » Wed Dec 25, 2019 10:05 pm

I have been using the mail plugin in servoy to send outgoing email via gSuite/gmail. Currently I set the gSuite/gmail account to allow less secure apps and then authenticate with a gSuite/gmail username and password. This has worked great for many years.

gSuite will be turning off access to less secure apps (LSA) in two steps as follows
June 15, 2020 - Users who try to connect to an LSA for the first time will no longer be able to do so. This includes third-party apps that allow password-only access to Google calendars, contacts, and email via protocols such as CalDAV, CardDAV and IMAP. Users who have connected to LSAs prior to this date will be able to continue using them until usage of all LSAs is turned off.
February 15, 2021 - Access to LSAs will be turned off for all G Suite accounts.

Going forward authentication will have to be done with OAuth 2.0. I am wondering if the mail plug in will be modified in the near future to allow OAuth authentication. Alternatively if someone has a working example of how the current email plugin can be used with OAuth 2.0 (perhaps combining features of the OAuth plugin nd the Mail Plugin) to send email via gSuite or gmail that wouid be most appreciated.

Sincerely,

John McCann
doctorface
 
Posts: 3
Joined: Fri Jul 13, 2012 7:02 am

Re: OAuth 2, gSuite.gmail, Mail Plugin

Postby patrick » Thu Dec 26, 2019 11:34 am

From what I understand it comes down to this: you will need an oauth refresh token that is used as password and slightly different connection properties for this. It should work with these changes out of the box. Obviously, you will have to go through all the steps necessary for any oauth flow (setup your application for oauth, get a refresh token etc). I will have a look at that in January and see whether the plugin needs changes (the Java Mail libraries may need to be updated) and keep you updated.
Patrick Ruhsert
Servoy DACH
patrick
 
Posts: 3703
Joined: Wed Jun 11, 2003 10:33 am
Location: Munich, Germany

Re: OAuth 2, gSuite.gmail, Mail Plugin

Postby Harjo » Sat Dec 28, 2019 9:13 pm

👍🏻+1
Harjo Kompagnie
ServoyCamp
Servoy Certified Developer
Servoy Valued Professional
SAN Developer
Harjo
 
Posts: 4321
Joined: Fri Apr 25, 2003 11:42 pm
Location: DEN HAM OV, The Netherlands

Re: OAuth 2, gSuite.gmail, Mail Plugin

Postby doctorface » Mon Dec 30, 2019 12:23 am

Thanks so much Patrick. I look forward to you follow up post in early in 2020.

John McCann
doctorface
 
Posts: 3
Joined: Fri Jul 13, 2012 7:02 am

Re: OAuth 2, gSuite.gmail, Mail Plugin

Postby Harjo » Fri Jan 03, 2020 2:56 pm

The same is the case for Office 365: https://developer.microsoft.com/en-us/o ... customers/

Today, we are announcing that on October 13th, 2020 we will stop supporting and retire Basic Authentication for Exchange Active Sync (EAS), Post Office Protocol (POP), Internet Message Access Protocol (IMAP), and Remote PowerShell (RPS) in Exchange Online. This means that new or existing applications using one or more of these API’s/protocols will not be able to use Basic Authentication when connecting to Office 365 mailboxes or endpoints and will need to update how they authenticate.


So for the mail and mailPro plugin AND the Exchange plugin, will stop working after 13 october.
They all can handle mail ONLY with username & password, which will not be supported later this year. :shock:

here is some info on how to implement oAuth for javamail: https://javaee.github.io/javamail/OAuth2
Harjo Kompagnie
ServoyCamp
Servoy Certified Developer
Servoy Valued Professional
SAN Developer
Harjo
 
Posts: 4321
Joined: Fri Apr 25, 2003 11:42 pm
Location: DEN HAM OV, The Netherlands

Re: OAuth 2, gSuite.gmail, Mail Plugin

Postby patrick » Tue Jan 07, 2020 1:59 pm

A short update on this. I have tested it with the mail plugin and the mail pro plugin.

The first part is OAuth standard procedure:

1. you need to register your app with google via https://console.cloud.google.com/
2. specifically, you need an OAuth 2.0 client ID, which can be created in "API & Services" / "Credentials"
3. That will give you a client ID and secret

Once that is done, you need your user to authorize your app to use GMail, which can be done via the oauth plugin. The steps are roughly these:

Code: Select all
plugins.oauth.serviceBuilder(CLIENT_ID)
      .clientSecret(CLIENT_SECRET)
      .callback(getAccessTokenCallback, 30)
      .scope('https://mail.google.com/')
      .build(plugins.oauth.OAuthProviders.GOOGLE)


CLIENT_ID and CLIENT_SECRET in the code above are the ones you received when registering your app.

In the callback method (getAccessTokenCallback) you will then get a plugins.oauth.OAuthService object when everything went OK and the user granted the rights you asked for. That object has a getAccessToken() method that returns the access token used as the password for sending emails. This one you will have to store for that user.

Once you climbed over that hurdle, you can do this with the MailPro plugin:

Code: Select all
var smtpAcc = plugins.MailPro.SMTPAccount('smtp.gmail.com', 'from@gmail.com', accessToken);
smtpAcc.requiresAuthentication = true;
smtpAcc.useTLS = true;
smtpAcc.addSmtpProperty('mail.smtp.auth.mechanisms', 'XOAUTH2');
var msg = smtpAcc.createMessage('to@recipient.com', 'from@gmail.com', 'A test', 'My message')
var success = smtpAcc.sendMessage(msg);


For the standard mail plugin, something like this should work:

Code: Select all
var props = [];
props.push("mail.smtp.ssl.enable=true");
props.push("mail.smtp.auth.mechanisms=XOAUTH2");
props.push("mail.smtp.host=smtp.gmail.com");
props.push("mail.smtp.auth=true");
props.push("mail.smtp.user=from@gmail.com");
props.push("mail.smtp.password=" + accessToken);
plugins.mail.sendMail('to@recipient.com', 'from@gmail.com', 'A test', 'My message', null, null, null, props);


I hope this helps. Let me know your findings.
Patrick Ruhsert
Servoy DACH
patrick
 
Posts: 3703
Joined: Wed Jun 11, 2003 10:33 am
Location: Munich, Germany

Re: OAuth 2, gSuite.gmail, Mail Plugin

Postby patrick » Tue Jan 07, 2020 2:08 pm

One more remark: when testing this, you usually run off localhost:8080, which does not match any URL you registered with Google. To overcome this, you can edit the hosts file on windows and add something like

127.0.0.1 test.ruhsert.de

when test.ruhsert.de is the URL you entered when creating your client credentials. Then you need to run your NG Client from test.ruhsert.de:8080 instead of localhost:8080 and it should work (although showing a safety warning from google).
Patrick Ruhsert
Servoy DACH
patrick
 
Posts: 3703
Joined: Wed Jun 11, 2003 10:33 am
Location: Munich, Germany

Re: OAuth 2, gSuite.gmail, Mail Plugin

Postby swingman » Mon May 11, 2020 1:21 pm

Hi all,

I'm following Patricks sample and I'm struggling to get it to work...

I'm getting my refresh token back from Google and trying to use it instead of a password.

Or do I need to go back to Google to exchange it for an access token?
Or does the mail plugin do this for me?

Has anyone successfully sent email via google using oauth2?
There may be something really simple that I'm missing...
Christian Batchelor
Certified Servoy Developer
Batchelor Associates Ltd, London, UK
http://www.batchelorassociates.co.uk

http://www.postgresql.org - The world's most advanced open source database.
User avatar
swingman
 
Posts: 1472
Joined: Wed Oct 01, 2003 10:20 am
Location: London

Re: OAuth 2, gSuite.gmail, Mail Plugin

Postby patrick » Mon May 11, 2020 4:08 pm

Has anyone successfully sent email via google using oauth2?
Yes, I have when I tested that and posted the sample code above.

What goes wrong in your case? What error do you get? What plugin are you trying it with? Are you setting this mail.smtp.auth.mechanisms=XOAUTH2?
Patrick Ruhsert
Servoy DACH
patrick
 
Posts: 3703
Joined: Wed Jun 11, 2003 10:33 am
Location: Munich, Germany

Re: OAuth 2, gSuite.gmail, Mail Plugin

Postby swingman » Mon May 11, 2020 4:41 pm

Hi Patrick,

I'm using Servoy's mail plugin.

Code: Select all
   var properties = [];
   properties.push("mail.smtp.ssl.enable=true");
   properties.push("mail.smtp.auth=true");
   properties.push("mail.smtp.auth.mechanisms=XOAUTH2");
   properties.push("mail.smtp.host=smtp.gmail.com");
   properties.push("mail.smtp.username=" + globals.myEmailAddress);
   properties.push("mail.smtp.password=" + globals.myGmailPassword); //actually an Oauth2 token
    //properties.push('mail.smtp.port=587');
    //properties.push('mail.smtp.starttls.enable=true');
   //
   
   var success = plugins.mail.sendMail(to, from, subject, msg,null,null,null,properties);


with this I get an error

Code: Select all
Failed to send mail to<<recipient> 334 eyJzdGF0dXMiOiI0MDAiLCJzY2hlbWVzIjoiQmVhcmVyIiwic2NvcGUiOiJodHRwczovL21haWwuZ29vZ2xlLmNvbS8ifQ==


334 is an odd SMTP error.

I'm wondering whether the token I get back from Google is bad.

This my code for obtaining the token (may this is where I'm going wrong:)

Code: Select all
/**
* @properties={typeid:24,uuid:"F90B3954-3412-42F5-8B80-DBB1D5128E55"}
*/
function authorise_sending_email() {
   plugins.oauth.serviceBuilder(CLIENT_ID).clientSecret(CLIENT_SECRET).deeplink('google_oauth_callback').callback(google_oauth_callback, 30).scope('https://mail.google.com/').build(plugins.oauth.OAuthProviders.GOOGLE);
}

/**
*
* @properties={typeid:24,uuid:"7836A708-1111-4E6A-8B88-015BC5E18F80"}
*/
function google_oauth_callback(result, auth_outcome) {
   //plugins.dialogs.showInfoDialog('google_oauth_callback ' + result,'OK');

   //plugins.dialogs.showInfoDialog(auth_outcome,'OK');
   //plugins.dialogs.showInfoDialog(auth_outcome['code'],'OK');
   //plugins.dialogs.showInfoDialog(auth_outcome['scope'],'OK');

   var token = auth_outcome['code'];
   if (token) {
      var query = 'SELECT user_id FROM users WHERE user_name ILIKE ?';
      var args = [security.getUserName()];
      /** @type {JSFoundSet<db:/dbname/users>} */
      var fs = databaseManager.getFoundSet('dbname', 'users');
      if (fs.loadRecords(query, args) && fs.getSize() == 1) {
         var user = fs.getRecord(1);
         user.google_api_token = token;
         databaseManager.saveData();
         plugins.dialogs.showInfoDialog('Gmail','Successfully saved token for sending emails.', 'OK');
         forms.main.controller.show();
      }
      refreshUserEmailProperties();
   }
}


I use auth_outcome['code'] to get the token. If I use auth_outcome.getCode() I get null.
Also Google seems to call back twice. My deeplink comes back right away, while the google_oauth_callback fails after 30 seconds.
Christian Batchelor
Certified Servoy Developer
Batchelor Associates Ltd, London, UK
http://www.batchelorassociates.co.uk

http://www.postgresql.org - The world's most advanced open source database.
User avatar
swingman
 
Posts: 1472
Joined: Wed Oct 01, 2003 10:20 am
Location: London

Re: OAuth 2, gSuite.gmail, Mail Plugin

Postby patrick » Mon May 11, 2020 4:51 pm

I can't test this right now, but in my post above I say "getAccessToken()" should be used. If you type your auth_outcome parameter to plugins.oauth.OAuthService, you should see that method.
Patrick Ruhsert
Servoy DACH
patrick
 
Posts: 3703
Joined: Wed Jun 11, 2003 10:33 am
Location: Munich, Germany

Re: OAuth 2, gSuite.gmail, Mail Plugin

Postby swingman » Tue May 12, 2020 8:39 am

Hi Patrick,

I have taken a look at the Google OAuth Playground

https://developers.google.com/oauthplayground/

and what I get back when I check auth_outcome['code'] is in the exact same format as an authorisation code. And I'm trying to use it as a password which may be why I can't send emails.
getAccessToken() does not return anything, even when I typecast the auth_outcome.

Is there a Servoy-way to fetch the access_token from Google, as in step 2 of the playground: 'Exchange authorisation code for tokens' or does Servoy do this for me?

It would be very good to see some working sample code for this.
Christian Batchelor
Certified Servoy Developer
Batchelor Associates Ltd, London, UK
http://www.batchelorassociates.co.uk

http://www.postgresql.org - The world's most advanced open source database.
User avatar
swingman
 
Posts: 1472
Joined: Wed Oct 01, 2003 10:20 am
Location: London

Re: OAuth 2, gSuite.gmail, Mail Plugin

Postby swingman » Thu May 14, 2020 5:14 pm

Hi Patrick,

I appear to have solved the problem for now by using the way described in the webinar March 2019, using

Code: Select all
   service = plugins.oauth.getOAuthService(plugins.oauth.OAuthProviders.GOOGLE,CLIENT_ID,CLIENT_SECRET,'https://mail.google.com/',null,'on_authorize');
   application.showURL(service.getAuthorizationURL());


I did not try this a first because of the depression notice:
Creates an OAuth service that can be used to obtain an access token and access protected data. This method will be deprecated in the following versions, the preferred way is plugins.oauth.serviceBuilder with a callback function.
Christian Batchelor
Certified Servoy Developer
Batchelor Associates Ltd, London, UK
http://www.batchelorassociates.co.uk

http://www.postgresql.org - The world's most advanced open source database.
User avatar
swingman
 
Posts: 1472
Joined: Wed Oct 01, 2003 10:20 am
Location: London

Re: OAuth 2, gSuite.gmail, Mail Plugin

Postby emera » Fri May 15, 2020 9:18 am

patrick wrote:A short update on this. I have tested it with the mail plugin and the mail pro plugin.

The first part is OAuth standard procedure:

1. you need to register your app with google via https://console.cloud.google.com/
2. specifically, you need an OAuth 2.0 client ID, which can be created in "API & Services" / "Credentials"
3. That will give you a client ID and secret

Once that is done, you need your user to authorize your app to use GMail, which can be done via the oauth plugin. The steps are roughly these:

Code: Select all
plugins.oauth.serviceBuilder(CLIENT_ID)
      .clientSecret(CLIENT_SECRET)
      .callback(getAccessTokenCallback, 30)
      .scope('https://mail.google.com/')
      .build(plugins.oauth.OAuthProviders.GOOGLE)


CLIENT_ID and CLIENT_SECRET in the code above are the ones you received when registering your app.

In the callback method (getAccessTokenCallback) you will then get a plugins.oauth.OAuthService object when everything went OK and the user granted the rights you asked for. That object has a getAccessToken() method that returns the access token used as the password for sending emails. This one you will have to store for that user.

Once you climbed over that hurdle, you can do this with the MailPro plugin:

Code: Select all
var smtpAcc = plugins.MailPro.SMTPAccount('smtp.gmail.com', 'from@gmail.com', accessToken);
smtpAcc.requiresAuthentication = true;
smtpAcc.useTLS = true;
smtpAcc.addSmtpProperty('mail.smtp.auth.mechanisms', 'XOAUTH2');
var msg = smtpAcc.createMessage('to@recipient.com', 'from@gmail.com', 'A test', 'My message')
var success = smtpAcc.sendMessage(msg);


For the standard mail plugin, something like this should work:

Code: Select all
var props = [];
props.push("mail.smtp.ssl.enable=true");
props.push("mail.smtp.auth.mechanisms=XOAUTH2");
props.push("mail.smtp.host=smtp.gmail.com");
props.push("mail.smtp.auth=true");
props.push("mail.smtp.user=from@gmail.com");
props.push("mail.smtp.password=" + accessToken);
plugins.mail.sendMail('to@recipient.com', 'from@gmail.com', 'A test', 'My message', null, null, null, props);


I hope this helps. Let me know your findings.


If you are using the serviceBuilder then the auth_outcome in your callback method is a fully configured service in case of success (so if result is true).
The service object doesn't have a getCode method, but a getAccessToken() which returns the token you need to sign the requests.
However, I suggest you to use the createRequest or create(Get/Post/...)Request methods on the service because those also take care of the signing or refreshing the token in case it's expired.
You can see more samples on how to use those methods on the OAuthService in the developer.

Code: Select all
function someFunction() {
          plugins.oauth.serviceBuilder("0lqd1s0aw...")      //client/application ID
         .clientSecret("bIk6163KHi...")      //client secret
         .defaultScope("email")            //ask permission to get the user email
          .state("secret123337")            //anti forgery session state, required by the Facebook api
         .deeplink("deeplink_method")      //OPTIONAL deeplink method name or last part of your redirect URL, see docs
                               //if missing, a global method with the name 'deeplink_svy_oauth' will be generated
          .callback(callbackFunc, 30)          //see function below, timeout is 30 seconds
          .build(plugins.oauth.OAuthProviders.FACEBOOK);
}
   
function callbackFunc(result, auth_outcome) {
     if (result)
     {
           //SUCCESS
           var service = auth_outcome;
          application.output(service.getAccessToken()); // this is not really needed, but maybe you want to see what the access token is

                       //ACCESS SOME PROTECTED RESOURCE
          var response = service.executeGetRequest("https://graph.facebook.com/v2.11/me");
          if (response.getCode() == 200) {
              application.output(response.getBody());
             var json = response.getAsJSON();
             application.output("Name is "+json.name);
          }
         else {
          application.output('ERROR http status '+response.getCode());
         }
       else {
         //ERROR
         application.output("ERROR "+auth_outcome);//could not get access token, request timed out, etc..
      }
     }
}
emera
 
Posts: 44
Joined: Tue Jun 17, 2014 8:33 am

Re: OAuth 2, gSuite.gmail, Mail Plugin

Postby emera » Fri May 15, 2020 9:21 am

Google also provides a REST service to access a users's emails with oauth:
https://developers.google.com/gmail/api ... ssages/get
emera
 
Posts: 44
Joined: Tue Jun 17, 2014 8:33 am

Next

Return to Plugins and Beans

Who is online

Users browsing this forum: No registered users and 8 guests