Message insert - adding external label - gmail-api

I'm using gmail API to insert an email to the inbox. When the From domain is outside the organization, I expect the external label to be added but it's not.
I'm using python and everything else is working, I am using a service account and able to impersonate on behalf the user's email and I'm using labelIds of ['INBOX', 'UNREAD'] and I need the newly external label as well but couldn't figure a way to add it through the API.
This feature is turned ON for the workspace.
Update - adding my code:
from googleapiclient import discovery, errors
from google.oauth2 import service_account
from email.mime.text import MIMEText
import base64
SERVICE_ACCOUNT_FILE = 'insert-messages-91e77b62878f.json'
SCOPES = ['https://www.googleapis.com/auth/gmail.insert']
def validationService():
# Set the credentials
credentials = service_account.Credentials.\
from_service_account_file(SERVICE_ACCOUNT_FILE, scopes= SCOPES)
# Delegate the credentials to the user you want to impersonate
delegated_credentials = credentials.with_subject('<some_user>')
service = discovery.build('gmail', 'v1', credentials=delegated_credentials)
return service
def SendMessage(service, message):
message = service.users().messages().insert(userId='me', body=message).execute() # me will use <some_user> from above
return message
def CreateMessage(sender, to, subject, message_text):
message = MIMEText(message_text)
message['To'] = to
message['From'] = sender
message['Subject'] = subject
return {'raw': base64.urlsafe_b64encode(message.as_string().encode()).decode(), 'labelIds': ['INBOX', 'UNREAD']}
def main():
try:
service = validationService()
email = CreateMessage('some#external.com', "<some_user>", "Test", "This is a test")
email_sent = SendMessage(service, email)
print('Message Id:', email_sent['id'])
except errors.HttpError as err:
print('\n---------------You have the following error-------------')
print(err)
print('---------------You have the following error-------------\n')
if __name__ == '__main__':
main()

Related

How to I send a authentication token from firebase to my django backend so that it may add that user in the admin of django?

Like this is the code I have used in my backend part of Django..My frontend is in ReactJS
default_app = firebase_admin.initialize_app(cred)
class FirebaseAuthentication(authentication.BaseAuthentication):
def authenticate(self, request):
auth_header = request.META.get("HTTP_AUTHORIZATION")
if not auth_header:
raise NoAuthToken("No auth token provided")
id_token = auth_header.split(" ").pop()
decoded_token = None
try:
decoded_token = auth.verify_id_token(id_token)
except Exception:
raise InvalidAuthToken("Invalid auth token")
pass
if not id_token or not decoded_token:
return None
try:
uid = decoded_token.get("uid")
except Exception:
raise FirebaseError()
user, created = User.objects.get_or_create(username=uid)
user.profile.last_activity = timezone.localtime()
return (user, None)
I have just written this in backend and now am wondering where and how do I call this and how will be token received here.Thank you so much in advance

Error in feching message from gmail api with multiple queries

I want to get unread mails from yesterday. So i had to implement multiple queries in the message.list function which give me an error of invalid syntax. How do i do it? Can someone help me? And will internalDate help me anyway?
from __future__ import print_function
import httplib2
import os
from email.utils import parsedate_tz,mktime_tz,formatdate
from requests.adapters import HTTPAdapter
import datetime
from datetime import date,timedelta
import time
from apiclient import discovery
import oauth2client
from oauth2client import client
from oauth2client import tools
import json
try:
import argparse
flags = argparse.ArgumentParser(parents=[tools.argparser]).parse_args()
except ImportError:
flags = None
SCOPES = 'https://www.googleapis.com/auth/gmail.readonly'
CLIENT_SECRET_FILE = 'client_server.json'
APPLICATION_NAME = 'Gmail API Python Quickstart'
def get_credentials():
"""Gets valid user credentials from storage.
If nothing has been stored, or if the stored credentials are invalid,
the OAuth2 flow is completed to obtain the new credentials.
Returns:
Credentials, the obtained credential.
"""
home_dir = os.path.expanduser('~')
credential_dir = os.path.join(home_dir, '.credentials')
if not os.path.exists(credential_dir):
os.makedirs(credential_dir)
credential_path = os.path.join(credential_dir,
'gmail-python-quickstart.json')
store = oauth2client.file.Storage(credential_path)
credentials = store.get()
if not credentials or credentials.invalid:
flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES)
flow.user_agent = APPLICATION_NAME
if flags:
credentials = tools.run_flow(flow, store, flags)
else: # Needed only for compatibility with Python 2.6
credentials = tools.run(flow, store)
print('Storing credentials to ' + credential_path)
return credentials
def main():
da=date.fromordinal(730920)
credentials = get_credentials()
http = credentials.authorize(httplib2.Http())
service = discovery.build('gmail', 'v1', http=http)
today=date.today()
print (today)
yesterday=today-timedelta(1)
print (yesterday)
response = service.users().messages().list(userId='me',q='{in:inbox is:unread} AND {after: {0}.format(yesterday.strftime('%Y/%m/%d'))}').execute()
messages=[]
store=[]
message1=[]
test2=[]
da=[]
if 'messages' in response:
messages.extend(response['messages'])
fo = open("foo.txt", "wb")
for i in range(len(messages)):
store=messages[i]['id']
message = service.users().messages().get(userId='me',id=store,format='metadata',metadataHeaders=['from','date']).execute()
fo.write(store+" ");
#print(message['payload']['headers'][0])
fo.write(message['snippet'].encode('utf-8')+" ")
if message['payload']['headers'][0]['name'].lower()=="from":
From=message['payload']['headers'][0]['value']
fo.write(From+" ");
elif message['payload']['headers'][0]['name'].lower()=="date":
da=message['payload']['headers'][0]['value']
fo.write(da+"\n");
for line in open("foo.txt"):
print(line)
# Open a file
# Close opend file
fo.close()
if __name__ == '__main__':
main()
Use:
q='in:inbox is:unread newer_than:3d'
as the query. Gmail queries don't have a concept of timezones so if you try to get one day worth of email you'll end up with some overlap. Just use local filtering to narrow those down. See advanced Gmail search for more help. The API and Gmail UI use the same query syntax and should show the same results so you can do testing in the UI.

upload text file to google drive using python every 5 seconds

how can i modify the following python code to upload the ecg.txt to google drive every 5 seconds where i update this text file. the code now ask for Oauth every time it upload the file , i want it to ask for authentication only in the first time.
#!/usr/bin/python
import httplib2
import pprint
from apiclient.discovery import build
from apiclient.http import MediaFileUpload
from oauth2client.client import OAuth2WebServerFlow
# Copy your credentials from the console
CLIENT_ID = XXXXXX
CLIENT_SECRET = XXXXX
# Check https://developers.google.com/drive/scopes for all available scopes
OAUTH_SCOPE = 'https://www.googleapis.com/auth/drive'
# Redirect URI for installed apps
REDIRECT_URI = 'urn:ietf:wg:oauth:2.0:oob'
# Path to the file to upload
FILENAME = 'ecg.txt'
# Run through the OAuth flow and retrieve credentials
flow = OAuth2WebServerFlow(CLIENT_ID, CLIENT_SECRET, OAUTH_SCOPE, REDIRECT_URI)
authorize_url = flow.step1_get_authorize_url()
print 'Go to the following link in your browser: ' + authorize_url
code = raw_input('Enter verification code: ').strip()
credentials = flow.step2_exchange(code)
# Create an httplib2.Http object and authorize it with our credentials
http = httplib2.Http()
http = credentials.authorize(http)
drive_service = build('drive', 'v2', http=http)
# Insert a file
media_body = MediaFileUpload(FILENAME, mimetype='text/plain', resumable=True)
body = {
'title': 'My document',
'description': 'A test document',
'mimeType': 'text/plain'
}
file = drive_service.files().insert(body=body, media_body=media_body).execute()
pprint.pprint(file)
If you use the decorator as seen in the video bellow it stores your access token in the db for you and handles refreshing when needed.
https://www.youtube.com/watch?v=HoUdWBzUZ-M
https://developers.google.com/api-client-library/python/guide/google_app_engine
from oauth2client.appengine import OAuth2Decorator
decorator = OAuth2Decorator(client_id=CLIENT_ID,
client_secret=CLIENT_SECRET,
scope=OAUTH_SCOPE,
callback_path=REDIRECT_URI)
class MainPage(webapp2.RequestHandler):
#decorator.oauth_required #Simply place this above any function that requires login.
def get(self):

Facebook login in Google Cloud Endpoints

Can someone explain steps to implement login process with other OAuth2 providers
This link Google Cloud Endpoints with another oAuth2 provider gives little info about writing custom authentication, but I guess for beginner like me that's not enough, please give detailed steps.
Especially, interested in Facebook.
You need to implement Facebook's client side APIs according to their documentation and the environment you are deploying your client app to (Browser vs iOS vs Android). This includes registering your app with them. Your registered app will direct the user to go through an authentication flow and at the end of it your client app will have access to a short-lived access token. Facebook has multiple types of access tokens, but the one it sounds like you're interested in is called a User Access Token since it identifies an authorized user.
Pass the access token to your Cloud Endpoints API via a field or header. Inside of your API code receive the access token and implement Facebook's API that checks the validity of the access token. The first answer on this SO question makes it look rather easy, but you probably want to reference their documentation again. If that check passes then you would run your API code, otherwise throw an exception.
You will typically also want to implement a caching mechanism to prevent calling the Facebook server side validation API for each Cloud Endpoints request.
Finally, I mentioned that your client app has a short lived token. If you have a client app that is browser-based then you will probably want to upgrade that to a long lived token. Facebook has a flow for that as well which involves your API code requesting a long lived token with the short lived one. You would then need to transfer that long lived token back to the client app to use for future Cloud Endpoints API calls.
If your client app is iOS or Android based then your tokens are managed by Facebook code and you simply request access tokens from the respective APIs when you need them.
So I actually tried to implement that custom authentication flow. It seems working fine although there might be further consideration on security side.
First, user go to my application and authenticate with facebook, the application got his user_id and access_token. Then the application call auth API to the server with these info.
class AuthAPI(remote.Service):
#classmethod
def validate_facebook_user(cls, user_id, user_token):
try:
graph = facebook.GraphAPI(user_token)
profile = graph.get_object("me", fields='email, first_name, last_name, username')
except facebook.GraphAPIError, e:
return (None, None, str(e))
if (profile is not None):
# Check if match user_id
if (profile.get('id', '') == user_id):
# Check if user exists in our own datastore
(user, token) = User.get_by_facebook_id(user_id, 'auth', user_token)
# Create new user if not
if user is None:
#print 'Create new user'
username = profile.get('username', '')
password = security.generate_random_string(length=20)
unique_properties = ['email_address']
if (username != ''):
(is_created, user) = User.create_user(
username,
unique_properties,
email_address = profile.get('email', ''),
name = profile.get('first_name', ''),
last_name = profile.get('last_name', ''),
password_raw = password,
facebook_id = user_id,
facebook_token = user_token,
verified=False,
)
if is_created==False:
return (None, None, 'Cannot create user')
token_str = User.create_auth_token(user.get_id())
#print (user, token_str)
# Return if user exists
if token is not None:
return (user, token.token, 'Successfully logged in')
else:
return (None, None, 'Invalid token')
return (None, None, 'Invalid facebook id and token')
# Return a user_id and token if authenticated successfully
LOGIN_REQ = endpoints.ResourceContainer(MessageCommon,
type=messages.StringField(2, required=True),
user_id=messages.StringField(3, required=False),
token=messages.StringField(4, required=False))
#endpoints.method(LOGIN_REQ, MessageCommon,
path='login', http_method='POST', name='login')
def login(self, request):
type = request.type
result = MessageCommon()
# TODO: Change to enum type if we have multiple auth ways
if (type == "facebook"):
# Facebook user validation
user_id = request.user_id
access_token = request.token
(user_obj, auth_token, msg) = self.validate_facebook_user(user_id, access_token)
# If we can get user data
if (user_obj is not None and auth_token is not None):
print (user_obj, auth_token)
result.success = True
result.message = msg
result.data = json.dumps({
'user_id': user_obj.get_id(),
'user_token': auth_token
})
# If we cannot
else:
result.success = False
result.message = msg
return result
In addition to this, you might want to implement the normal user authentication flow following instruction here: http://blog.abahgat.com/2013/01/07/user-authentication-with-webapp2-on-google-app-engine/ .
This is because the user_id and user_token that I obtain was provided by webapp2_extras.appengine.auth.
Implementation of User.get_by_facebook_id:
class User(webapp2_extras.appengine.auth.models.User):
#classmethod
def get_by_facebook_id(cls, fb_id, subj='auth', fb_token=""):
u = cls.query(cls.facebook_id==fb_id).get()
if u is not None:
user_id = u.key.id()
# TODO: something better here, now just append the facebook_token to a prefix
token_str = "fbtk" + str(fb_token)
# get this token if it exists
token_key = cls.token_model.get(user_id, subj, token_str)
print token_key, fb_token
if token_key is None:
# return a token that created from access_token string
if (fb_token == ""):
return (None, None)
else:
token = cls.token_model.create(user_id, subj, token_str)
else:
token = token_key
return (u, token)
return (None, None)
Server verify if the user is authenticated with facebook once more time. If it passes, user is considered logged in. In this case, server pass back a user_token (generated based on facebook_token) and user_id from our datastore.
Any further API calls should use this user_id and user_token
def get_request_class(messageCls):
return endpoints.ResourceContainer(messageCls,
user_id=messages.IntegerField(2, required=False),
user_token=messages.StringField(3, required=False))
def authenticated_required(endpoint_method):
"""
Decorator that check if API calls are authenticated
"""
def check_login(self, request, *args, **kwargs):
try:
user_id = request.user_id
user_token = request.user_token
if (user_id is not None and user_token is not None):
# Validate user
(user, timestamp) = User.get_by_auth_token(user_id, user_token)
if user is not None:
return endpoint_method(self, request, user, *args, **kwargs )
raise endpoints.UnauthorizedException('Invalid user_id or access_token')
except:
raise endpoints.UnauthorizedException('Invalid access token')
#endpoints.api(name='blah', version='v1', allowed_client_ids = env.CLIENT_IDS, auth=AUTH_CONFIG)
class BlahApi(remote.Service):
# Add user_id/user_token to the request
Blah_Req = get_request_class(message_types.VoidMessage)
#endpoints.method(Blah_Req, BlahMessage, path='list', name='list')
#authenticated_required
def blah_list(self, request, user):
newMessage = BlahMessage(Blah.query().get())
return newMessage
Note:
I am using this library to handle facebook authentication checking on server: https://github.com/pythonforfacebook/facebook-sdk
I implemented this use case by adding a webapp2 handler to exchange the Facebook access token for one generated by my own application, using the SimpleAuth mixin for verification:
class AuthHandler(webapp2.RequestHandler, SimpleAuthHandler):
"""Authenticates a user to the application via a third-party provider.
The return value of this request is an OAuth token response.
Only a subset of the PROVIDERS specified in SimpleAuthHandler are currently supported.
Tested providers: Facebook
"""
def _on_signin(self, data, auth_info, provider):
# Create the auth ID format used by the User model
auth_id = '%s:%s' % (provider, data['id'])
user_model = auth.get_auth().store.user_model
user = user_model.get_by_auth_id(auth_id)
if not user:
ok, user = user_model.create_user(auth_id)
if not ok:
logging.error('Unable to create user for auth_id %s' % auth_id)
self.abort(500, 'Unable to create user')
return user
def post(self):
# Consider adding a check for a valid endpoints client ID here as well.
access_token = self.request.get('x_access_token')
provider = self.request.get('x_provider')
if provider not in self.PROVIDERS or access_token is None:
self.abort(401, 'Unknown provider or access token')
auth_info = {'access_token': access_token}
fetch_user_info = getattr(self, '_get_%s_user_info' % provider)
user_info = fetch_user_info(auth_info)
if 'id' in user_info:
user = self._on_signin(user_info, auth_info, provider)
token = user.create_bearer_token(user.get_id())
self.response.content_type = 'application/json'
self.response.body = json.dumps({
'access_token': token.token,
'token_type': 'Bearer',
'expires_in': token.bearer_token_timedelta.total_seconds(),
'refresh_token': token.refresh_token
})
else:
self.abort(401, 'Access token is invalid')
The exchanged access token can be passed on each endpoints request in the Authorization header, or as part of the RPC message if you prefer. Here's an example of reading it from the header:
def get_current_user():
token = os.getenv('HTTP_AUTHORIZATION')
if token:
try:
token = token.split(' ')[1]
except IndexError:
pass
user, _ = User.get_by_bearer_token(token)
return user
I posted the complete example on Github: https://github.com/loudnate/appengine-endpoints-auth-example
So no body has thrown a light on the android client side stuff. Since, you do not require Google login in this case hence the code for getting api handle will look like:
private Api getEndpointsApiHandle() {
Api.Builder api = new Api.Builder(HTTP_TRANSPORT, JSON_FACTORY, null);
api.setRootUrl(yourRootUrl);
return api.build();
}
If you notice; You will require to pass null as the Credential. This code works like a charm
I too have written my own solution for this problem. You can check out the code here: https://github.com/rggibson/Authtopus
Authtopus is a python library for custom authentication with Google Cloud Endpoints. It supports basic username and password registrations + logins, as well as logins via Facebook and Google (and could probably be extended to support other social providers without too much hassle). I know this doesn't directly answer the original question, but it seems related enough that I thought I'd share.

GAE put object, redirect, then query for object returns null?

All,
I am in the process of learning Google App Engine / Webapp2 and i'm having trouble saving an object to the datastore, redirecting to another page/handler, then fetching that object from the datastore. Forgive me if there is an easy answer to this question. The following is a description of the code I have.
I have a base handler:
class BaseHandler(webapp2.RequestHandler):
def set_secure_cookie(self, name, val):
cookie_val = make_secure_val(val)
self.response.headers.add_header(
'Set-Cookie',
'%s=%s; Path=/' % (name, cookie_val))
def get_secure_cookie(self, name):
cookie_val = self.request.cookies.get(name)
return cookie_val and check_secure_val(cookie_val)
def login(self, user):
self.set_secure_cookie('user', str(user.name))
# Called before every request and stores user object
def initialize(self, *a, **kw):
webapp2.RequestHandler.initialize(self, *a, **kw)
username = self.get_secure_cookie('user')
self.user = username and User.by_name(str(username))
I have a Signup page which inherits from BaseHandler:
class Signup(BaseHandler):
def get(self):
# Get the page
def post(self):
has_error = False
# Extract and validate the input
if has_error:
#Re-render the form
else:
new_user = User.register(self.username, self.password, self.email)
new_user.put()
self.login(new_user)
self.redirect("/blog/welcome")
If the user is a new user, the User db.Model object is created, the user is stored to the datastore, a user cookie is set and we are redirected to the Welcome handler:
class Welcome(BaseHandler):
def get(self):
if self.user:
self.render('welcome.html', username = self.user.name)
else:
self.redirect('/blog/signup')
The intent here is that upon redirect, BaseHandler.initialize() would get called and would set self.user of the new user I just created.
Here is what I know:
- When signing up a new user, I am redirected back to the signup page.
- If I then manually navigate to /blog/welcome, the page loads correctly with the new username populated.
If I add the following logging statements into Welcome.get():
username = self.get_secure_cookie('user')
logging.info("Cookie %r obtained inside of Welcome.get().", username)
logging.info("Found user %r", User.by_name(str(username)))
The cookie is obtained for the new username but no User object is found. Again, if I navigate directly to /blog/welcome, the logs report that the cookie is obtained and the User object is found for the new user.
The User object looks like so:
def users_key(group = 'default'):
return db.Key.from_path('users', group)
class User(db.Model):
name = db.StringProperty(required = True)
password = db.StringProperty(required = True)
email = db.StringProperty()
#classmethod
def by_name(cls, name):
u = User.all().filter('name =', name).get()
return u
#classmethod
def register(cls, name, password, email = None):
return User(parent = users_key(),
name = name,
password = password,
email = email)
Is there something about the datastore that is causing this first query to get the new user to return nothing? How should I proceed in debugging this? Is there additional reading I should do? (I have tried to provide all necessary code snippets but I can provide additional code if required.)
Just guessing, but I suspect self.username, self.password and self.email in your RequestHandler are not set to anything. I'm assuming you're getting those paramters from the request POST data, but that's not happening in the code shown.
The other potential problem is that your query is eventually consistent, and may not reflect recent changes (ie new User entity). It would be much better if you fetch the user by it's key or id with a get() call instead of a query via filter().

Resources