I`m trying to send mails with flask-mail, which I achieved since anaccount#gmail.com, but in production we need to send the mail from anaccount#myowndomain.mx which fails because from "#gmail.com" i can permit less secure apps, but in bussiness gmail acount I can´t...so my question is...
¿Is there another way to permite less secure apps? or ¿How coul I do my app more secure?, a workaround?
thanks in advance.
here´s my flask-mail configuration.
from flask_mail import Mail, Message
app.config['MAIL_SERVER']='smtp.gmail.com'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USERNAME'] = '#myowndomain.mx'
app.config['MAIL_PASSWORD'] = '**********'
app.config['MAIL_USE_TLS'] = False
app.config['MAIL_USE_SSL'] = True
mail = Mail(app)
I solved the problem in base of this:
https://www.twilio.com/blog/2018/03/send-email-programmatically-with-gmail-python-and-flask.html
first you have to create a two step verification to your gmail account, then create an app password, and use this app pasword in the flask-mail configuration
Follow these steps
Enable "Less secure app" button in respective google account
Enable 2 step verification in respective account(complete the
steps which google prompts to setup 2 step verification)
Enable the App password which is present in security tab of
respective google account
Select the device and app option
copy paste the 16 digit app password your mail
configuration (e.g., MAIL_PASSWORD=16digit/character app password)
Related
I have an application developed in python that uses the SMPT service to connect to a gmail account. This type of connection is typified as an "Access of insecure applications" lesssecureapps.
To remedy this I have set myself the task of updating my app, using the gmail api and for authentication to use a private key generated from a service account (without using G-Suit).
I have created a first proof of concept and it seems that it connects and authenticates correctly, but when trying to get the labels of the gmail account I get the following message:
<HttpError 400 when requesting https://gmail.googleapis.com/gmail/v1/users/me/labels?alt=json returned "Precondition check failed.">
I recap the steps I have followed to configure my google account:
I access Google Api Console and enable the use of the gmail api through the button that appears at the top: Enable apis and services
I access the credentials section, click on the top button: "create credentials" and select Service account
I create a service account and then generate a private key in json format
I add a small code snippet with my proof of concept and it that returns the error that I comment on the top:
from google.oauth2 import service_account
from googleapiclient.discovery import build
SCOPES = ['https://mail.google.com/','https://www.googleapis.com/auth/gmail.modify','https://www.googleapis.com/auth/gmail.readonly','https://www.googleapis.com/auth/gmail.labels','https://www.googleapis.com/auth/gmail.metadata','https://www.googleapis.com/auth/gmail.addons.current.message.metadata','https://www.googleapis.com/auth/gmail.addons.current.message.readonly']
SERVICE_ACCOUNT_FILE = '/home/user/keys/privatekey_from_service_account.json'
credentials = service_account.Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes=SCOPES)
service = build('gmail', 'v1', credentials=credentials)
# Call the Gmail API
results = service.users().labels().list(userId='me').execute()
labels = results.get('labels', [])
if not labels:
print('No tienes labels.')
else:
print('Labels:')
for label in labels:
print(label['name'])
How can I solve my problem without using g-suite?
"Precondition check failed."
Means that you are not allowed to do what you are trying to do.
use a private key generated from a service account (without using G-Suit).
The Gmail api does not support service accounts for non gsuite domains. You can only use a service account with a Gsuite domain account and gsuite domain emails.
Services account wont work with normal google gmail accounts.
I am using Azure AD to authenticate the user in my Xamarin forms app and what I want to achieve in my UWP app that if one user lets says signed in the app and then signed out. On Next login flow Azure AD should show list of user who were logged in on that particular device so user can pick the user and just enter password.
In my case if I signout the user then it always start the flow from asking the email and password
Here is code snippet for signout
AuthenticationContext authContext = new AuthenticationContext($"{tenantUrl}/{tenantId}");
authContext.TokenCache.Clear();
Windows.Web.Http.Filters.HttpBaseProtocolFilter myFilter = new Windows.Web.Http.Filters.HttpBaseProtocolFilter();
var cookieManager = myFilter.CookieManager;
var cookieUri = new System.Uri(tenantUrl);
HttpCookieCollection myCookieJar = cookieManager.GetCookies(cookieUri);
foreach (HttpCookie cookie in myCookieJar)
{
cookieManager.DeleteCookie(cookie);
}
P.S: Seems to be issue for UWP ADAL package since samething is working fine on iOS
Great question!
There was a fix needed in ADAL (a new release needs to happen, so anything higher then 5.0.2-preview will have the fix) to handle this in UWP.
Add this code to your app:
var x = Windows.Security.Authentication.Web.WebAuthenticationBroker.GetCurrentApplicationCallbackUri();
Take the value (something like this: ms-app://s-1-15-2-111638678-219698677-36916742-1909548894-372823757-39941306-27685825/) and register the value as a redirectUri in the portal for this app.
Then, back in the code,
instead of passing in the above value (x) as the redirectURI, pass in null. ADAL/MSAL will set the redirect uri to https://sso which will route through the WebAuthenticationManager, and you should now see a list of the accounts, like on iOS.
You also might be interested in this documentation as well, especially if having issues on corp net.
With ADAL package, you won't see last logged in users email id. But if you use MSAL package by default, you will be able to see the list of last logged in users email id. I tried on my local machine and with MSAL package I am able to see the user's email id list. Below is the screenshot.
I hope the above information is helpful.
Desired Behaviour
Use Gmail, OAuth2 and Nodemailer to send an email from a server side node.js file.
What I've Tried
Relevant Documentation
https://nodemailer.com/smtp/oauth2
https://nodemailer.com/usage/using-gmail
https://developers.google.com/gmail/api/auth/web-server
Relevant Questions
send emails from MY gmail account with OAuth2 and nodemailer
How do I authorise an app (web or installed) without user intervention?
https://stackoverflow.com/a/47936349
https://stackoverflow.com/a/22572776
There were gaps in the instructions of the above sources and some information was outdated, so the answer below was my final implementation which appears to be working.
I'm posting this solution for confirmation it is best practice and, if it is, to save others time.
The following worked for me, there are two parts:
01) app.js
02) Google and OAuth2 setup
app.js
var nodemailer = require("nodemailer");
var transporter = nodemailer.createTransport({
host: 'smtp.gmail.com',
port: 465,
secure: true,
auth: {
type: 'OAuth2',
user: local_settings.my_gmail_username,
clientId: local_settings.my_oauth_client_id,
clientSecret: local_settings.my_oauth_client_secret,
refreshToken: local_settings.my_oauth_refresh_token,
accessToken: local_settings.my_oauth_access_token
}
});
var mail = {
from: "John Smith <me#mydomain.com>",
to: "user#userdomain.com",
subject: "Registration successful",
text: "You successfully registered an account at www.mydomain.com",
html: "<p>You successfully registered an account at www.mydomain.com</p>"
}
transporter.sendMail(mail, function(err, info) {
if (err) {
console.log(err);
} else {
// see https://nodemailer.com/usage
console.log("info.messageId: " + info.messageId);
console.log("info.envelope: " + info.envelope);
console.log("info.accepted: " + info.accepted);
console.log("info.rejected: " + info.rejected);
console.log("info.pending: " + info.pending);
console.log("info.response: " + info.response);
}
transporter.close();
});
Google and OAuth Setup
The code above requires the following setup:
01) Go to https://console.developers.google.com
02) If you don't have a project, you will be prompted to create one
03) Click on Create Project
04) Click on Create
05) Enter a Project Name and click Create
06) Select the Gmail API
07) Click on Enable
08) Click on Create Credentials
09) Enter the required settings
10) Give the OAuth client a name and ensure you add https://developers.google.com/oauthplayground as a redirect URI in order to generate the refresh and access tokens later
11) Define the consent screen settings
12) Click I'll do this later and Done
13) Click on the Edit icon, to view your Client ID and Client Secret
14) To generate access and refresh tokens, go to https://developers.google.com/oauthplayground
15) Click on the cog icon in the top right, check Use your own OAuth credentials and enter Client ID and Client Secret
16) In the left column, select Gmail API v1 and click Authorise APIs
17) If you are signed into multiple accounts, when prompted select the relevant account
18) Click Allow
19) Click Exchange authorisation code for tokens
I'm not sure why there is a count down on the access token, but hopefully the message at the bottom of the screen means that the token won't expire.
OAuth Consent Screen
You are definetely right about the gaps and outdated information, and you did a really great job on documenting the steps needed to use Gmail with OAuth and nodemailer!
Nevertheless, I think it worths mentioning that in the Credentials page there is another step: the OAuth Consent Screen tab.
It contains a form like a Google Play app submission that requires validation from Google, if you choose your app to not being validated, you have a limitation of 100 calls of what they call Sensitive scopes before being asked for submission.
What about quota?
It's still not clear to me if this 100 calls quota will be consumed even if you don't select any additional permission to use sensitive scopes (the default ones are email, profile, openid). I hope not, since the OAuth Consent Screen asks for things like the Application Homepage Link and Authorised domains that is something you might not have if you are working on a backend application.
I think that this whole procedure is really slow and uselessly complex since most people do all these steps to just send an email from their app using nodemailer...
We are building a solution that will need to access our customers Gmail accounts to read/send mail. On account signup, we'd have a pop-up for our customer to do Gmail auth page and then a backend process to periodically read their emails.
The documentation doesn't seem to cover this use case. For example https://developers.google.com/api-client-library/dotnet/guide/aaa_oauth says that client tokens should be stored in client_secrets.json - what if we have 1000s of clients, what then?
Service accounts are for non-user info, but rather application data. Also, if I use the GoogleWebAuthorizationBroker and the user has deleted access or the tokens have expired, I don't want my backend server app to pop open a web brower, as this seems to do.
I would imagine I could use IMAP/SMTP accomplish this, but I don't think it's a good idea to store those credentials in my db, nor do I think Google wants this either.
Is there a reference on how this can be accomplished?
I have this same situation. We are planning a feature where the user is approving access to send email on their behalf, but the actual sending of the messages is executed by a non-interactive process (scheduled task running on an application server).
I think the ultimate answer is a customized IAuthorizationCodeFlow that only supports access with an existing token, and will not execute the authorization process. I would probably have the flow simulate the response that occurs when a user clicks the Deny button on an interactive flow. That is, any need to get an authorization token will simply return a "denied" AuthorizationResult.
My project is still in the R&D phase, and I am not even doing a proof of concept yet. I am offering this answer in the hope that it helps somebody else develop a concrete solution.
While #hurcane's answer more than likely is correct (haven't tried it out), this is what I got working over the past few days. I really didn't want to have to de/serialize data from the file to get this working, so I kinda mashed up this solution
Web app to get customer approval
Using AuthorizationCodeMvcApp from Google.Apis.Auth.OAuth2.Mvc and documentation
Store resulting access & refresh tokens in DB
Use AE.Net.Mail to do initial IMAP access with access token
Backend also uses AE.Net.Mail to access
If token has expired, then use refresh token to get new access token.
I've not done the sending part, but I presume SMTP will work similarly.
The code is based on SO & blog posts:
t = EF object containing token info
ic = new ImapClient("imap.gmail.com", t.EmailAddress, t.AccessToken, AuthMethods.SaslOAuth, 993, true);
To get an updated Access token (needs error handling) (uses the same API as step #1 above)
using (var wb = new WebClient())
{
var data = new NameValueCollection();
data["refresh_token"] = refresh;
data["client_id"] = "(Web app OAuth id)";
data["client_secret"] = "(Web app OAuth secret)";
data["grant_type"] = "refresh_token";
var response = wb.UploadValues(#"https://accounts.google.com/o/oauth2/token", "POST", data);
string Tokens = System.Text.Encoding.UTF8.GetString(response);
var token = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(Tokens);
at = token.access_token;
return at;
}
we've created an single-signon with office for our webbapp.
Now we created an app for the office-store, but it was rejected with "Your app does not appear in the ‘My Apps’ launcher after authentication."
What we are currently doing:
send the user to https://login.windows.net/" + Configuration.getOfficeTenant() + "/oauth2/authorize
Fetch a token with the code https://login.microsoftonline.com/" + Configuration.getOfficeTenant() + "/oauth2/token
and then parse the id_token to get users name and email and log him in
How can we controll the "‘My Apps’ launcher" of the user? Do we need to make an additional api call? The page "https://msdn.microsoft.com/en-us/office/office365/howto/connect-your-app-to-o365-app-launcher" does not really point me to a solution - it seems that it should happen autmatically