2
votes

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)?

2

2 Answers

2
votes
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

1
votes

As per documentation, a draft can be added to a thread as part of creating, updating, or sending a draft message.

In order to be part of a thread, a message or draft must meet the following criteria:

  1. The requested threadId must be specified on the Message or Draft.Message you supply with your request.
  2. The References and In-Reply-To headers must be set in compliance with the RFC 2822 standard.
  3. The Subject headers must match.

The documentation also states that in both examples for creating a draft and sending a message, you would simply add a threadId key paired with a thread ID to a message's metadata, the message object.