'Web Gmail shows message as starred even after Apps Script unstars it

OK, I think web Gmail is being screwy. I run a Google apps script that in part adds my "To-do" label to any thread I manually star, then archives and unstars it. A snippet is below. I'd appreciate any help.

After running the script the thread gets the label and is unstarred, except the star icon next to the thread/message in web Gmail still shows as selected. If I go to Starred messages label/folder nothing is displayed. If I immediately rerun the script it doesn't find any Starred threads. This seems to indicate the script is working OK. The problem seems to be that web Gmail still wants to show it as Starred even though it isn't. Gmail Android app doesn't show the star applied to the thread. Pictures are worth more...

What my inbox looks like after the script runs. Note the star: What it looks like after the script runs

Yet no Starred messages: Yet no Starred messages

function addStarred2ToDo() {
  var threads = GmailApp.search('is:starred');
  for (var h in threads) {
    var messages = threads[h].getMessages();
    for (var i in messages) {
      if (messages[i].isStarred()) {
        messages[i].unstar();
      }
    }
  }
}

EDIT: I also tried this and neither produce what is expected.

function thisOne() {
  var threads = GmailApp.search('is:starred');
  for (var h in threads) {
    var messages = threads[h].getMessages();
    for (var i in messages) {
      if (messages[i].isStarred()) {
        messages[i].unstar().refresh();
      }
    }
  }
}

function andThisOne() {
  var threads = GmailApp.search('is:starred');
  var toUnstar = [];
  threads.forEach(function (thread) {
    thread.getMessages().forEach(function (message) {
      if (message.isStarred()) {
        toUnstar.push(message);
      }
    });
  });
  GmailApp.unstarMessages(toUnstar);
}


Solution 1:[1]

If you refresh gmail and hover over the star, you will see that the popup says it is Not Stared. Also, this seems to be an issue when you select the star from gmail, as stars that are set by my filters work correctly when my script unstars them.

Solution 2:[2]

This display issue is caused because you do not force Gmail to update the message with a call to refresh() after your call to unstar().

Per documentation of GmailMessage#refresh():

Reloads this message and associated state from Gmail (useful in case the labels, read state, etc., have changed).

messages[i].unstar().refresh();

Should be sufficient to inform Gmail of the new starred status.

Alternately, a batch call to modify the messages will be more efficient in terms of quota usage:

var toUnstar = [];
threads.forEach(function (thread) {
  thread.getMessages().forEach(function (message) {
    if (message.isStarred()) {
      toUnstar.push(message);
      ...
    }
  });
});
GmailApp.unstarMessages(toUnstar);

In my sample I avoid the assumption that iterating an array is safe with for .. in.. and use the more expressive Array.forEach() to indicate that the code is something that we want to apply to every thread and every message in said thread.

Documentation on GmailApp.unstarMessages():

Removes stars from these messages and forces the messages to refresh.

Solution 3:[3]

I'm having a similar problem. I have enabled a superstar, the green-check. I manually set them.

My script finds the relevant threads using "l:^ss_cg" in a search. It finds the starred email, sends a copy of the email somewhere, and then does the unstar.

Afterward, in the web gmail, if i search for the same message again, it shows up with a green star visually, but if I hover over the star icon, it shows 'not starred'.

However, if I run the script again, the thread is found using the search. It doesn't send another copy of the email, however, because I have a check for ".isStarred()" before it sends a copy of the specific email. I have also been able to reduce the number of threads it double-checks by adding a .hasStarredEmails() check to the thread before it starts looking at individual emails.

Doing a search in the web interface for has:green-check reveals only the emails it should.

There is something about .unStar() that doesn't work properly, I think.

I had considered trying to remove the star at the thread level by removing the ^ss_cg label, but that won't work because there is no way to get a GMailLabel object to send to the function.

Solution 4:[4]

Still having same issue where the Gmail web app shows the star. But just made interesting finding.

Assuming

var threads = GmailApp.getStarredThreads()
var thread = threads[0]
var message = thread.getMessages()[0]

GmailApp.unstarMessage(message) would immediately give the following results:

var isMessageStarred = message.isStarred() true
var isThreadStarred = thread.hasStarredMessages() true

GmailApp.unstarMessage(message).refreshMessage(message) would immediately give the following results:
var isMessageStarred = message.isStarred() false
var isThreadStarred = thread.hasStarredMessages() true

And GmailApp.unstarMessage(message).refreshMessage(message).refreshThread(thread) would immediately give the following results:
var isMessageStarred = message.isStarred() false
var isThreadStarred = thread.hasStarredMessages() false

Solution 5:[5]

I had this case. Actually what was happening was I was starring everything that hit the inbox with a filter. Once my script processed the message I unstarred it. But my script was also forwarding the message and that new sent message was being starred by the filter. So the thread still contained a starred message. Argh.

My solution was to create another filter to delete any messages from me.

Solution 6:[6]

Same problem here.

I am unable to unstar() emails which I starred manually in my browser/on my phone.

If I star an email via a rule or a script and then unstar it with a gapps script, unstarring works.

I also tried doing refresh right after unstarring - no difference:

message.unstar()
message.refresh()

I wrote a script which stars always the last message of a previously starred thread to keep my starred threads with the most recent replies at the top of my mailbox. The only problem is that it's not really working if I star an email manually at the beginning and not with a rule or another script.

The code going through my threads:


      for(var z=0;z<messages.length;z++){
        var message = messages[z]
        var messageTime = message.getDate()
        var messageTimeInCET = Utilities.formatDate(messageTime,'CET','yyyy-MM-dd HH:mm:ss') 
        //Logger.log('messageTime: '+ messageTime)

        //Let's add star to the last email in the thread and remove stars from all previous emails
        if(threadLastMessageDateInCET==messageTimeInCET){
          Logger.log('Starred email from: '+ messageTimeInCET)
          message.star()
        }
        else{
          message.unstar()
          message.refresh()
          Logger.log('Unstarred email from: '+messageTimeInCET)
        }
      }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Bob Perry
Solution 2 tehhowch
Solution 3 user2415581
Solution 4 Matthew Schwarz
Solution 5 michaeldon
Solution 6 Daniel Zrust