Microsoft Graph API send email using Access Token of Enterprise Application - python

I'm working on python code to send an email from Outlook using Microsoft Graph API. For this, I have created an Enterprise Application in my Azure Active Directory Tenant. I have granted admin consent for the tenant to the application on Mail.Send permission. I'm able to get the access token for Graph API with the help of this application, but I'm not able to send the mail. Can anyone please help me to understand, what is the issue with my code?
Python Code:
from requests import post
CLIENT_SECRET_VALUE = 'CLIENT_SECRET_VALUE'
TENANT_ID = 'TENANT_ID'
CLIENT_ID = 'CLIENT_ID'
LOGIN_URI = f'https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/token'
headers = {
'Host': 'login.microsoftonline.com',
'Content-Type': 'application/x-www-form-urlencoded'
}
body = {
'client_id': CLIENT_ID,
'scope': 'https://graph.microsoft.com/.default',
'client_secret': CLIENT_SECRET_VALUE,
'grant_type': 'client_credentials',
'tenant': TENANT_ID
}
response = post(url=LOGIN_URI, headers=headers, data=body)
response.raise_for_status()
response_body = response.json()
authorization_token = f"{response_body['token_type']} {response_body['access_token']}"
print(authorization_token)
email_header = {
'Authorization': authorization_token,
'Content-Type': 'application/json'
}
message = {
'body': {
'content': 'Outlook Mail Testing Demo',
'contentType': 'Text'
},
'sender': {
'emailAddress': {
'address': 'email.address.of.shared.mailbox#active-directory-tenant.tld',
'name': 'Name of Shared Mailbox'
}
},
'subject': 'Testing email',
'toRecipients': [
{
'emailAddress': {
'address': 'temprorary.email.address#another-domain.tld',
'name': 'Name of person to whom email belongs'
}
}
]
}
email_body = {
'message': message
}
email_send_response = post(url='https://graph.microsoft.com/v1.0/users/me/sendMail', headers=email_header, data=email_body)
email_send_response.raise_for_status()
[N.B.: CLIENT_SECRET_VALUE is getting generated by the enterprise application. TENANT_ID & CLIENT_ID are the tenant and client ids assigned to the application]
On running the code, I'm getting an error:
400 Client Error: Bad Request for url: https://graph.microsoft.com/v1.0/users/me/sendMail

There are two problems in your code. As I specified the first issue in comments that the URL should be as below as you are using client credential flow.
https://graph.microsoft.com/v1.0/users/{userid/UPN}/sendMail
The second problem I have identified after a long research in python is that the body which you are sening with the API call is not in the format of json. So I have used import json and method json.dumps and tested it. Then it worked.
Code:
from requests import post
import json
CLIENT_SECRET_VALUE = 'aX27Q~insds3EvI4z8otRNGHRcCgdjeFOTSpCLPZ'
TENANT_ID = '363147dc-b3be-41a7-af56-f67894ef5a7'
CLIENT_ID = 'e61195e5-7955-4558-9126-37f6cf372d45'
LOGIN_URI = f'https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/token'
headers = {
'Host': 'login.microsoftonline.com',
'Content-Type': 'application/x-www-form-urlencoded'
}
body = {
'client_id': CLIENT_ID,
'scope': 'https://graph.microsoft.com/.default',
'client_secret': CLIENT_SECRET_VALUE,
'grant_type': 'client_credentials',
'tenant': TENANT_ID
}
response = post(url=LOGIN_URI, headers=headers, data=body)
response.raise_for_status()
response_body = response.json()
authorization_token = f"{response_body['token_type']} {response_body['access_token']}"
print(authorization_token)
email_header = {
'Authorization': authorization_token,
'Content-Type': 'application/json'
}
message = {
'body': {
'content': 'Outlook Mail Testing Demo',
'contentType': 'Text'
},
'sender': {
'emailAddress': {
'address': 'email.address.of.shared.mailbox#active-directory-tenant.tld',
'name': 'Name of Shared Mailbox'
}
},
'subject': 'Testing email',
'toRecipients': [
{
'emailAddress': {
'address': 'temprorary.email.address#another-domain.tld',
'name': 'Name of person to whom email belongs'
}
}
]
}
email_body = {
'message': message
}
email_send_response = post(url='https://graph.microsoft.com/v1.0/users/1ab4e76f-5f52-44b8-8a72-7d03c05e6ff4/sendMail', headers=email_header, data=json.dumps(email_body))
print(email_send_response)
OUTPUT:

Related

How to create reports with Python SDK Api

I am trying to create reports with Python on dailymotion but I have error,According to my received error, renponse is empty. I don't get it. I guess, My user coudln't login to dailymotion. Please check error.
{'data': {'askPartnerReportFile': None}, 'errors': [{'message': 'Not authorized to access `askPartnerReportFile` field.', 'path': ['askPartnerReportFile'], 'locations': [{'line': 3, 'column': 9}], **'type': 'not_authorized**'}]}
Traceback (most recent call last):
File "get_reports.py", line 143, in <module>
product='CONTENT',
File "get_reports.py", line 65, in create_report_request
return response.json()['data']['askPartnerReportFile']['reportFile']['reportToken'];
TypeError: 'NoneType' object is not subscriptable
Here is my code;
`
def get_access_token(app_key, app_secret, username, password):
'''
Authenticate on the API in order to get an access token
'''
response = requests.post('https://graphql.api.dailymotion.com/oauth/token', data={
'client_id': app_key,
'client_secret': app_secret,
'username': username,
'password': password,
'grant_type': 'password',
'version': '2'
})
if response.status_code != 200 or not 'access_token' in response.json():
raise Exception('Invalid authentication response')
return response.json()['access_token']
def create_report_request(access_token, dimensions, metrics, start_date, end_date, product, filters = None):
'''
Creating a report request
'''
reportRequest = """
mutation ($input: AskPartnerReportFileInput!) {
askPartnerReportFile(input: $input) {
reportFile {
reportToken
}
}
}
"""
response = requests.post(
'https://graphql.api.dailymotion.com',
json={
'query': reportRequest,
'variables': {
'input': {
'metrics': metrics,
'dimensions': dimensions,
'filters': filters,
'startDate': start_date,
'endDate': end_date,
'product': product,
}
}
},
headers={'Authorization': 'Bearer ' + access_token}
)
print(response.status_code)
if response.status_code != 200 or not 'data' in response.json():
raise Exception('Invalid response')
print(response.json())
return response.json()['data']['askPartnerReportFile']['reportFile']['reportToken'];
def check_report_status(access_token, report_token):
'''
Checking the status of the reporting request
'''
report_request_status_check = """
query PartnerGetReportFile ($reportToken: String!) {
partner {
reportFile(reportToken: $reportToken) {
status
downloadLinks {
edges {
node {
link
}
}
}
}
}
}
"""
response = requests.post(
'https://graphql.api.dailymotion.com',
json={
'query': report_request_status_check,
'variables': {
'reportToken': report_token
}
},
headers={'Authorization': 'Bearer ' + access_token}
)
if response.status_code != 200 or not 'data' in response.json():
raise Exception('Invalid response')
status = response.json()['data']['partner']['reportFile']['status'];
if (status == 'FINISHED'):
download_links = []
for url in map(lambda edge: edge['node']['link'], response.json()['data']['partner']['reportFile']['downloadLinks']['edges']):
download_links.append(url)
return download_links
else:
return None
def download_report(download_links, base_path=None):
'''
Downloading the report files
'''
cpt = 1
if not base_path:
base_path = os.getcwd()
for url in download_links:
r = requests.get(url)
filename = 'report_{}.csv'.format(cpt)
file_path = os.path.join(base_path, filename)
open(file_path, 'wb').write(r.content)
print('Report file {} downloaded: {}'.format(cpt, file_path))
cpt += 1
print('Generating access token...')
access_token = get_access_token(
app_key='******',
app_secret='*******',
username='*****',
password='*****'
)
print('Creating report request...')
report_token = create_report_request(
access_token=access_token,
dimensions=('DAY', 'VIDEO_TITLE'),
metrics=('VIEWS'),
filters={'videoOwnerChannelSlug': 'B******'},
start_date='2022-11-23',
end_date='2022-11-24',
product='CONTENT',
)
download_links = None
while not download_links:
print('Checking report status...')
# Checks every 15secs the report status
time.sleep(15)
download_links = check_report_status(
access_token=access_token,
report_token=report_token
)
download_report(download_links=download_links)
`
I tried to get data dailymotion api.
Thanks
This feature requires a specific API access, which is missing on your API Key, that's why you get the message Not authorized to access askPartnerReportFile field.
As it's a feature restricted to verified-partners, you should reach out to your content manager to ask him this kind of access, or you can try to contact our support

Facing Issue Sending Gmail Using Google Gmail API

It shows credentials are missing when I try to use the Google Gmail API to send messages. I want to send an email to my other Gmail account using the Google Gmail API.
import sys
import requests
import base64
import sys
from email.mime.text import MIMEText
AccessToken = ""
params = {
"grant_type": "refresh_token",
"client_id": "xxxxxxxxxxxxxxx",
"client_secret": "xxxxxxxxxxxxxxx",
"refresh_token": "xxxxxxxxxxxxxxxxxxxx",
}
authorization_url = "https://www.googleapis.com/oauth2/v4/token"
r = requests.post(authorization_url, data=params)
if r.ok:
AccessToken = str((r.json()['access_token']))
EmailFrom = "Test1#gmail.com"
EmailTo = "test2#gmail.com"
def create_message(sender, to, subject, message_text):
message = MIMEText(message_text, 'html')
message['to'] = to
message['from'] = sender
message['subject'] = subject
raw = base64.urlsafe_b64encode(message.as_bytes())
raw = raw.decode()
body = {'raw': raw}
return body
body = create_message(EmailFrom, EmailTo, "Just wanna Say Waka Waka!", "Waka Waka!")
url = "https://gmail.googleapis.com/gmail/v1/users/me/messages/send"
header = {
'Authorization': 'Bearer ' + AccessToken,
'Content-Type': 'application/json',
'Accept': 'application/json'
}
r = requests.post(
url,
header,
body
)
print("\n")
print(r.text)
print("\n")
Error:
{
"error": {
"code": 401,
"message": "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"errors": [
{
"message": "Login Required.",
"domain": "global",
"reason": "required",
"location": "Authorization",
"locationType": "header"
}
],
"status": "UNAUTHENTICATED",
"details": [
{
"#type": "type.googleapis.com/google.rpc.ErrorInfo",
"reason": "CREDENTIALS_MISSING",
"domain": "googleapis.com",
"metadata": {
"method": "caribou.api.proto.MailboxService.SendMessage",
"service": "gmail.googleapis.com"
}
}
]
}
}
I'm not a google api user, but I've used oauth several times, and your setup is a bit different than what I usually use or what I see from a quick sniff of Google's documention. For example, I use client-creds instead of a refresh token. For what I'm seeing above in your code, no reason to refresh an old token, when you can just mint another one. Compared to yours, usually with oauth, we'll do something like auth=(client_id, client_secret)
Lastly, before you change anything big, when you changed your header to place the AccessToken variable in quotes, did you use an f-string? What is the output of
print(header)
after you have defined it? Is it what you expect? If you didn't format it, it's going to have the variable's name rather than value.
If that's all ok, I'd try to write it according to OAuth standards that I've used several times. Not telling you how to do it, but you could try something like:
def getKey():
url = "https://www.googleapis.com/oauth2/v4/token"
client_id = "*yourgoogleclientid*"
client_secret = "*yourgoogleclientsecret*"
data = {
'grant_type': 'client_credentials'
}
r = requests.post(url, json=data, auth=(client_id, client_secret))
key = r.json()['access_token']
return key
def getWhatever(key, url):
header = {
'Authorization': f'Bearer {key} '
}
params = {
'whatever params': 'you might need'
}
response = requests.get(url, headers=header, params=params)
* parse, process, return, whatever you'd like to do with the response.*
now to use it....
if __name__ == '__main__':
myKey = getKey()
whatImLookingFor = getWhatever(myKey, "*https://google_api_endpoint*")

Unable to verify webhooks from PayPal in Python

I am trying to verify webhooks for subscriptions in paypal using django python. I am receiving the webhooks but when i send them to get verified i get this error: {'name': 'VALIDATION_ERROR', 'message': 'Invalid request - see details', 'debug_id': 'ccc873865982', 'details': [{'field': '/', 'location': 'body', 'issue': 'MALFORMED_REQUEST_JSON'}], 'links': []}. I have checked what the status code is for the response which gives a 400 response. By looking at the API Docs i see that invalid request + 400 response is either a validation error (which is to do with the Json format, so most likely a syntax error) or an authorization error (which says i need to change the scope). I think it is the validation error because the error points to the body.
Here is the relevant code:
header_params = {
"Accept": "application/json",
"Accept-Language": "en_US",
}
param = {
"grant_type": "client_credentials",
}
cid = settings.PAYPAL_CLIENT_ID
secret = settings.PAYPAL_CLIENT_SECRET
token_i = requests.post('https://api-m.sandbox.paypal.com/v1/oauth2/token', auth=(cid, secret), headers=header_params, data=param).json()
token = token_i["access_token"]
bearer_token = "Bearer x".replace('x', token)
headers = {
"Content-Type": "application/json",
"Authorization": bearer_token,
}
print(request.body)
webhook_event = request.body.decode("utf-8")
data = {
"transmission_id": request.headers["PAYPAL-TRANSMISSION-ID"],
"transmission_time": request.headers["PAYPAL-TRANSMISSION-TIME"],
"cert_url": request.headers["PAYPAL-CERT-URL"],
"auth_algo": request.headers["PAYPAL-AUTH-ALGO"],
"transmission_sig": request.headers["PAYPAL-TRANSMISSION-SIG"],
"webhook_id": "3AJ143072C221060T",
"webhook_event": webhook_event,
}
print(json.dumps(data))
response = requests.post('https://api-m.sandbox.paypal.com/v1/notifications/verify-webhook-signature', headers=headers, json=json.dumps(data)).json()
print('worked')
print(response)
if response["verification_status"] == "SUCCESS":
print('success')
Here is the print of the print(json.dumps(data)) (i removed some ids):
{
"transmission_id": "id_is_here",
"transmission_time": "2021-07-04T23:37:29Z",
"cert_url": "https://api.sandbox.paypal.com/v1/notifications/certs/CERT-360caa42-fca2a594-7a8abba8",
"auth_algo": "auth_algo",
"transmission_sig": "EODOx5y8kIDycYiBYcIgByiBzHyEfu1/NS2nsumOIksVuw/2vJwHj2FcuHYxIa4n/s+s25xkeqk0CXPiSuqtNUGv4pvFtpwbCVAOCU+Msn304+wBgyb7G24rwUPwrof/5jHYQxqKKX5RzxTrff4oPnisKBDUUXV4s2+KO3h2RYAhrXtwTSPt7cK5ZbGZ6SmfpYJ8qDnYFh4PIesLeflSPQ4vHQrFbgr3NiW63sZruGFJc0hTWWc8L3BhzDuUfiSrxBJLAtrqReC8R0HSV8D+Ywmdeipep54yZeJZXfbmUUGvSYbmVMsVggyzZnltyl1hP5xUd3iIi2jdNWYpLESZzA==",
"webhook_id": "Webhook_id_is_here",
"webhook_event": "{\"id\":\"id_here\",\"event_version\":\"1.0\",\"create_time\":\"2021-07-04T23:37:26.733Z\",\"resource_type\":\"subscription\",\"resource_version\":\"2.0\",\"event_type\":\"BILLING.SUBSCRIPTION.CREATED\",\"summary\":\"Subscription created\",\"resource\":{\"start_time\":\"2021-07-04T23:37:26Z\",\"quantity\":\"1\",\"create_time\":\"2021-07-04T23:37:26Z\",\"custom_id\":\"custom_id_here\",\"links\":[{\"href\":\"https://www.sandbox.paypal.com/webapps/billing/subscriptions?ba_token=BA-2UF06918UT180770Y\",\"rel\":\"approve\",\"method\":\"GET\"},{\"href\":\"https://api.sandbox.paypal.com/v1/billing/subscriptions/I-4S15814RUE18\",\"rel\":\"edit\",\"method\":\"PATCH\"},{\"href\":\"https://api.sandbox.paypal.com/v1/billing/subscriptions/I-4S15814RUE18\",\"rel\":\"self\",\"method\":\"GET\"}],\"id\":\"sub_id_here_\",\"plan_overridden\":false,\"plan_id\":\"P-0DA33732CG980003EMDQJ6BA\",\"status\":\"APPROVAL_PENDING\"},\"links\":[{\"href\":\"https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-91E32247D9338170B-4RF07261WK370823W\",\"rel\":\"self\",\"method\":\"GET\"},{\"href\":\"https://api.sandbox.paypal.com/v1/notifications/webhooks-events/id_here/resend\",\"rel\":\"resend\",\"method\":\"POST\"}]}"
}
Your data for the key webhook_event is double encoded as JSON.
You have to decode it with
webhook_event = json.loads(webhook_event)
or not encode it in the first place.

Apple Sign In Python

I want to make an apple sign in with social auth python. Now I have a piece of code below. When I do a request, I get an invalid grant error. I think that 'id_token' is not valid. But I don't know how to get that id_token, because I get the id_token after the request. Can anybody help me. Big Thanks!
headers = {
'alg': 'ES256',
'kid': settings.SOCIAL_AUTH_APPLE_ID_KEY
}
payload = {
'iss': settings.SOCIAL_AUTH_APPLE_ID_TEAM,
'iat': now,
'exp': now + TOKEN_TTL_SEC,
'aud': 'https://appleid.apple.com',
'sub': settings.SOCIAL_AUTH_APPLE_ID_CLIENT,
}
client_secret = jwt.encode(
payload,
settings.SOCIAL_AUTH_APPLE_ID_SECRET,
algorithm='ES256',
headers=headers
).decode("utf-8")
headers = {'content-type': "application/x-www-form-urlencoded"}
data = {
'client_id': 'com.scread.app',
'client_secret': client_secret,
'code': 'id_token',
'grant_type': 'authorization_code'
}
res = requests.post('https://appleid.apple.com/auth/token', data=data, headers=headers)
It seems that the service id must end like .app. Thus for example com.company.app. That was the solution for me.

How to send POST request in python 3?

This is how my code looks like. I need to find out how can make call since I am new to Python.
HEADER = {
'Content-Type': 'application/x'
}
BODY = {
'scope': 'b2b',
'grant_type': 'client_credentials',
'client_id': var_clientid,
'client_secret': var_clientsecret
}
This is how I was able to connect!
import requests
url = 'someurlexample'
BODY = {
'scope': 'b2b',
'grant_type': 'client_credentials',
'client_id': var_clientid,
'client_secret': var_clientsecret
}
S = requests.session()
post = S.post(url, data=BODY, json=False)

Categories