Recent

Author Topic: Synapse ahd XOAUTH2 (gmail)?  (Read 37023 times)

epergola

  • Full Member
  • ***
  • Posts: 157
Synapse ahd XOAUTH2 (gmail)?
« on: July 03, 2015, 01:14:44 am »
Hi

Anybody knows how to send email with XOAUTH2 authentication?
Any clue whatsoever?

epergola

  • Full Member
  • ***
  • Posts: 157
Re: Synapse ahd XOAUTH2 (gmail)?
« Reply #1 on: July 03, 2015, 07:21:35 pm »
Ok, nobody knows.
 
I will ask this then.

Is there any free-pascal non-indy way to send emails that require XOAUTH2 authentication?

rvk

  • Hero Member
  • *****
  • Posts: 6111
Re: Synapse ahd XOAUTH2 (gmail)?
« Reply #2 on: July 03, 2015, 07:49:38 pm »
Yes, there is a way but I haven't found ready made examples.

You could look at the following article which does use indy:
http://wiert.me/2014/08/29/delphi-so-xoauth2-sasl-component-that-can-do-oauth2-via-asbjorn-heid-g/

But since you asked a non-indy way I guess you'll need to program the XOAUTH2-stuff yourself.

I did this once with the Google Calendar Api which also required xoauth2 authentication. I think there are more examples to be found like that now.

If I get a moment this weekend I can look if I can adjust the unit I got (for Calendar) to work for email.

epergola

  • Full Member
  • ***
  • Posts: 157
Re: Synapse ahd XOAUTH2 (gmail)?
« Reply #3 on: July 04, 2015, 12:54:39 am »
Thanks.
If you find time, would that adaptation be for free-pascal (i.e. something that could be called from inside a Lazarus application)?
I would like my application bo be able to allow the user to send email using his/her
gmail account.

BeniBela

  • Hero Member
  • *****
  • Posts: 905
    • homepage
Re: Synapse ahd XOAUTH2 (gmail)?
« Reply #4 on: July 04, 2015, 01:23:22 am »
In theory, OAUTH2 is extremely simple.

You just need to make 2 HTTP requests.,,

And another one to send the mail, if you want to send it through the API instead SMTP.

But I still needed to 2 hours to find the correct parameters :(  :

http://wiki.lazarus.freepascal.org/Internet_Tools#Using_Google_Mail.2C_other_Google_APIs.2C_or_OAUTH2

(not Synapse specific)

Quote from: Google Docs https://developers.google.com/gmail/api/guides/sending
     

Emails are sent as base64url encoded strings within the raw property of a message resource. The high-level workflow to send an email is to:

    Create the email content in some convenient way and encode it as a base64url string.
    Create a new message resource and set its raw property to the base64url string you just created.

Screw you, Google. >:( >:(

It only works, when the mail  is not base64url encoded


rvk

  • Hero Member
  • *****
  • Posts: 6111
Re: Synapse ahd XOAUTH2 (gmail)?
« Reply #5 on: July 04, 2015, 01:38:12 am »
In theory, OAUTH2 is extremely simple.

You just need to make 2 HTTP requests.,,
Yeah, in theory :D

I would also advise against authorizing each time you want to send a mail. You need to reuse the access_token. And these expire after some time. So after that time you need to get a new access_token with the refresh_token. That way only one time authentication is needed. (edit: Aaah, I see you also mentioned that in the comments)

I have a 'small' library which does just that. It checks if the access_token is expired and if so it will get a new one with the refresh_token. If that's not present the authentication to the user happens to get access to mail/profile and/or calendar. It will automatically detect the accept from the user in the browser (sorry, Windows only). I just need to test this with the correct (E-Mail) scope and try to send a mail via TSMTPSend from Synapse.

When I get a working example I'll post it here (unless somebody else already has a working solution).


Edit: I have it working. It's too late now but I'll clean up the code tomorrow and post it.
« Last Edit: July 04, 2015, 02:17:40 am by rvk »

rvk

  • Hero Member
  • *****
  • Posts: 6111
Re: Synapse ahd XOAUTH2 (gmail)?
« Reply #6 on: July 04, 2015, 04:45:13 pm »
Ok, here goes. (I hope I done everything correctly. It's my first open-source project)

https://github.com/rvk01/google-oauth2
You can download it with the button on the lower right ("Download Zip").

I kept my Api-credentials in the test-application but of course when you're going to deploy your application you need to create your own. (The consent screen of Google shows my application title) For testing-purposes you can use the one I kept in frmmain.pas.

You need to put libeay32.dll, libssl32.dll and ssleay32.dll in your project directory (I assume you can get your hands on those).

Then the important file is google_oauth2.pas. It implements a TGoogleOAuth2 class which you can use to get access to someones account.
Code: [Select]
var
  gApi: TGoogleOAuth2;
begin
  gApi := TGoogleOAuth2.Create(client_id, client_secret);
  gApi.GetAccess([goMail], True); // <- get from file
  //...

The true in the GetAccess is that the Access and Refresh_tokens are stored in a file named tokens.dat. If you use false then you'll need to store these tokens yourself and set them accordingly.
Code: [Select]
var
  gApi: TGoogleOAuth2;
begin
  gApi := TGoogleOAuth2.Create(client_id, client_secret);
  gApi.Refresh_token := my_stored_Refresh_token;
  gApi.Access_token := my_stored_Access_token;
  gApi.GetAccess([goMail], False); // <- do not use the tokens.dat file

  // SAVE THESE TOKENS
  my_stored_Refresh_token := gApi.Refresh_token;
  my_stored_Access_token := gApi.Access_token;

  //...

In the test-app you can press "Get GMail access" and it will store tokens in a file. After that you can change the recipient and press "Send mail". If you do this without doing the "Get GMail access" first it will also do the authentication first. So the "Get GMail access" is not strictly necessary. After that there is no more need for authentication. The tokens are stored and reused until they expire in which case the GetAccess will try to refresh them. In case it fails it will automatically ask for authentication again.

Now that the mechanism is in place to get the access_token you can go on to sending the mail. You wanted to do this with Synapse. The problem with TSMTPSend in Synapse is that it doesn't provide you the ability to issue your own commands during connection build-up.

And for sending mail via smtp.gmail.com you'll need to issue a command AUTH XOAUTH2 <AUTH_TOKEN_base64> during the connect. I made a small class helper to do just that.

After that it was just simply a matter of sending the mail-data and everything should be working ok.

Try the test-application xoauth2_test. I hope everything works correctly.

(P.S. At the moment this is Windows-only. I will be doing some recoding in the future to make it Linux-compatible but at the moment it uses a small Internet Explorer browser to show the user the first time consent screen. The biggest problem with Linux would be to get the user-code after giving consent from the browser-object. If somebody has an idea about that....? I haven't got that much experience with Linux-desktops)

epergola

  • Full Member
  • ***
  • Posts: 157
Re: Synapse ahd XOAUTH2 (gmail)?
« Reply #7 on: July 06, 2015, 01:10:22 am »
Thnaks both of you.
Rvk I still cannot try your code because I am stuck with en error at compiling the IDE
(I posted in the LCL forum)
. I will let you know when I will.

epergola

  • Full Member
  • ***
  • Posts: 157
Re: Synapse ahd XOAUTH2 (gmail)?
« Reply #8 on: July 07, 2015, 12:07:14 am »
Good thing: it compiled.
Bad thing: I get this error:
Getting account information
Error: 403 - Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup.
Invalid access_token
Authorizing...
You don't have access
Maybe I'll try tomorrow to see if the "daily" thing gets resolved.
However, If i put this code inside my app, everytime the user sends an email it will go in that google internet web form first?

rvk

  • Hero Member
  • *****
  • Posts: 6111
Re: Synapse ahd XOAUTH2 (gmail)?
« Reply #9 on: July 07, 2015, 04:17:56 am »
No, it should only ask for permission once. After that the access-token gets stored and can be used for some time without showing the web-dialog. After the access-token expires a new access-token is received (via the refresh-token) also without the web-dialog. Only when something goes wrong with the authentication the web-dialog would appear.

The first time you run this the programs tried to access the api with an access-token which isn't initiated yet. That's why you get a 403. It's normal. I could see if I can remove it. After that it tried to gain access to the account and does the web-dialog.

You did click accept in the web-dialog?? To give permission to the app??

P.s. In your end application you would need to set new credentials which you can create in the google api console. (For testing you could keep the one in the test-app for now)

rvk

  • Hero Member
  • *****
  • Posts: 6111
Re: Synapse ahd XOAUTH2 (gmail)?
« Reply #10 on: July 07, 2015, 11:27:11 am »
Getting account information
Error: 403 - Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup.
Invalid access_token
Authorizing...
You don't have access
I made some changes to google_oauth2.pas. (in https://github.com/rvk01/google-oauth2)
You don't get a 403 anymore when the initial authentication is not yet done.

In your log you have "Authorizing" and directly after it you have "You don't have access". That leads me to believe you didn't click the Accept button in the Consent-screen. You need to give a one time permission to the app to send mail on your behalf. Normally, when the permission is given, this is a one time action. After that, the app receives a token which it can use in subsequent access.

If however, you didn't get the consent-screen (or you got the screen and accepting it didn't work) I'd like to know. Maybe something went wrong with "reading-out" the caption of the Internet.Explorer window. In that case I could build in a method for the user to manually enter the received access-token (or find out why reading out the caption didn't work).

epergola

  • Full Member
  • ***
  • Posts: 157
Re: Synapse ahd XOAUTH2 (gmail)?
« Reply #11 on: July 07, 2015, 09:52:02 pm »
I tried the new version.
Acces to Mail checkbox is checked.
I clicked once Get accessd and I did click on Accept on the subsequent form.
Bu I still get
Authorizing...
Autorization not accepted
We don't have access
I had not changed anything in the credentials as you said I could use them as is for test.

epergola

  • Full Member
  • ***
  • Posts: 157
Re: Synapse ahd XOAUTH2 (gmail)?
« Reply #12 on: July 07, 2015, 10:02:35 pm »
Oops!
Now, when I tried to run the app again, I got a blank form, with nothing shown on it.
Even after I exited Lazarus and reconstructed the project.

rvk

  • Hero Member
  • *****
  • Posts: 6111
Re: Synapse ahd XOAUTH2 (gmail)?
« Reply #13 on: July 08, 2015, 12:11:05 am »
I clicked once Get accessd and I did click on Accept on the subsequent form.
Bu I still get
Authorizing...
Autorization not accepted
We don't have access
That's very weird. I tried this a lot of times and everytime it works for me. I'm on Windows 7 64 bit with standard updated internet explorer.

On what Windows version are you? And what version of Lazarus? (I'll test it on the same)

I think the problem is in getting the access_token from the browser. If I don't get the same as you (on the same OS version I'll try to build in same more debugging).

rvk

  • Hero Member
  • *****
  • Posts: 6111
Re: Synapse ahd XOAUTH2 (gmail)?
« Reply #14 on: July 08, 2015, 03:23:14 pm »
I released a new version on https://github.com/rvk01/google-oauth2.

*)
It has the ability to take the authorization-code from the browser-titlebar. I remember this didn't work some time ago but maybe Google fixed it. (the code used to be cut off at some point) So maybe that method works better now. (It's the default method now)

*)
If that doesn't work you can uncheck the "Use browser-title for authentication-code" after which the library tries to get the authorization-code from the returned HTML. You can go to the debug-tab to see exactly what the program gets as HTML-text. Maybe there is something wrong there. I do a lookup for readonly="readonly" value=" in the text and try to extract the code. But perhaps that doesn't work at your end. (it works for me though)

*)
And finally... if that doesn't work you can check "Force manually input of authentication_token". In that case there is an inputbox behind the browser. You van accept on the consent-screen after which you see a authorization-code in the screen. You can click and copy it, close the browser and paste it in the inputbox. Press OK and you should have access.

If only the manual-method works I would like to know what the debug-screen gives you with the other two methods (so I can fix it).

 

TinyPortal © 2005-2018