I want to implement functionality to append a draft as a reply to an existing thread of emails using the gmail API in Python, but my drafts intended to be replies to a thread are created as standalone drafts. The docs for the create()
method are here and the docs for the RFC 2822 standard are here. I believe I have already correctly set the Subject
header to match the Subject
header of the message being replied to, the In-Reply-To
header to match the Message-ID
header of the message being replied to, and the References
header to match the References
header of the message being replied to followed by the Message-ID
(separated with a space).
My code for getting the headers from the message being replied to is in get_message_headers()
and my code for setting the reply's headers and creating the draft is in reply_draft()
.
In the main
script, I call get_message_headers()
and then draft the reply with reply_draft()
, inputting the values returned by get_message_headers()
as well as the body of the new draft, the target's email address, and the thread ID of the message being replied to.
Does anyone know what I am missing to get the draft to be created as a reply to a thread instead of a new draft?
def get_message_headers(self, message_id):
"""Get a message and return its References, In-Reply-To, and Subject headers"""
payload = (
self.service.users()
.messages()
.get(userId="me", id=message_id)
.execute()["payload"]
)
references_value = None
in_reply_to_value = None
subject = None
for header in payload["headers"]:
if header["name"] == "References":
refs = header["value"]
elif header["name"] == "Message-ID":
in_reply_to_value = header["value"]
elif header["name"] == "Subject":
subject = header["value"]
references_value = refs + " " + in_reply_to_value
return references_value, in_reply_to_value, subject
def reply_draft(
self, content, other, subject, thread_id, references_value, in_reply_to_value
):
"""Create and insert a draft email.
Print the returned draft's message and id.
Returns: Draft object, including draft id and message meta data.
"""
try:
message = EmailMessage()
message.set_content(content)
message["To"] = other
message["From"] = self.me
message["Subject"] = subject
message["References"] = references_value
message["In-Reply-To"] = in_reply_to_value
# encoded message
encoded_message = base64.urlsafe_b64encode(message.as_bytes()).decode()
body = {"message": {"raw": encoded_message}}
body["threadId"] = str(thread_id)
draft = (
self.service.users().drafts().create(userId="me", body=body).execute()
)
except HttpError as error:
print(f"An error occurred: {error}")
draft = None
return draft
If I understand your question correctly you have a message and you want to create a draft of a reply to that message.
You just need to add the threadId with the id of the message you want to reply to.
try:
# Call the Gmail API
service = build('gmail', 'v1', credentials=creds)
message = EmailMessage()
message.set_content('This is automated draft mail')
message['To'] = '[redacted]'
message['From'] = [redacted]
message['Subject'] = 'Automated draft'
# encoded message
encoded_message = base64.urlsafe_b64encode(message.as_bytes()).decode()
create_message = {
'message': {
'threadId': message_id, # The id of the main message to reply to
'raw': encoded_message
}
}
# pylint: disable=E1101
draft = service.users().drafts().create(userId="me",
body=create_message).execute()
print(F'Draft id: {draft["id"]}\nDraft message: {draft["message"]}')
except HttpError as error:
# TODO(developer) - Handle errors from gmail API.
print(f'An error occurred: {error}')