Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a draft message in existing thread with gmail API

Using the python google client I able to create new messages within an existing thread with id threadId as follows:

message = (service.users().messages().send(userId='me', body={'threadId': <threadId>}, media_body=message['media_body'])
           .execute())

(here I'm using media_body as it supports the /upload endpoint for large attachments)

This works fine for messages, and the threadId optional parameter is documented at https://developers.google.com/gmail/api/v1/reference/users/messages/send

However I have been unsuccessful doing the same when creating new draft messages, and don't see any docs about it at https://developers.google.com/gmail/api/v1/reference/users/drafts/create

I tried adding threadId to the draft body when doing draft = service.users().drafts().create(userId=user_id, body={'threadId': <threadId>}, media_body=message_body['media_body']).execute() at the create draft stage and it simply is ignored.

I also tried adding threadId to the body at the send draft stage: message = service.users().drafts().send( userId='me', body={'id': draft_id, threadId': <threadId>}).execute() and this was also ignored.

Either way the draft message just gets created in its own, new thread.

How can I create a new draft message within an existing thread with the gmail API (and specifically with Python client)?

like image 971
fpghost Avatar asked Sep 05 '25 02:09

fpghost


1 Answers

email = self.service.users().messages().get(userId='me', id='1756f9403f66ac1d').execute() # sub in your message id

def get_field(self, email, field_name):
    header = email['payload']['headers']
    for m in header:
        if m['name'] == field_name:
            return m['value']

def add_draft(self, email, body):
    message = MIMEText(body)
    message['to'] = '[email protected]'
    message['from'] = '[email protected]'
    message['subject'] = self.get_field(email, 'Subject')
    message['In-Reply-To'] = self.get_field(email, 'Message-ID')
    message['References'] = self.get_field(email, 'Message-ID')# + ',' + self.get_field_a(email, 'References')
    email_body = {'message' : {'threadId' : email['threadId'], 'raw' : base64.urlsafe_b64encode(message.as_string().encode('utf-8')).decode()}}
    draft = self.service.users().drafts().create(userId='me', body=email_body).execute()

In this above example I was adding a draft as a response to a brand new thread that had one message sent to me. That particular email didn't have a value 'References' in the header so I commented out the section where I was extracting that field from the received email and adding it to the draft. For adding a draft to longer threads I believe you'll need to read and append this field. A function to safely append the field is left as an exercise to the reader :)

A great resource for seeing examples of what you should be sending is the GMail 'show original'. Open an email -> three buttons -> Show Original. This opens a page where you can see the values of the actual fields in the emails gmail is sending for you when you (the human you) sends emails. For example, here is the reference and in reply to section of the second message in a different thread:

References: <[email protected]>,<[email protected]>
In-Reply-To: <[email protected]>

In this case, 'In-Reply-To' was set as the 'Message-Id' field of the prior message, and 'References' was set as prior 'Message-Id' plus the prior 'References' fields

Here's a screenshot of the final result: enter image description here

like image 134
TheGaldozer Avatar answered Sep 07 '25 14:09

TheGaldozer