Dan Klos
Dan Klos

Reputation: 709

How to get the reply message without the original message from the Gmail API

I would like to get the reply message in a thread without the original message. However, when I use either Users.messages: GET or Users.threads: GET, I receive the reply (as desired) with the original message (undesired) as well. See screenshot below code.

(This question, as far as I can tell, was also posed here, however I did not find that the proposed solution answers the question and the poster of the proposed solution suggested I start a new question. I tried with Users.threads as Tholle suggests however received the same result.)

I'm a noob, so any and all help is greatly appreciated and I apologize if I'm missing something obvious.

Code

var gapiGETRequest = function (gapiRequestURL)
  {
      var xmlHttp = new XMLHttpRequest();
      xmlHttp.open( "GET", gapiRequestURL, false );
      xmlHttp.send( null );
      return xmlHttp.responseText;
  }

var gapiRequestInboxMessagesAndToken = "https://www.googleapis.com/gmail/v1/users/me/messages?q=-label%3ASENT+in%3AINBOX&access_token=" + thisToken
var allMessagesReceived = gapiGETRequest(gapiRequestInboxMessagesAndToken)
var allMessagesObject = JSON.parse(allMessagesReceived)
var messageIdsOfReceivedMessages = [];
var getIdsOfReceivedMessages = function(responseObject){
  for(var i=0; i < responseObject.messages.length; i ++) {
    messageIdsOfReceivedMessages.push(responseObject.messages[i].id);
  }
}

var messageContentsArr = [];
var getMessageContents = function(messageIdList)
{
  for(var i=0; i < messageIdList.length; i++)
  {
    var gapiRequestMessageWithId = "https://www.googleapis.com/gmail/v1/users/me/messages/" + messageIdList[i] + "?access_token=" + thisToken
    var currentMessage = JSON.parse(gapiGETRequest(gapiRequestMessageWithId))
    var encodedMessageContents = currentMessage.payload.parts[0].body.data
    var decodedMessageContents = atob(encodedMessageContents.replace(/-/g, '+').replace(/_/g, '/'));
    messageContentsArr.push(decodedMessageContents)
  }
}

getIdsOfReceivedMessages(allMessagesObject);
getMessageContents(messageIdsOfReceivedMessages);

Response

result

Upvotes: 8

Views: 6180

Answers (5)

Nikita Yuzhakov
Nikita Yuzhakov

Reputation: 69

This is my solution. It's a bit long but I tried to document it as detailed as possible.

Handles message returned by Gmail API: https://developers.google.com/gmail/api/v1/reference/users/messages#resource

Input:

Hello. This is my reply to message.

On Thu, Apr 30, 2020 at 8:29 PM John Doe <[email protected]>
wrote:

> Hey. This is my message.
>


-- 
John Doe
My Awesome Signature

Output:

Hello. This is my reply to message.

Code: (Unfortunately this has no syntax highlight :P)

const message = await getMessageFromGmailApi();

const text = getGoogleMessageText(message);

console.log(text, '<= AWESOME RESULT');


function getGoogleMessageText(message) {
    let text = '';

    const fromEmail = getGoogleMessageEmailFromHeader('From', message);
    const toEmail = getGoogleMessageEmailFromHeader('To', message);

    let part;
    if (message.payload.parts) {
        part = message.payload.parts.find((part) => part.mimeType === 'text/plain');
    }

    let encodedText;
    if (message.payload.parts && part && part.body.data) {
        encodedText = part.body.data;
    } else if (message.payload.body.data) {
        encodedText = message.payload.body.data;
    }

    if (encodedText) {
        const buff = new Buffer(encodedText, 'base64');
        text = buff.toString('ascii');
    }

    // NOTE: We need to remove history of email.
    // History starts with line (example): 'On Thu, Apr 30, 2020 at 8:29 PM John Doe <[email protected]> wrote:'
    //
    // We also don't know who wrote the last message in history, so we use the email that
    // we meet first: 'fromEmail' and 'toEmail'
    const fromEmailWithArrows = `<${fromEmail}>`;
    const toEmailWithArrows = `<${toEmail}>`;
    // NOTE: Check if email has history
    const isEmailWithHistory = (!!fromEmail && text.indexOf(fromEmailWithArrows) > -1) || (!!toEmail && text.indexOf(toEmailWithArrows) > -1);

    if (isEmailWithHistory) {
       // NOTE: First history email with arrows
       const historyEmailWithArrows = this.findFirstSubstring(fromEmailWithArrows, toEmailWithArrows, text);

       // NOTE: Remove everything after `<${fromEmail}>`
       text = text.substring(0, text.indexOf(historyEmailWithArrows) + historyEmailWithArrows.length);
       // NOTE: Remove line that contains `<${fromEmail}>`
       const fromRegExp = new RegExp(`^.*${historyEmailWithArrows}.*$`, 'mg');
       text = text.replace(fromRegExp, '');
    }

    text = text.trim()

    return text;
}


function getGoogleMessageEmailFromHeader(headerName, message) {
    const header = message.payload.headers.find((header) => header.name === headerName);

    if (!header) {
        return null;
    }

    const headerValue = header.value; // John Doe <[email protected]>

    const email = headerValue.substring(
        headerValue.lastIndexOf('<') + 1,
        headerValue.lastIndexOf('>')
    );

    return email; // [email protected]
}


function findFirstSubstring(a, b, str) {
    if (str.indexOf(a) === -1) return b;
    if (str.indexOf(b) === -1) return a;

    return (str.indexOf(a) < str.indexOf(b))
        ? a
        : b; // NOTE: (str.indexOf(b) < str.indexOf(a))
}

Upvotes: 5

Obed Parlapiano
Obed Parlapiano

Reputation: 3702

I tried all other answers with no success.

The following will remove any quoted text, including quoted text that is within the sent message. However, this worked for me as I only wanted the original text.

function removeHistory(emailText: string) {
  const textLines = emailText.split(/\r?\n/gm);

  let textLinesWithNoQuotes = [];

  for (let line of textLines) {
    if (!line.startsWith(">") && line) {
      textLinesWithNoQuotes.push(line);
    }
  }

  if (
    textLinesWithNoQuotes.length > 0 &&
    textLinesWithNoQuotes[textLinesWithNoQuotes.length - 1].endsWith("> wrote:")
  ) {
    textLinesWithNoQuotes.pop();
  }

  return textLinesWithNoQuotes.join("\r\n");
}

It splits the text by line and removes all quoted text. Once that's done we can assume the last line is the beginning of history, check if it's there and remove it too. It will only work with English emails because of the "wrote:" text, but can easily de adjusted to other languages.

Upvotes: 0

shahzaib manzoor
shahzaib manzoor

Reputation: 57

Let me save your day

console.log(message.split("On")[0])

output : Hello. This is my reply to message.

Upvotes: -2

Jegan Ramasamy
Jegan Ramasamy

Reputation: 1

Substring the reply content alone, based on your Email id position in the full email string.

$str = "VGhhbmtzIGZvciB0aGUgbWFpbC4NCg0KT24gVHVlLCBKdWwgMTIsIDIwMjIgYXQgMjo1OCBQTSA8aW5mb0BhaXJjb25uZWN0aW5kaWEuY29tPiB3cm90ZToNCg0KPiBTLk5vIFZlbmRvciBQcm9kdWN0IEJhbmR3aWR0aCBGcm9tIExvY2F0aW9uIFRvIExvY2F0aW9uDQo-IDEgQWlydGVsIEludGVybmV0IDEwMCAyMS4xNzAyNDAxLDcyLjgzMTA2MDcwMDAwMDAxDQo-IDE5LjA0NjE5NTY4NjA2MjMxMiw3Mi44MjAyNzY0Mzc4MjA0Mw0KPg0K";

$str_raw = strtr($str, array('+' => '-', '/' => '_'));

$full_email = utf8_decode(base64_decode($str_raw));

$split_position = strpos($full_email, "your_mail_id") - 33; //33 - before that some date time available, remove those also
$final_string = substr($full_email, 0, $split_position);

echo $final_string;

Upvotes: 0

Jay Lee
Jay Lee

Reputation: 13528

You are getting the full reply message. When the report replied, they quoted the original message and this the text of the original is in the reply message. You may just want to do what Gmail and many other modern emails apps do and collapse/hide any reply text which begins with >.

Upvotes: 4

Related Questions