0

Here I want to send a reply using Gmail API. For that, I got a successful response while retrieving. Now I have threadId using that threadId I need to send a reply instead of creating a new thread

This is my response for retrieval of mail

{
  id: '178fe5f9cc632096',
  threadId: '178fe5f9cc632096',
  labelIds: [ 'IMPORTANT', 'CATEGORY_PERSONAL', 'INBOX' ],
  snippet: 'it's working --',
  payload: {
    partId: '',
    mimeType: 'multipart/alternative',
    filename: '',
    headers: [
      [Object], [Object], [Object],
      [Object], [Object], [Object],
      [Object], [Object], [Object],
      [Object], [Object], [Object],
      [Object], [Object], [Object],
      [Object], [Object], [Object],
      [Object], [Object], [Object],
      [Object]
    ],
    body: { size: 0 },
    parts: [ [Object], [Object] ]
  },
  sizeEstimate: 5218,
  historyId: '119777',
  internalDate: '1619175369000'
} 

And my code for sending reply

function makeBody(to, from, subject, message) {
    var str = ["Content-Type: text/plain; charset=\"UTF-8\"\n",
        "MIME-Version: 1.0\n",
        "Content-Transfer-Encoding: 7bit\n",
        "to: ", to, "\n",
        "from: ", from, "\n",
        "subject: ", subject, "\n\n",
        message
    ].join('');

    var encodedMail = Buffer.from(str).toString("base64").replace(/\+/g, '-').replace(/\//g, '_');
    return encodedMail
}
function sendMessage(auth) {
                    try {
                        var raw = makeBody('abc@gmail.com', 'xyz@gmail.com', 'test subject', 'workinggggggg...');
                        const gmail = google.gmail({ version: 'v1', auth });
                        gmail.users.messages.send({
                            auth: auth,
                            userId: 'me',
                            resource: {
                                raw: raw,
                                message_id: res.data.threadId
                            }
                        }, function (err, response) {
                            if (err) {
                                return console.log('The API returned an error: ' + err);
                            }
                            else
                                console.log(response)
                        });
                    } catch (error) {
                        console.log(error)
                    }
                }

But while using this code a new thread is creating. Need help.

2 Answers2

1

As per documentation:

If you're trying to send a reply and want the email to thread, make sure that:

The Subject headers match The References and In-Reply-To headers follow the RFC 2822 standard.

Thus, proving 'test subject' as the subject will not work if this is not the real subject of the email to which you want to reply.

Also:

As you can draw the the Resource: Message, you should pass the thread id to the parameter threadId. message_id is not a valid parameter.

ziganotschka
  • 25,866
  • 2
  • 16
  • 33
  • But in my headers, I don't have references and In-Reply-to headers – Saichandhra Arvapally Apr 26 '21 at 09:53
  • 1
    If you don't have any, then you do no need to worry about this part. But the other two points (matching subject and correct assignation of `threadId`) are crucial. – ziganotschka Apr 26 '21 at 10:28
  • Yeah I have changed the threadId assignment and the subject was changed to Re:`${subject}`..But still a new mail is sending instead of replying to existing thread – Saichandhra Arvapally Apr 26 '21 at 10:44
  • 1
    See if [this](https://stackoverflow.com/questions/32589476/how-to-send-a-reply-with-gmail-api) helps you. Do you have the thread view activated in your Gmail UI? – ziganotschka Apr 26 '21 at 11:02
  • Hi, now I'm able to send a reply but the receiver is getting new mail instead of a reply to previous and from the sender side I'm getting another mail to that same thread instead of reply – Saichandhra Arvapally Apr 27 '21 at 08:04
  • 1
    Is the receiver a Gmail user? Does he have conversion view enabled? – ziganotschka Apr 27 '21 at 08:59
  • yes he is a Gmail user and enabled he's conversation – Saichandhra Arvapally Apr 27 '21 at 09:57
  • The References and In-Reply-To headers will form only when a reply is sent right? So here I'm sending the reply but that thread doesn't have the References and In-Reply-To headers. – Saichandhra Arvapally Apr 27 '21 at 11:15
  • 1
    The `In-Reply-To` should go into the email header and contain the message id to which you want to reply - see [here](https://stackoverflow.com/questions/44880439/trying-to-reply-to-an-existing-email-with-gmail-api). – ziganotschka Apr 27 '21 at 13:19
  • Yeah, I have used the Message-Id value as In-Reply-to's value, replies are sending fine. How can I dynamically update the token file? Now I'm doing it manually. – Saichandhra Arvapally Apr 28 '21 at 07:04
  • I am glad it works now. As for the token - that is already a differerent quesiton, but in short: You need to create a flow with an OAuth2 client , prompting for authorization and generation of a refresh and access token - just like in the sample of the [quickstart](https://developers.google.com/gmail/api/quickstart/nodejs#step_2_set_up_the_sample). – ziganotschka Apr 28 '21 at 07:21
  • No, not that one, we need another file as token.json in which we have an access token and refresh token and that file has expiry. so how can I refresh it – Saichandhra Arvapally Apr 28 '21 at 07:23
  • 1
    The refresh token automatically creates a new access token whenever the latter expires. But for this you need to incorporate the workflow as mentioned in the quickstart. Unless you have a different implementation - see [google-auth-library-nodejs](https://github.com/googleapis/google-auth-library-nodejs). I suggest you to write a separate post where you explain your situation and use case more in detail. This will make it for users easier to help you. – ziganotschka Apr 28 '21 at 07:30
0

The solution is to keep Message-Id as In-Reply-To and References You need to update the In-Reply-To and References values like below

function makeBody(ref, InReply, to, from, subject, message) {
    var str = ["Content-Type: text/plain; charset=\"UTF-8\"\n",
        "MIME-Version: 1.0\n",
        "Content-Transfer-Encoding: 7bit\n",
        "References:", ref, "\n" +
        "In-Reply-To: ", InReply, "\n" +
        "to: ", to, "\n",
        "from: ", from, "\n",
        "subject: ", subject, "\n\n",
        message
    ].join('');

    var encodedMail = Buffer.from(str).toString("base64").replace(/\+/g, '-').replace(/\//g, '_');
    return encodedMail
}

const headers = res.data.payload.headers
                        let subject
                        let to
                        let ref
                        let InReply
                        headers.forEach(element => {
                            if (element.name === 'Subject' || element.name === 'subject') {
                                subject = element.value
                            }
                            if (element.name === 'From' || element.name === 'from') {
                                to = element.value
                            }
                            if (element.name === 'Message-ID' || element.name === 'Message-Id') {
                                ref = element.value
                                InReply = element.value
                            }
                        });
  var raw = makeBody(ref, InReply, to, 'example1@gmail.com', subject, 'reply message text');