I would like to give my thanks to the other answers which were helpful. My use case required me to use the user's access token obtained from Gmail and respond back to a given message thread.
In this, I had to modify the above answer given by Tanaike to the following.
import base64
import mimetypes
import os
import traceback
from email.mime.audio import MIMEAudio
from email.mime.base import MIMEBase
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import httplib2
from apiclient import discovery
from oauth2client.client import AccessTokenCredentials
def send_message(access_token: str, sender: str, to: str, subject: str, html_message: str, thread_id: str,
user_id: str = 'me', attachment_file=None):
try:
# Referenced from: https://oauth2client.readthedocs.io/en/latest/source/oauth2client.client.html
credentials = AccessTokenCredentials(access_token, 'PostmanRuntime/7.29.2')
http = credentials.authorize(httplib2.Http())
service = discovery.build('gmail', 'v1', http=http)
if attachment_file:
message_body = __create_message_with_attachment__(sender, to, subject, html_message, thread_id, attachment_file)
else:
message_body = __create_message_body__(sender, to, subject, html_message, thread_id)
response = (service.users().messages().send(userId=user_id, body=message_body).execute())
print(response)
return response['id']
except Exception as e:
traceback.print_exc()
def __create_message_body__(from_email: str, to_email: str, subject: str, message_body: str, thread_id: str):
msg = MIMEMultipart('alternative')
msg['Subject'] = subject
msg['From'] = from_email
msg['To'] = to_email
msg.attach(MIMEText(message_body, 'plain'))
msg.attach(MIMEText(message_body, 'html'))
return {
'raw': base64.urlsafe_b64encode(msg.as_string().encode()).decode(),
'threadId': thread_id
}
def __create_message_with_attachment__(sender: str, to: str, subject: str, message_body, thread_id: str,
attachment_file: str):
"""Create a message for an email.
Args:
sender: Email address of the sender.
to: Email address of the receiver.
subject: The subject of the email message.
message_body: Html message to be sent
thread_id: thread id to respond to
attachment_file: The path to the file to be attached.
Returns:
An object containing a base64url encoded email object.
"""
message = MIMEMultipart('mixed')
message['to'] = to
message['from'] = sender
message['subject'] = subject
message_alternative = MIMEMultipart('alternative')
message_related = MIMEMultipart('related')
message_related.attach(MIMEText(message_body, 'html'))
message_alternative.attach(MIMEText(message_body, 'plain'))
message_alternative.attach(message_related)
message.attach(message_alternative)
print("create_message_with_attachment: file: %s" % attachment_file)
content_type, encoding = mimetypes.guess_type(attachment_file)
if content_type is None or encoding is not None:
content_type = 'application/octet-stream'
main_type, sub_type = content_type.split('/', 1)
if main_type == 'text':
fp = open(attachment_file, 'rb')
msg = MIMEText(fp.read(), _subtype=sub_type)
fp.close()
elif main_type == 'image':
fp = open(attachment_file, 'rb')
msg = MIMEImage(fp.read(), _subtype=sub_type)
fp.close()
elif main_type == 'audio':
fp = open(attachment_file, 'rb')
msg = MIMEAudio(fp.read(), _subtype=sub_type)
fp.close()
else:
fp = open(attachment_file, 'rb')
msg = MIMEBase(main_type, sub_type)
msg.set_payload(fp.read())
fp.close()
filename = os.path.basename(attachment_file)
msg.add_header('Content-Disposition', 'attachment', filename=filename)
message.attach(msg)
return {
'raw': base64.urlsafe_b64encode(message.as_string().encode()).decode(),
'threadId': thread_id
}
def main():
to = "example@gmail.com"
sender = "example@gmail.com"
subject = "subject"
message = "Hi<br/>same message here"
access_token = "ya29.a0AVA9y1uc1Ec-................"
thread_id = '181b9292e6a.....'
send_message(access_token=access_token,
sender=sender,
to=to,
subject=subject,
html_message=message,
thread_id=thread_id)
if __name__ == '__main__':
main()
Please keep note of how I construct the required credential using the user's access token;
credentials = AccessTokenCredentials(access_token, 'user agent here')
This is obtained from https://oauth2client.readthedocs.io/en/latest/source/oauth2client.client.html