title: Getting the last message on a Gmail message thread in Katalon Studio
body: <p>I'm using <a href="https://store.katalon.com/product/39/Read-and-Write-Gmail-Messages-Keywords#overview-content" rel="nofollow noreferrer">this plugin for Katalon Studio</a> to access the last unread message from my testing Gmail account.</p>
  <p>My email util class is like:</p>
  <pre><code>
  public final class SMDEmailUtils {
      public static final String MainInboxFolder = &quot;INBOX&quot;;
      public static final String SpamFolder = &quot;[Gmail]/Spam&quot;;
  
      public static String GetMainEmail() {
          if (!GeneralWebUIUtils.GlobalVariableExists('emailID'))
              return &quot;dev@example.com&quot;;
          return GlobalVariable.emailID.toString();
      }
  
      public static String ExtractSignUpLink() {
          final String folderName = this.GetNewMessageFolderName(30, FailureHandling.STOP_ON_FAILURE);
          return this.ProcessHTML(this.GetNewMessage(folderName), &quot;//a[.//div[@class = 'sign-mail-btn-text']]/@href&quot;);
      }
  
      public static String GetNewMessageFolderName(int timeOut,
              FailureHandling failureHandling = FailureHandling.STOP_ON_FAILURE) {
          final long startTime = System.currentTimeMillis()
  
          final Map&lt;String, Integer&gt; folderMessageCountDict = [
              (this.MainInboxFolder) : this.GetMessageCount(this.MainInboxFolder),
              (this.SpamFolder) : this.GetMessageCount(this.SpamFolder),
          ];
  
          while (System.currentTimeMillis() &lt; startTime + 1000 * timeOut) {
              final String folderName = folderMessageCountDict.findResult({String folderName, int initialMessageCount -&gt;
                  if (initialMessageCount &lt; this.GetMessageCount(folderName))
                      return folderName;
                  return null;
              })
  
              if (folderName != null)
                  return folderName;
  
              // TODO: we shouldn't have to do some hard-coded suspension of the runtime. We need to close the store somehow
              Thread.sleep(1000 * 2);
          }
  
          throw new StepFailedException(&quot;Failed to find a folder with a new message in it after ${(System.currentTimeMillis() - startTime) / 1000} seconds&quot;);
      }
  
      public static int GetMessageCount(String folderName) {
          return Gmail.getEmailsCount(this.GetMainEmail(), GlobalVariable.emailPassword, folderName);
      }
  
      public static String GetNewMessage(String folderName) {
          return Gmail.readLatestEMailBodyContent(this.GetMainEmail(), GlobalVariable.emailPassword, folderName);
      }
  
      /**
       * **NOTE**: forked from https://stackoverflow.com/a/2269464/2027839 , and then refactored
       * 
       * Processes HTML, using XPath
       * 
       * @param html
       * @param xpath
       * @return the result 
       */
      public static String ProcessHTML(String html, String xpath) {
  
          final String properHTML = this.ToProperHTML(html);
  
          final Element document = DocumentBuilderFactory.newInstance()
                  .newDocumentBuilder()
                  .parse(new ByteArrayInputStream( properHTML.bytes ))
                  .documentElement;
          return XPathFactory.newInstance()
                  .newXPath()
                  .evaluate( xpath, document );
      }
  
      private static String ToProperHTML(String html) {
          // SOURCE: https://stackoverflow.com/a/19125599/2027839
          String properHTML = html.replaceAll( &quot;(&amp;(?!amp;))&quot;, &quot;&amp;amp;&quot; );
  
          if (properHTML.contains('&lt;!DOCTYPE html'))
              return properHTML;
  
  
          return &quot;&quot;&quot;&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Strict//EN&quot;
          &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&quot;&gt;
  &lt;html&gt;
      &lt;head&gt;&lt;/head&gt;
      &lt;body&gt;
          ${properHTML}
      &lt;/body&gt;
  &lt;/html&gt;
  &quot;&quot;&quot;;
      }
  }
  </code></pre>
  <p>My use case of that is the following:</p>
  <ol>
  <li>a test member lead, whose email forwards to my testing email (<code>[myTestingEmailName]+[memberLeadName]@gmail.com</code>), gets a link to an agreement to sign</li>
  <li>on successful signature, the physician, whose email also forwards to my testing email (<code>[myTestingEmailName]+[physicianName]@gmail.com</code>), gets a link to an agreement to sign</li>
  </ol>
  <p>Step 1 works, the link gets extracted successfully via <code>SMDEmailUtils.ExtractSignUpLink()</code> .</p>
  <p>However, when it is the physician's turn to sign, that same line of code doesn't work. It's giving me the link from the first email message (the one meant for the recipient in step 1, that was already signed).</p>
  <p>I check out my inbox manually, and see this:</p>
  <p><a href="https://i.stack.imgur.com/zKhGX.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/zKhGX.png" alt="enter image description here" /></a></p>
  <p><strong>The AUT sent both email messages on the same thread</strong>, but <strong>the plugin can only handle the first message on the thread</strong>!</p>
  <p>How do I handle this?</p>