Create Gmail Draft with a HTTP Request - python

I am trying to make a Gmail Draft with a HTTP request.
The sample below creates the draft, but its blank.
When I copy and paste the Base64 output into the APIs Explorer it works fine.
#app.route('/createEmail', methods=["POST"])
def createEmail():
message = MIMEText('Hello World')
message['to'] = 'to#email.com'
message['from'] = 'from#email.com'
message['subject'] = 'Subject'
access_token = credentials.access_token
flow = AccessTokenCredentials(access_token, 'application_name')
http = flow.authorize(httplib2.Http())
obj = http.request(
uri='https://www.googleapis.com/upload/gmail/v1/users/me/drafts',
method='POST',
body={
'message':{
'raw':base64.urlsafe_b64encode( message.as_string() )
}
},
headers={'content-type':'message/rfc822'}
)
return obj[1]

If you are not planning on sending any attachments, you can use the metadata url https://www.googleapis.com/gmail/v1/users/me/drafts instead, which will allow you to send just the raw-parameter.
When your entire mail is sent as a raw-parameter in the body, you need to put the raw-parameter in a message-object, and the Content-Type is not message/rfc822, but application/json.
obj = http.request(
uri='https://www.googleapis.com/gmail/v1/users/me/drafts',
method='POST',
body={
'message': {
'raw':base64.urlsafe_b64encode( message.as_string() )
}
},
headers={'content-type':'application/json'}
)

Related

get url from python

good day!
I need to send a request via the api to the https server. the documentation describes that this must be done via curl.
example request:
everything works out through curl. the request is sent, the response comes ok.
but if I try to send the same request with a python script, I get a 401 error.
here is my code.
import requests
def main():
token = 'my_token'
# url = 'https://api-ip.fssp.gov.ru/api/v1.0/'
url = 'https://api-ip.fssp.gov.ru/api/v1.0/search/physical'
region = '48'
lastname = 'Иванов'
firstname = 'Валерий'
secondname = 'Викторович'
birthdate = '02.07.1970'
data = {
'token': token,
'region': region,
'lastname': lastname,
'firstname': firstname,
'birthdate': birthdate,
'secondname': secondname
}
response = requests.get(url=url, data=data)
print(response.status_code)
if __name__ == '__main__':
main()
here is the content of the response from the server
b'{"status":"error","code":401,"exception":"token not exist","response":[]}'
What am I doing wrong?
Try using the params argument instead of data to URL encode the values:
response = requests.get(url=url, params=data)

{'error': 'RESTEASY003650: No resource method found for PUT, return 405 with Allow header'} when updating user data in Keycloak

I am trying to update user info in keycloak by sending put request. Get request is working fine I am getting all the users but Whenever I tried to send put request to update the user data I get this error "{'error': 'RESTEASY003650: No resource method found for PUT, return 405 with Allow header'}" while searching for the solution I find somewhere that I should add 'HTTP_X_HTTP_METHOD_OVERRIDE' in headers I also tried this but still, I am facing same error, how can I fix it.
code:
def update_user(user_id, user_data):
import requests
headers = dict()
headers['HTTP_X_HTTP_METHOD_OVERRIDE'] = 'PUT'
headers['content_type'] = 'application/json'
data = {
"grant_type": "password",
"username": "admin",
"password": os.getenv("KEYCLOAK_ADMIN_KEY"),
"client_id": "admin-cli"
}
token = _request("POST", f"{server_internal_url}realms/master/protocol/openid-connect/token", None, data=data).json()["access_token"]
# token = admin_token()
headers["Authorization"] = f"Bearer {token}"
headers["Host"] = kc_host
# here = _request("PUT", admin_url+f"/users"+"/".format(user_id=user_id), token, data=json.dumps(user_data)).json()
response = requests.put(admin_url+f"/users"+"/".format(user_id=user_id), headers=headers, data=data, verify=VERIFY)
print(response.json())
server_internal_url = "https://keycloak:8443/auth/"
admin_url = "https://keycloak:8443/auth/admin/realms/{realm_name}"
It looks like you request has wrong URL:
response = requests.put(admin_url+f"/users"+"/".format(user_id=user_id), headers=headers, data=data, verify=VERIFY)
I guess it should be:
response = requests.put(admin_url+"/users/"+user_id, headers=headers, data=data, verify=VERIFY)

"BadRequest" error while using SendMail request of Microsoft Graph API

I am writing a python script to send a mail using the Microsoft Graph API. The mail is sent to only those IDs which exists in our AAD.
I wrote the code:
from adal import AuthenticationContext
import adal
import string
import urllib
import json
import requests
import pprint
import base64
import mimetypes
API_VERSION = 'beta'
RESOURCE = 'https://graph.microsoft.com'
TENANT = <my tenant ID>
CLIENTID = <Client ID>
CLIENTSECRET = <sescret>
DOMAIN = <mydomain>
# AUTHENTICATION - get access token and update session header
def get_session():
authority_host_url = 'https://login.windows.net'
tenant = TENANT
authority_url = authority_host_url + '/' + tenant
service_endpoint = "https://graph.microsoft.com/"
client_id = CLIENTID
client_secret = CLIENTSECRET
# Retrieves authentication tokens from Azure Active Directory and creates a new AuthenticationContext object.
context = AuthenticationContext(authority_url, validate_authority=True, cache=None, api_version=None, timeout=300, enable_pii=False)
# Gets a token for a given resource via client credentials.
token_response = context.acquire_token_with_client_credentials(service_endpoint, client_id, client_secret)
# Create a persistent session with the access token
session = requests.Session()
session.headers.update({'Authorization': f'Bearer {token_response["accessToken"]}', 'SdkVersion': 'python-adal', 'x-client-SKU': 'DynaAdmin'})
#session.headers.update({'Authorization': f'Bearer {token_response["accessToken"]}'})
return session
def build_uri(url):
if 'https' == urllib.parse.urlparse(url).scheme:
return url
result = urllib.parse.urljoin(f'{RESOURCE}/{API_VERSION}/', url.lstrip('/'))
print("\nURL:\n")
print(result)
return result
def sendmail(*, session, subject=None, recipients=None, body='',
content_type='HTML', attachments=None):
"""Helper to send email from current user.
session = user-authenticated session for graph API
subject = email subject (required)
recipients = list of recipient email addresses (required)
body = body of the message
content_type = content type (default is 'HTML')
attachments = list of file attachments (local filenames)
Returns the response from the POST to the sendmail API.
"""
# Verify that required arguments have been passed.
if not all([session, subject, recipients]):
raise ValueError('sendmail(): required arguments missing')
# Create recipient list in required format.
recipient_list = [{'EmailAddress': {'Address': address}}
for address in recipients]
# Create list of attachments in required format.
attached_files = []
if attachments:
for filename in attachments:
b64_content = base64.b64encode(open(filename, 'rb').read())
mime_type = mimetypes.guess_type(filename)[0]
mime_type = mime_type if mime_type else ''
attached_files.append( \
{'#odata.type': '#microsoft.graph.fileAttachment',
'ContentBytes': b64_content.decode('utf-8'),
'ContentType': mime_type,
'Name': filename})
# Create email message in required format.
email_msg = {'Message': {'Subject': subject,
'Body': {'ContentType': content_type, 'Content': body},
'ToRecipients': recipient_list,
'Attachments': attached_files},
'SaveToSentItems': 'true'}
print("\nBody:\n")
print(email_msg)
# Do a POST to Graph's sendMail API and return the response.
resp = session.post(build_uri('/users/8368b7b5-b337ac267220/sendMail'), data=email_msg, stream=True, headers={'Content-Type': 'application/json'})
return resp
# ------------ RUN CODE ------------
session = get_session()
myRecipients = "sea.chen#mydomain.com;anj.dy#mydomain.com"
response = sendmail(session=session,
subject= "hai",
recipients=myRecipients.split(';'),
body="hai this is a new mail")
print("\nRequest headers: \n")
print(response.request.headers)
print("\nResponse: \n")
print(response)
print(response.text)
The output I got is :
Body:
{'Message': {'Subject': 'hai', 'Body': {'ContentType': 'HTML', 'Content': 'hai this is a new mail'}, 'ToRecipients': [{'EmailAddress': {'Address': 'sea.chen#mydomain.com'}}, {'EmailAddress': {'Address': 'anj.dy#mydomain.com'}}], 'Attachments': []}, 'SaveToSentItems': 'true'}
URL:
https://graph.microsoft.com/beta/users/8368b7b5-b337ac267220/sendMail
Request headers:
{'User-Agent': 'python-requests/2.22.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Authorization': 'Bearer eyJ0eXAiOiJKV1QiLCJub25jZSI6IkFRQUJBQUFBQUFEQ29NcGpKWHJ4VHE5Vkc5dGUtN0ZYVzRQOWpybFRZWXdIVmZieWJxd0dUVUtNRThqUG5Va0hFSlowU2JyUFRaaDlaSjdURklVMjRwV1RpOTQxZU5kaXpIeHdXdDk0ODNlYmY1OWE5IiwiYXBwaWRhY3IiOiIxIiwiaWRwIjoiaHR0cHM6Ly9zdHMud2luZG93cy5uZXQvOWFmYjFmOGEtMjE5Mi00NWJhLWIwYTEtNmIxOTNjNzU4ZTI0LyIsIm9pZCI6ImI3NDY4ZDQxLTkxMWMtNGU4ZS1iMzA4LWY5NmM1ZGQ4MDVmMyIsInJvbGVzIjpbIlVzZXIuUmVhZFdyaXRlLkFsbCIsIkdyb3VwLlJlYWQuQWxsIiwiRGlyZWN0b3J5LlJlYWRXcml0ZS5BbGwiLCJHcm91cC5SZWFkV3JpdGUuQWxsIiwiRGlyZWN0b3J5LlJlYWQuQWxsIiwiVXNlci5SZWFkLkFsbCIsIk1haWwuU2VuZCJdLCJzdWIiOiJiNzQ2OGQ0MS05MTFjLTRlOGUtYjMwOC1mOTZjNWRkODA1ZjMiLCJ0aWQiOiI5YWZiMWY4YS0yMTkyLTQ1YmEtYjBhMS02YjE5M2M3NThlMjQiLCJ1dGkiOiJWX1d6UHJjUDhrQ000MGNPM0xZZkFBIiwidmVyIjoiMS4wIiwieG1zX3RjZHQiOjE0NTY0Nzc5MzB9.Nq0qdmfd4qAQWdnaFLVNKYWQ__t52jRYC09IsDlrSOoAhZU6d2M6ePAAaKFSR-Ss_NJ4o21FAbxRM8mRUumW3n1TFvARN0FDzjtZMG9mgIrPmYndfRQtcD3s7f5Q5JOQdtd5QDRVhPqVRNAwmC-o_TW5mm0p40oIR2Mc2MN_MB3dp-_0xH7fN3xsPzWi9yRR1-iHnvEjLmhKecY5pxCBO3RW5QVcAR6DH6kw0koV49cmjpIu-_gau4SFlF4kFdwEVXdv1jTeJj91lA02Ar9tR-2hQiPOaqsloSmKpaH0Tb4LwGQJBk2O8fiwy5Sv2NoKbi6QE2EPFck7jZPVBDh35g', 'SdkVersion': 'python-adal', 'x-client-SKU': 'DynaAdmin', 'Content-Type': 'application/json', 'Content-Length': '90'}
Response:
<Response [400]>
{
"error": {
"code": "BadRequest",
"message": "Unable to read JSON request payload. Please ensure Content-Type header is set and payload is of valid JSON format.",
"innerError": {
"request-id": "26ef0c0b-c362-401c-b8ed-48755a45d086",
"date": "2019-06-24T07:10:53"
}
}
}
The error I got is :
Unable to read JSON request payload. Please ensure Content-Type header
is set and payload is of valid JSON format.
So I tried the request in Graph Explorer and used the same URL and body I got printed in the above output. The request sent from Graph Explorer was successful and the mail was sent to the correct recipients. That means the content-body is valid.
It is obvious from the above output that the bearer token, and 'Content-Type': 'application/json' were passed as the header.
Then why I am getting the error while running the script?
Can anyone please help me?
Most likely the body of your POST is not properly formatted. When I did this with the requests library, I found I needed to set data like so:
data = json.dumps(email_msg)
The default for data is to form-encode, not pass as JSON. Have a look at https://learn.microsoft.com/outlook/rest/python-tutorial#contents-of-tutorialoutlookservicepy
Thanks for sharing this.
I had different issue when I was trying to get Graph API to send one-on-one chat message to Microsoft Teams. I could run the following code using http.client and get most of the messages posted in chat.
import http.client
headers = {'Content-type':'application/json',
"Authorization": f"Bearer {getGraphAccessToken()}"
}
body = {
"body": {
"contentType": "text",
"charset" : "utf-8",
"content": text
}}
connection = http.client.HTTPSConnection("graph.microsoft.com")
connection.request("POST",f"/v1.0/chats/{chatId}/messages",headers=headers, body = str(body))
However when I had certain emojis inside the text I got the following error:
"Unable to read JSON request payload. Please ensure Content-Type header is set and payload is of valid JSON format."
By switching the library to requests I was able to send the message with special emojis to work.
import requests
import json
headers = {'Content-type':'application/json',
"Authorization": f"Bearer {getGraphAccessToken()}"
}
body = {
"body": {
"contentType": "text",
"content": text
}}
requests.post(f"https://graph.microsoft.com/v1.0/chats/{chatId}/messages",headers=headers,data =json.dumps(body) )

MailChimp bad request JSONParseError with Python

I am trying to hook up to MailChimp's api, in my Django application, to add an email to one of my lists. Seems pretty simple enough. I add my api key to the header of the request, with the email address and other variable in the body of the request. every time I try and connect though, I get a response status code of 400. The message says there is a JSON parsing error, and that my JSON is either formatted incorrectly, or there is missing data required for the request. I am making this same api call however with Postman, and am getting a good response back.
view function
import requests
def join_newsletter(request, email):
# hash the user's email for mailchimp's API
# m = hashlib.md5()
# c_email = email
# m.update(c_email.encode('utf-8'))
# email_hash = m.hexdigest()
api_key = 'apikey ' + settings.MAILCHIMP_API
api_endpoint = api_endpoint
data = {
"email_address": email,
"status": "subscribed"
}
header = {
'Authorization': api_key
}
r = requests.post(api_endpoint, data=data, headers=header)
message = r.content
return message

How to generate an AccessToken programmatically in Django?

I'm setting up an API. Everything is working. I'm creating a token via OAuth2 python lib. I'm using TastyPie for my API.
The problem I'm facing.. is that there is no "create" token method in the AccessToken or Client models.
I can create an accessToken via the Django admin, and I can create one by doing a curl to:
myhost.com/oauth2/access_token (with all the info, secret key, client id, user & pass)
my goal is to upon successful registration of a user with my API, the oAuth client is automatically created (working) but I also want to generate the AccessToken. I cannot cURL my own server as its giving me a redirect/connection refused error so I want to do it programmatically in Python. Anyway to do this? Here's a snippet:
try:
user = User.objects.create_user(username, password)
user.save()
if user:
oauth_client = Client(user=user, name="api account", client_type=1, url="http://example.com")
oauth_client.save()
oauth_client_id = oauth_client.pk
oauth_client_secret = oauth_client.client_secret
if oauth_client:
print user
print oauth_client_id
print AccessToken.objects.all()
print '........'
token = AccessToken(user=user, client=oauth_client_id, scope=6)
token.save()
the last two lines above, while giving NO errors.. will NOT save a new AccessToken.
I'm using https://github.com/caffeinehit/django-oauth2-provider. I managed to create access token and refresh token by using models. I might be bypassing grant flow.
I haven't used this code in production but in development server i can perform API calls using the access token generated this way. I think it should be well tested before going to production.
#settings.py
OAUTH2_PROVIDER = {
# this is the list of available scopes
'SCOPES': {'read': 'Read scope'},
'ACCESS_TOKEN_EXPIRE_SECONDS': 36000,
}
#views.py
expire_seconds = oauth2_settings.user_settings['ACCESS_TOKEN_EXPIRE_SECONDS']
scopes = oauth2_settings.user_settings['SCOPES']
application = Application.objects.get(name="ApplicationName")
expires = datetime.now() + timedelta(seconds=expire_seconds)
access_token = AccessToken.objects.create(
user=user,
application=application,
token=random_token_generator(request),
expires=expires,
scope=scopes)
refresh_token = RefreshToken.objects.create(
user=user,
token=random_token_generator(request),
access_token=access_token,
application=application)
token = {
'access_token': access_token.token,
'token_type': 'Bearer',
'expires_in': expire_seconds,
'refresh_token': refresh_token.token,
'scope': scopes}
return Response(token, status=200)
This is how I was able to make it work:
from oauth2_provider.views import TokenView
import json
class SuperUserLogin(views.APIView):
permission_classes = (permissions.AllowAny, )
def post(self, request, **kwargs):
url, headers, body, status_code = TokenView().create_token_response(request)
return Response(json.loads(body), status=status_code)
This is how my request object looks like.
{
"username" : email,
"password" : password,
"client_id" : client_id,
"client_secret" : client_secret,
"grant_type" : password
}
This generates the desired access_token. I've verified the token creation on my database.
Based on what I see here https://github.com/caffeinehit/django-oauth2-provider/blob/master/provider/oauth2/views.py#L93 token creation is done this way
access_token = AccessToken.objects.create(
user=user,
client=client,
scope=scope
)
RefreshToken.objects.create(
user=user,
access_token=access_token,
client=client
)
I assume second token isn't so interesting for you so it's almost your code but with managers create() method. The only difference it makes is that manager calls save() with force_insert=True.
So try
token.save(force_insert = True)
I was able to get this to work in Django 1.6 using the following:
token = AccessToken.objects.create(user=user,
client=Client.objects.get(name=clientName),
scope=3)
Try below,
In [1]: import base64
In [2]: from django.conf import settings
In [3]: from django.http import HttpRequest
In [4]: from oauth2_provider.views import TokenView
In [5]: request = HttpRequest()
In [6]: key = base64.b64encode('{}:{}'.format(<CLIENT_ID>, <SECRET_KEY>))
In [7]: request.META = {'HTTP_AUTHORIZATION': 'Basic {}'.format(key)}
In [8]: request.POST = {'grant_type': 'password', 'username': '<USERNAME>', 'password': '<PASSWORD>'}
In [9]: tv = TokenView()
In [10]: url, headers, body, status = tv.create_token_response(request)
In [11]: body
Out [11]: '{"access_token": "IsttAWdao3JF6o3Fk9ktf2gRrUhuOZ", "token_type": "Bearer", "expires_in": 36000, "refresh_token": "y2KQyyliOuRIXf3q9PWzEUeBnx43nm", "scope": "read write"}'
Try this one, I just tested it moments earlier
>>> from oauth2_provider.models import Application
>>> app = Application.objects.create(name="Sample ORM", client_type="public", authorization_grant_type="password", user_id=1)
<Application: Sample ORM>
>>> import requests
>>> from requests.auth import HTTPBasicAuth
>>>
>>>
>>> data = "grant_type=password&username=admin&password=d3#narmada13"
>>> headers = {"content-type": "application/x-www-form-urlencoded"}
>>> r = requests.post(token_url, data=data, auth=(app.client_id, app.client_secret), headers=headers)
>>> print r.content
{"access_token": "5kEaw4O7SX6jO9nT0NdzLBpnq0CweE", "token_type": "Bearer", "expires_in": 7776000, "refresh_token": "ZQjxcuTSTmTaLSyfGNGqNvF3M6KzwZ", "scope": "read write"}
>>> import json
>>> json.loads(r.content)['access_token']
u'5kEaw4O7SX6jO9nT0NdzLBpnq0CweE'
>>>

Categories