I get this error when running my code:
google.auth.exceptions.RefreshError: ('unauthorized_client: Client is unauthorized to retrieve access tokens using this method, or client not authorized for any of the scopes requested.', {'error': 'unauthorized_client', 'error_description': 'Client is unauthorized to retrieve access tokens using this method, or client not authorized for any of the scopes requested.'})
Here is the code:
from __future__ import print_function
from googleapiclient import discovery, errors
from oauth2client import file, client, tools
from google.oauth2 import service_account
from email.mime.text import MIMEText
import base64
SERVICE_ACCOUNT_FILE = 'keys.json'
SCOPES = [' https://www.googleapis.com/auth/gmail.send']
# The user we want to "impersonate"
USER_EMAIL = "myName#myDomain.com"
def validationService():
# Set the crendentials
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(USER_EMAIL)
service = discovery.build('gmail', 'v1', credentials=delegated_credentials)
return service
def send_message(service):
gmail_from = 'myName#myDomain.com'
gmail_to = 'anotherName#gmail.com'
gmail_subject = 'Hello World'
gmail_content = 'test test'
message = MIMEText(gmail_content)
message['to'] = gmail_to
message['from'] = gmail_from
message['subject'] = gmail_subject
raw = base64.urlsafe_b64encode(message.as_bytes())
raw = raw.decode()
body = {'raw': raw}
try:
message = (service.users().messages().send(userId='me', body=body)
.execute())
print('your message has been sent')
return message
except errors.HttpError as error:
print('An error occurred: %s' % error)
send_message(validationService())
I don't understand where in the code my email address "gmail_from" is connected to my email address. Apart from that i've given access to my IDE in gmail:
I've also created in the google console OAuth 2.0 Client IDs credentials and Service Accounts credentials but i don't really understand how/where to use these.
What am I missing?
On the google website: https://developers.google.com/identity/protocols/oauth2/service-account#error-codes I have found that I needed to "In the Domain-wide delegation page in the Admin console, remove the client, and re-add it with the numeric ID." but i don't understand how to do that nor how that would help.
There is an extra space in the scope:
SCOPES = [' https://www.googleapis.com/auth/gmail.send']
^ here
I'm trying to send a simple test email using the Gmail API but I keep getting the same error for every code sample I find.
My code at the moment is this:
def validationService():
SCOPES = ['https://mail.google.com/']
SERVICE_ACCOUNT_FILE = 'creds.json'
creds = service_account.Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes=SCOPES)
service = build('gmail', 'v1', credentials=creds)
return service
def SendMessage(service, user_id, message):
try:
message = (service.users().messages().send(userId=user_id, body=message).execute())
print('Message Id:',message['id'])
return message
except errors.HttpError as error:
print('An error occurred:', error)
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()}
service = validationService()
email = CreateMessage("sendermail#gmail.com", "receiverrmail#gmail.com", "Test", "This is a test")
sent = SendMessage(service, "sendermail#gmail.com", email)
Returns
>>> An error occurred: <HttpError 400 when requesting https://www.googleapis.com/gmail/v1/users/me/messages/send?alt=json returned "Bad Request">
I also don't understand the difference between the "sender" parameter at CreateMessage and userId at SendMessage.
If serves a purpose, I'm using a Service Account credential
-
Thanks!
When using a service account with the Gmail API. You need to set domain-wide delegation, which allows the service account to impersonate any user in your G Suite domain. Therefore, you must have a G Suite Account to be able to use domain wide-delegation as the docs say:
If you have a G Suite domain—if you use G Suite, for example—an
administrator of the G Suite domain can authorize an application to
access user data on behalf of users in the G Suite domain.
So now, why do you need to impersonate a user(a real person)? it's due to the fact a service account is a bot(not a real person) that is used to server-to-server interactions making possible your app calls Google APIs and although the service account has a parameter called client_email, which has a structure like name#project-randomnumber.iam.gserviceaccount.com it's not a real email that belongs to a real person (kind of confusing I know).
Having said that, I made some changes to your code. First, I modified your validationService function in order to build the service using domain-wide delegation.
def validationService():
# Set the crendentials
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(USER_EMAIL)
service = discovery.build('gmail', 'v1', credentials=delegated_credentials)
return service
In your SendMessage function is not necessarily to pass the user who is going to send the email. Using me is enough as the Users.messages: send Parameters state:
userId string The user's email address. The special value me can be
used to indicate the authenticated user.
def SendMessage(service, message):
message = service.users().messages().send(userId="me", body=message).execute()
return message
Your whole code at the end could look like this one:
from googleapiclient import discovery, errors
from oauth2client import file, client, tools
from google.oauth2 import service_account
from email.mime.text import MIMEText
import base64
SERVICE_ACCOUNT_FILE = 'service_account.json'
SCOPES = [' https://mail.google.com/']
# The user we want to "impersonate"
USER_EMAIL = "user#domain"
def validationService():
# Set the crendentials
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(USER_EMAIL)
service = discovery.build('gmail', 'v1', credentials=delegated_credentials)
return service
def SendMessage(service, message):
message = service.users().messages().send(userId="me", body=message).execute()
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()}
def main():
try:
service = validationService()
email = CreateMessage(USER_EMAIL, "receiverrmail#domain", "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()
Notice
You also need to allow your service account to access Google's API when using domain-wide delegation by setting the Managing API client access on your G Suite account.
You don't break your head... Just use email and smtplib libraries. Very simple and fun sending email through Python, if you ask me. I have given my coding below and you should develop your own code based on this. If it works, just let me know - I will be happy. here it is....
import email, smtplib, os, time, fnmatch
from datetime import date, timedelta
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
def sendMailTo(recepient_id, today):
login_id = 'myemailID#gmail.com'
login_pwd = "mypassword"
fro_ = login_id
s_name = 'smtp.gmail.com'
s_port = 587
fileList = []
fi_type = '*.pdf'
file_path = "C:\\Myfolder\\Subfolder"
srvr = smtplib.SMTP(s_name, s_port)
srvr.ehlo()
srvr.starttls()
srvr.ehlo()
srvr.login(login_id, login_pwd)
sub = "Your subject here"
# loading MIMEMultipart obj onto outer var
outer = MIMEMultipart('alternative')
outer["From"] = 'Your company/Personal Name'
outer["To"] = recepient_id
outer['Subject'] = sub
# storing only pdf files
fileList = fnmatch.filter(os.listdir(file_path), fi_type)
for fi in fileList:
fi_name = os.path.join(file_path, fi)
fp = open(fi_name, 'rb')
img = MIMEImage(fp.read(), _subtype='jpg')
fp.close()
img.add_header('Content-disposition', "attachment", filename = fi)
outer.attach(img)
#start sending email with attachment with original file name
srvr.sendmail(fro_, recepient_id, outer.as_string())
part = None
outer = None
srvr.quit()
Suppose I have this code which places all the message history between a twilio number and its recipients in an array. Is there a way to retrieve only the message history from all the recipients and not the sender (whom is I)
from twilio.rest import Client
account_sid = 'xxxx'
auth_token = 'xxxx'
client = Client(account_sid, auth_token)
text=[]
messages = client.messages.list()
for record in messages:
print(record.body)
text.append(record.body)
print(text)
There are some examples of filter criteria with the above command, you can filter on to: to your specific Twilio number to just see that side of the conversation (via body key).
# Download the helper library from https://www.twilio.com/docs/python/install
from datetime import datetime
from twilio.rest import Client
# Your Account Sid and Auth Token from twilio.com/console
# DANGER! This is insecure. See http://twil.io/secure
account_sid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
auth_token = 'your_auth_token'
client = Client(account_sid, auth_token)
messages = client.messages.list(
to='+15558675310',
limit=20
)
for record in messages:
print(record.sid)
I'm attempting to call the Spotify API and have set up an app/got my client ID and Secret. Here's an example of my code (with specifics blocked out):
import spotipy
import spotipy.util as util
from spotipy.oauth2 import SpotifyClientCredentials
cid ="xx"
secret = "xx"
username = "xx"
client_credentials_manager = SpotifyClientCredentials(client_id=cid, client_secret=secret)
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
scope = 'user-library-read playlist-read-private'
token = util.prompt_for_user_token(username,scope,client_id='http://localhost:8888/callback/',client_secret='http://localhost:8888/callback/',redirect_uri='http://localhost:8888/callback/')
if token:
sp = spotipy.Spotify(auth=token)
else:
print("Can't get token for", username)
cache_token = token.get_access_token()
sp = spotipy.Spotify(cache_token)
currentfaves = sp.current_user_top_tracks(limit=20, offset=0, time_range='medium_term')
print(currentfaves)
I've made sure my URL is exactly the same as what's registered in my Spotify app development page, and I've added the client ID, redirect URIs and client Secret keys to my environment variables.
So far a separate tab opens up (https://accounts.spotify.com/authorize?client_id=http%3A%2F%2Flocalhost%3A8888%2Fcallback%2F&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A8888%2Fcallback%2F&scope=playlist-read-private+user-library-read) but I'm only getting 'INVALID_CLIENT: Invalid client' on that page. What can I do/change to make this work?
token = util.prompt_for_user_token(username,scope,client_id='http://localhost:8888/callback/',client_secret='http://localhost:8888/callback/',redirect_uri='http://localhost:8888/callback/')
Is there a typo in here, since you copied the redirect uri also as the client id and secret?
Hi everyone Im in a tangle as how to recorded, transcribe and retrieve the text from the transcription in Twilio. How do I do it? Example:
# Download the Python helper library from twilio.com/docs/python/install
from twilio.rest import TwilioRestClient
# Your Account Sid and Auth Token from twilio.com/user/account
account_sid = "AC30bd8bdca7572344721eb96c15a5c0c7"
auth_token = "your_auth_token"
client = TwilioRestClient(account_sid, auth_token)
transcription = client.transcriptions.get("TR8c61027b709ffb038236612dc5af8723")
print(transcription.transcription_text)
in client.transcriptions.get, How do I get the latest transcription? I need the Uri (I believe) but have no idea how to access it/variable name.
On a side note, what alternatives to the Twilio transcription are there and how do I access the appropriate recordings in my script to transcribe?
Twilio developer evangelist here.
You can access all your transcriptions by listing them as follows:
# Your Account Sid and Auth Token from twilio.com/user/account
account_sid = "AC30bd8bdca7572344721eb96c15a5c0c7"
auth_token = "your_auth_token"
client = TwilioRestClient(account_sid, auth_token)
for transcription in client.transcriptions.list():
print transcription.transcriptiontext
You can also set the TranscriptionUrl attribute so you get notified with a transcription ID when a transcription is complete. That way you can use the code snipped you posted above.