[CUS-11560] added filters for gmail api addon.#366
[CUS-11560] added filters for gmail api addon.#366ManojTestsigma wants to merge 1 commit intodevfrom
Conversation
📝 WalkthroughWalkthroughThis PR increments the Maven version from 1.1.7 to 1.1.8 and refactors Gmail API actions across Android, iOS, and Web platforms to use a new centralized Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning Review ran into problems🔥 ProblemsGit: Failed to clone repository. Please run the Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 8
🧹 Nitpick comments (2)
gmail_api/src/main/java/com/web/GetGmailContent.java (1)
42-50: Avoid fetching the whole inbox just to read one message.
inbox.getMessages()builds an array for every message even though only the newest one is used.getMessageCount()plusgetMessage(count)keeps this path lighter on large mailboxes.Proposed fix
- Message[] messages = inbox.getMessages(); - logger.info("messages: " + messages.length); + int messageCount = inbox.getMessageCount(); + logger.info("messages: " + messageCount); - if (messages.length == 0) { + if (messageCount == 0) { setErrorMessage("No emails found in the INBOX for '" + username + "'. The mailbox is empty."); return Result.FAILED; } - Message latestMessage = messages[messages.length - 1]; + Message latestMessage = inbox.getMessage(messageCount);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@gmail_api/src/main/java/com/web/GetGmailContent.java` around lines 42 - 50, The code currently calls inbox.getMessages() which allocates an array for every message; instead, call inbox.getMessageCount() and if zero call setErrorMessage(...) and return Result.FAILED, otherwise fetch only the newest message with inbox.getMessage(messageCount) and assign it to latestMessage. Update the block around Message[] messages / latestMessage to use getMessageCount() and getMessage() so only the single latest Message is retrieved (refer to inbox.getMessages(), inbox.getMessageCount(), inbox.getMessage(), latestMessage, setErrorMessage, Result.FAILED).gmail_api/src/main/java/com/web/GetFilteredGmailContent.java (1)
55-88: Consider extracting the filtered fetch flow intoGmailUtils.The connect/open/search/latest-message/empty-body sequence here is almost identical to
GetGmailContentByRegex. Pulling it behind one helper would keep filter behavior and failure handling aligned in one place.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@gmail_api/src/main/java/com/web/GetFilteredGmailContent.java` around lines 55 - 88, Extract the repeated INBOX fetch/search/latest-message logic into a new GmailUtils helper method (e.g., fetchLatestFilteredMessage or getLatestMessageBySearch) that encapsulates connectToGmail, store.getFolder("INBOX"), inbox.open(...), inbox.search(SearchTerm), selecting the latest Message and returning either the Message or a result object containing the Message and error information; update GetFilteredGmailContent.execute (or the method containing this diff) to call that new GmailUtils method, handle the returned error cases exactly as now (setErrorMessage/Result.FAILED when no messages or empty body), and use GmailUtils.extractContent to obtain the body; ensure the new helper throws or returns meaningful errors so both GetFilteredGmailContent and GetGmailContentByRegex can use the same failure handling and logging.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@gmail_api/src/main/java/com/android/GetGmailContent.java`:
- Around line 65-67: The success message currently includes the full email body
via fullMessage, which leaks sensitive content; update the setSuccessMessage
call in GetGmailContent (the code that constructs the message using
setSuccessMessage, var1.getValue().toString(), and fullMessage) to remove
fullMessage from the output and only reference the runtime variable name (e.g.,
var1.getValue().toString()) or a non-sensitive placeholder (e.g., "email stored
in runtime variable") so the actual email body is not echoed in persisted step
output.
In `@gmail_api/src/main/java/com/android/GetGmailContentByRegex.java`:
- Around line 96-103: The code currently logs and echoes the sensitive regex
match (matchedContent) via logger.info and setSuccessMessage; remove the secret
from logs and success output: keep extracting matcher.group(0) and storing it in
runTimeData.setValue(matchedContent) and
runTimeData.setKey(var1.getValue().toString()), but change the logger.info call
to not include matchedContent (e.g., log a generic "Regex matched" or include
only non-sensitive metadata) and update setSuccessMessage to only mention the
target variable name (var1.getValue().toString()) without appending the
matchedContent; ensure no other references to matchedContent are logged or
returned.
In `@gmail_api/src/main/java/com/ios/GetGmailContent.java`:
- Around line 65-67: The success message currently echoes the full email body
via setSuccessMessage which concatenates fullMessage (see setSuccessMessage,
var1, fullMessage); remove the inclusion of fullMessage from the message and
only reference the runtime variable name/value placeholder (e.g., "Email content
stored in runtime variable: " + var1.getValue().toString()) so the email body
stored in runTimeData is not duplicated in persisted step output.
In `@gmail_api/src/main/java/com/ios/GetGmailContentByRegex.java`:
- Around line 96-103: The code currently logs and includes the extracted secret
(matcher.group(0)) in the success message; remove or redact that sensitive value
from logs and user-visible messages: stop calling logger.info with the full
matchedContent, keep storing the value via runTimeData.setValue(matchedContent)
and runTimeData.setKey(var1.getValue().toString()), and change setSuccessMessage
to a generic message like "Matched content stored in variable: <variableName>"
(no matchedContent). Update any other logging around matcher.group(0) to only
state that a match occurred without printing the match.
In `@gmail_api/src/main/java/com/web/GetGmailContent.java`:
- Around line 62-66: The success message currently includes the entire email
body (fullMessage) which may leak sensitive data; update the code in
GetGmailContent where runTimeData is set (runTimeData.setValue(fullMessage);
runTimeData.setKey(var1.getValue().toString()); setSuccessMessage(...)) so that
setSuccessMessage only mentions the runtime variable name
(var1.getValue().toString()) or a generic confirmation, and does NOT include
fullMessage or any portion of the email body — keep the fullMessage stored only
in runTimeData.
In `@gmail_api/src/main/java/com/web/GetGmailContentByRegex.java`:
- Around line 95-103: The current code logs and surfaces the full extracted
value (matchedContent) which may leak secrets; remove or disable the
logger.info("Regex matched: " + matchedContent) call and stop embedding
matchedContent into setSuccessMessage. Instead keep storing the raw value only
in com.testsigma.sdk.RunTimeData via runTimeData.setValue(matchedContent) and
set the public message via setSuccessMessage to a static or redacted string
(e.g., "Matched content stored in variable: <varName>") referencing
var1.getValue().toString() for context; ensure no other calls echo
matchedContent outside runTimeData.
In `@gmail_api/src/main/java/utils/GmailUtils.java`:
- Around line 38-52: The extractContent method currently only inspects
getBodyPart(0) and casts unsafely; replace it with a recursive MIME-tree walker
in GmailUtils.extractContent that traverses Multipart and Part nodes, checks
Part.isMimeType("text/html") and Part.isMimeType("text/plain") instead of blind
String casts, prefers text/html over text/plain when both exist (handle
multipart/alternative), skips attachments by checking Part.getDisposition() and
Part.getFileName(), and returns the first suitable body text found; ensure you
handle nested Multipart by recursing into each body part and safely call
getContent() only after confirming the part's mime type or traversing further.
- Around line 17-25: The Properties setup in GmailUtils (the Properties props
block) lacks IMAP timeouts causing potential indefinite hangs; add
mail.imaps.connectiontimeout and mail.imaps.timeout entries to props (set to
appropriate millisecond values, e.g. 15000 for connection timeout and 30000 for
read timeout) before the code that opens the store/connection (the code that
uses props to create the IMAP session and calls store.connect or
Session.getInstance). Ensure you use the same "mail.imaps" prefix as the other
properties so the IMAP client honors the timeouts.
---
Nitpick comments:
In `@gmail_api/src/main/java/com/web/GetFilteredGmailContent.java`:
- Around line 55-88: Extract the repeated INBOX fetch/search/latest-message
logic into a new GmailUtils helper method (e.g., fetchLatestFilteredMessage or
getLatestMessageBySearch) that encapsulates connectToGmail,
store.getFolder("INBOX"), inbox.open(...), inbox.search(SearchTerm), selecting
the latest Message and returning either the Message or a result object
containing the Message and error information; update
GetFilteredGmailContent.execute (or the method containing this diff) to call
that new GmailUtils method, handle the returned error cases exactly as now
(setErrorMessage/Result.FAILED when no messages or empty body), and use
GmailUtils.extractContent to obtain the body; ensure the new helper throws or
returns meaningful errors so both GetFilteredGmailContent and
GetGmailContentByRegex can use the same failure handling and logging.
In `@gmail_api/src/main/java/com/web/GetGmailContent.java`:
- Around line 42-50: The code currently calls inbox.getMessages() which
allocates an array for every message; instead, call inbox.getMessageCount() and
if zero call setErrorMessage(...) and return Result.FAILED, otherwise fetch only
the newest message with inbox.getMessage(messageCount) and assign it to
latestMessage. Update the block around Message[] messages / latestMessage to use
getMessageCount() and getMessage() so only the single latest Message is
retrieved (refer to inbox.getMessages(), inbox.getMessageCount(),
inbox.getMessage(), latestMessage, setErrorMessage, Result.FAILED).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 9da0f4a9-fbe4-460e-9105-c3bcaded035d
📒 Files selected for processing (11)
gmail_api/pom.xmlgmail_api/src/main/java/com/android/GetFilteredGmailContent.javagmail_api/src/main/java/com/android/GetGmailContent.javagmail_api/src/main/java/com/android/GetGmailContentByRegex.javagmail_api/src/main/java/com/ios/GetFilteredGmailContent.javagmail_api/src/main/java/com/ios/GetGmailContent.javagmail_api/src/main/java/com/ios/GetGmailContentByRegex.javagmail_api/src/main/java/com/web/GetFilteredGmailContent.javagmail_api/src/main/java/com/web/GetGmailContent.javagmail_api/src/main/java/com/web/GetGmailContentByRegex.javagmail_api/src/main/java/utils/GmailUtils.java
| setSuccessMessage("Email content stored in runtime variable: " + var1.getValue().toString() + | ||
| " and value: " + fullMessage); | ||
| return Result.SUCCESS; |
There was a problem hiding this comment.
Do not echo the full email body in the success message.
fullMessage is already stored in runTimeData. Repeating it here exposes the entire email in persisted step output, which is risky for a public Gmail addon.
🔒 Proposed fix
- setSuccessMessage("Email content stored in runtime variable: " + var1.getValue().toString() +
- " and value: " + fullMessage);
+ setSuccessMessage("Email content stored in runtime variable: " + var1.getValue().toString());
return Result.SUCCESS;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| setSuccessMessage("Email content stored in runtime variable: " + var1.getValue().toString() + | |
| " and value: " + fullMessage); | |
| return Result.SUCCESS; | |
| setSuccessMessage("Email content stored in runtime variable: " + var1.getValue().toString()); | |
| return Result.SUCCESS; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@gmail_api/src/main/java/com/android/GetGmailContent.java` around lines 65 -
67, The success message currently includes the full email body via fullMessage,
which leaks sensitive content; update the setSuccessMessage call in
GetGmailContent (the code that constructs the message using setSuccessMessage,
var1.getValue().toString(), and fullMessage) to remove fullMessage from the
output and only reference the runtime variable name (e.g.,
var1.getValue().toString()) or a non-sensitive placeholder (e.g., "email stored
in runtime variable") so the actual email body is not echoed in persisted step
output.
| String matchedContent = matcher.group(0); | ||
| logger.info("Regex matched: " + matchedContent); | ||
|
|
||
| runTimeData = new com.testsigma.sdk.RunTimeData(); | ||
| runTimeData.setValue(matchedContent); | ||
| runTimeData.setKey(var1.getValue().toString()); | ||
| setSuccessMessage("Matched content stored in variable: " + var1.getValue().toString() + | ||
| ", value: " + matchedContent); |
There was a problem hiding this comment.
Keep the extracted regex match out of logs and success output.
The match is usually the secret the caller wanted to capture. Logging it and echoing it in the success text leaks OTPs/tokens outside the runtime variable channel.
🔒 Proposed fix
String matchedContent = matcher.group(0);
- logger.info("Regex matched: " + matchedContent);
+ logger.info("Regex match found. Length: " + matchedContent.length());
runTimeData = new com.testsigma.sdk.RunTimeData();
runTimeData.setValue(matchedContent);
runTimeData.setKey(var1.getValue().toString());
- setSuccessMessage("Matched content stored in variable: " + var1.getValue().toString() +
- ", value: " + matchedContent);
+ setSuccessMessage("Matched content stored in variable: " + var1.getValue().toString());
return Result.SUCCESS;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| String matchedContent = matcher.group(0); | |
| logger.info("Regex matched: " + matchedContent); | |
| runTimeData = new com.testsigma.sdk.RunTimeData(); | |
| runTimeData.setValue(matchedContent); | |
| runTimeData.setKey(var1.getValue().toString()); | |
| setSuccessMessage("Matched content stored in variable: " + var1.getValue().toString() + | |
| ", value: " + matchedContent); | |
| String matchedContent = matcher.group(0); | |
| logger.info("Regex match found. Length: " + matchedContent.length()); | |
| runTimeData = new com.testsigma.sdk.RunTimeData(); | |
| runTimeData.setValue(matchedContent); | |
| runTimeData.setKey(var1.getValue().toString()); | |
| setSuccessMessage("Matched content stored in variable: " + var1.getValue().toString()); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@gmail_api/src/main/java/com/android/GetGmailContentByRegex.java` around lines
96 - 103, The code currently logs and echoes the sensitive regex match
(matchedContent) via logger.info and setSuccessMessage; remove the secret from
logs and success output: keep extracting matcher.group(0) and storing it in
runTimeData.setValue(matchedContent) and
runTimeData.setKey(var1.getValue().toString()), but change the logger.info call
to not include matchedContent (e.g., log a generic "Regex matched" or include
only non-sensitive metadata) and update setSuccessMessage to only mention the
target variable name (var1.getValue().toString()) without appending the
matchedContent; ensure no other references to matchedContent are logged or
returned.
| setSuccessMessage("Email content stored in runtime variable: " + var1.getValue().toString() + | ||
| " and value: " + fullMessage); | ||
| return Result.SUCCESS; |
There was a problem hiding this comment.
Do not echo the full email body in the success message.
fullMessage is already stored in runTimeData. Repeating it here exposes the entire email in persisted step output, which is risky for a public Gmail addon.
🔒 Proposed fix
- setSuccessMessage("Email content stored in runtime variable: " + var1.getValue().toString() +
- " and value: " + fullMessage);
+ setSuccessMessage("Email content stored in runtime variable: " + var1.getValue().toString());
return Result.SUCCESS;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| setSuccessMessage("Email content stored in runtime variable: " + var1.getValue().toString() + | |
| " and value: " + fullMessage); | |
| return Result.SUCCESS; | |
| setSuccessMessage("Email content stored in runtime variable: " + var1.getValue().toString()); | |
| return Result.SUCCESS; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@gmail_api/src/main/java/com/ios/GetGmailContent.java` around lines 65 - 67,
The success message currently echoes the full email body via setSuccessMessage
which concatenates fullMessage (see setSuccessMessage, var1, fullMessage);
remove the inclusion of fullMessage from the message and only reference the
runtime variable name/value placeholder (e.g., "Email content stored in runtime
variable: " + var1.getValue().toString()) so the email body stored in
runTimeData is not duplicated in persisted step output.
| String matchedContent = matcher.group(0); | ||
| logger.info("Regex matched: " + matchedContent); | ||
|
|
||
| runTimeData = new com.testsigma.sdk.RunTimeData(); | ||
| runTimeData.setValue(matchedContent); | ||
| runTimeData.setKey(var1.getValue().toString()); | ||
| setSuccessMessage("Matched content stored in variable: " + var1.getValue().toString() + | ||
| ", value: " + matchedContent); |
There was a problem hiding this comment.
Keep the extracted regex match out of logs and success output.
The match is usually the secret the caller wanted to capture. Logging it and echoing it in the success text leaks OTPs/tokens outside the runtime variable channel.
🔒 Proposed fix
String matchedContent = matcher.group(0);
- logger.info("Regex matched: " + matchedContent);
+ logger.info("Regex match found. Length: " + matchedContent.length());
runTimeData = new com.testsigma.sdk.RunTimeData();
runTimeData.setValue(matchedContent);
runTimeData.setKey(var1.getValue().toString());
- setSuccessMessage("Matched content stored in variable: " + var1.getValue().toString() +
- ", value: " + matchedContent);
+ setSuccessMessage("Matched content stored in variable: " + var1.getValue().toString());
return Result.SUCCESS;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| String matchedContent = matcher.group(0); | |
| logger.info("Regex matched: " + matchedContent); | |
| runTimeData = new com.testsigma.sdk.RunTimeData(); | |
| runTimeData.setValue(matchedContent); | |
| runTimeData.setKey(var1.getValue().toString()); | |
| setSuccessMessage("Matched content stored in variable: " + var1.getValue().toString() + | |
| ", value: " + matchedContent); | |
| String matchedContent = matcher.group(0); | |
| logger.info("Regex match found. Length: " + matchedContent.length()); | |
| runTimeData = new com.testsigma.sdk.RunTimeData(); | |
| runTimeData.setValue(matchedContent); | |
| runTimeData.setKey(var1.getValue().toString()); | |
| setSuccessMessage("Matched content stored in variable: " + var1.getValue().toString()); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@gmail_api/src/main/java/com/ios/GetGmailContentByRegex.java` around lines 96
- 103, The code currently logs and includes the extracted secret
(matcher.group(0)) in the success message; remove or redact that sensitive value
from logs and user-visible messages: stop calling logger.info with the full
matchedContent, keep storing the value via runTimeData.setValue(matchedContent)
and runTimeData.setKey(var1.getValue().toString()), and change setSuccessMessage
to a generic message like "Matched content stored in variable: <variableName>"
(no matchedContent). Update any other logging around matcher.group(0) to only
state that a match occurred without printing the match.
| runTimeData = new com.testsigma.sdk.RunTimeData(); | ||
| runTimeData.setValue(FullMessage); | ||
| runTimeData.setValue(fullMessage); | ||
| runTimeData.setKey(var1.getValue().toString()); | ||
| setSuccessMessage("Email content stored in runtime variable: " + var1.getValue().toString() + "and value: " + FullMessage); | ||
|
|
||
| inbox.close(false); | ||
| store.close(); | ||
|
|
||
| setSuccessMessage("Email content stored in runtime variable: " + var1.getValue().toString() + | ||
| " and value: " + fullMessage); |
There was a problem hiding this comment.
Don't include the email body in the success message.
This duplicates the full mailbox content into step/report output, which can leak OTPs or PII and create very large result payloads. Store the body only in runTimeData.
Proposed fix
runTimeData = new com.testsigma.sdk.RunTimeData();
runTimeData.setValue(fullMessage);
runTimeData.setKey(var1.getValue().toString());
- setSuccessMessage("Email content stored in runtime variable: " + var1.getValue().toString() +
- " and value: " + fullMessage);
+ setSuccessMessage("Email content stored in runtime variable: " + var1.getValue().toString());
return Result.SUCCESS;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| runTimeData = new com.testsigma.sdk.RunTimeData(); | |
| runTimeData.setValue(FullMessage); | |
| runTimeData.setValue(fullMessage); | |
| runTimeData.setKey(var1.getValue().toString()); | |
| setSuccessMessage("Email content stored in runtime variable: " + var1.getValue().toString() + "and value: " + FullMessage); | |
| inbox.close(false); | |
| store.close(); | |
| setSuccessMessage("Email content stored in runtime variable: " + var1.getValue().toString() + | |
| " and value: " + fullMessage); | |
| runTimeData = new com.testsigma.sdk.RunTimeData(); | |
| runTimeData.setValue(fullMessage); | |
| runTimeData.setKey(var1.getValue().toString()); | |
| setSuccessMessage("Email content stored in runtime variable: " + var1.getValue().toString()); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@gmail_api/src/main/java/com/web/GetGmailContent.java` around lines 62 - 66,
The success message currently includes the entire email body (fullMessage) which
may leak sensitive data; update the code in GetGmailContent where runTimeData is
set (runTimeData.setValue(fullMessage);
runTimeData.setKey(var1.getValue().toString()); setSuccessMessage(...)) so that
setSuccessMessage only mentions the runtime variable name
(var1.getValue().toString()) or a generic confirmation, and does NOT include
fullMessage or any portion of the email body — keep the fullMessage stored only
in runTimeData.
| if (matcher.find()) { | ||
| String matchedContent = matcher.group(0); | ||
| logger.info("Regex matched: " + matchedContent); | ||
|
|
||
| runTimeData = new com.testsigma.sdk.RunTimeData(); | ||
| runTimeData.setValue(matchedContent); | ||
| runTimeData.setKey(var1.getValue().toString()); | ||
| setSuccessMessage("Matched content stored in variable: " + var1.getValue().toString() + | ||
| ", value: " + matchedContent); |
There was a problem hiding this comment.
Don't echo the matched payload into routine output.
This action will often extract OTPs or tokens. Logging matchedContent and copying it into setSuccessMessage(...) leaks the secret into normal execution output; keep it only in runTimeData and use a static or redacted message instead.
Proposed fix
if (matcher.find()) {
String matchedContent = matcher.group(0);
- logger.info("Regex matched: " + matchedContent);
+ logger.info("Regex matched successfully");
runTimeData = new com.testsigma.sdk.RunTimeData();
runTimeData.setValue(matchedContent);
runTimeData.setKey(var1.getValue().toString());
- setSuccessMessage("Matched content stored in variable: " + var1.getValue().toString() +
- ", value: " + matchedContent);
+ setSuccessMessage("Matched content stored in variable: " + var1.getValue().toString());
return Result.SUCCESS;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@gmail_api/src/main/java/com/web/GetGmailContentByRegex.java` around lines 95
- 103, The current code logs and surfaces the full extracted value
(matchedContent) which may leak secrets; remove or disable the
logger.info("Regex matched: " + matchedContent) call and stop embedding
matchedContent into setSuccessMessage. Instead keep storing the raw value only
in com.testsigma.sdk.RunTimeData via runTimeData.setValue(matchedContent) and
set the public message via setSuccessMessage to a static or redacted string
(e.g., "Matched content stored in variable: <varName>") referencing
var1.getValue().toString() for context; ensure no other calls echo
matchedContent outside runTimeData.
| Properties props = new Properties(); | ||
| props.setProperty("mail.store.protocol", "imaps"); | ||
| props.setProperty("mail.imaps.host", HOST); | ||
| props.setProperty("mail.imaps.port", PORT); | ||
| props.setProperty("mail.imaps.auth", "true"); | ||
| props.setProperty("mail.imaps.starttls.enable", "true"); | ||
| props.setProperty("mail.imap.ssl.protocols", "TLSv1.2"); | ||
| props.setProperty("mail.imap.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); | ||
|
|
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find . -name "GmailUtils.java" -type fRepository: testsigmahq/testsigma-addons
Length of output: 1887
🏁 Script executed:
# Once found, read the file to see full context
cat -n gmail_api/src/main/java/utils/GmailUtils.java | head -40Repository: testsigmahq/testsigma-addons
Length of output: 1887
🌐 Web query:
JavaMail IMAPS timeout properties mail.imaps.connectiontimeout mail.imaps.timeout
💡 Result:
In JavaMail (and Jakarta Mail), the properties mail.imaps.connectiontimeout and mail.imaps.timeout control timeouts for IMAPS (IMAP over SSL) connections. mail.imaps.connectiontimeout: Socket connection timeout value in milliseconds. Implemented by java.net.Socket. Default is infinite timeout. Controls the time to establish the TCP connection to the server. mail.imaps.timeout: Socket read timeout value in milliseconds. Implemented by java.net.Socket. Default is infinite timeout. Controls the timeout for reading data from the server after connection. These properties are set in the Properties object used to create the Session, using the "imaps" prefix because they apply specifically to the IMAPS protocol. For example: Properties props = new Properties; props.setProperty("mail.imaps.host", "imap.example.com"); props.setProperty("mail.imaps.port", "993"); props.setProperty("mail.imaps.connectiontimeout", "30000"); // 30 seconds props.setProperty("mail.imaps.timeout", "60000"); // 60 seconds Session session = Session.getInstance(props); Note that for the plain "imap" protocol (non-SSL), use "mail.imap.connectiontimeout" and "mail.imap.timeout". The IMAPS provider shares the same property set as IMAP but with the protocol prefix. There is also mail.imaps.writetimeout for write timeouts (default infinite). These are documented in the official JavaMail IMAP provider documentation and confirmed in usage examples across Stack Overflow and other technical resources. As of 2026, these remain standard in Jakarta Mail implementations.
Citations:
- 1: https://javaee.github.io/javamail/docs/api/com/sun/mail/imap/package-summary.html
- 2: https://javadoc.io/static/com.sun.mail/jakarta.mail/2.0.1/jakarta.mail/com/sun/mail/imap/package-summary.html
- 3: https://jakarta.ee/specifications/mail/1.6/apidocs/com/sun/mail/imap/package-summary
- 4: https://stackoverflow.com/questions/46149360/javamail-connect-over-imaps-to-an-e-mail-store-extend-the-timeout
- 5: https://stackoverflow.com/questions/33915172/imapprotocol-readresponse-timeout-javamail
- 6: https://forums.oracle.com/ords/apexds/post/while-reading-mail-using-imap-timed-out-exception-thrown-5427
- 7: https://connector.sourceforge.net/doc-files/Properties.html
Add IMAP connection and read timeouts.
This shared utility has no timeout configured, leaving connections vulnerable to indefinite hangs. Add mail.imaps.connectiontimeout and mail.imaps.timeout before the connection call:
Proposed fix
props.setProperty("mail.imaps.auth", "true");
props.setProperty("mail.imaps.starttls.enable", "true");
+ props.setProperty("mail.imaps.connectiontimeout", "10000");
+ props.setProperty("mail.imaps.timeout", "10000");
props.setProperty("mail.imap.ssl.protocols", "TLSv1.2");
props.setProperty("mail.imap.socketFactory.class", "javax.net.ssl.SSLSocketFactory");📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| Properties props = new Properties(); | |
| props.setProperty("mail.store.protocol", "imaps"); | |
| props.setProperty("mail.imaps.host", HOST); | |
| props.setProperty("mail.imaps.port", PORT); | |
| props.setProperty("mail.imaps.auth", "true"); | |
| props.setProperty("mail.imaps.starttls.enable", "true"); | |
| props.setProperty("mail.imap.ssl.protocols", "TLSv1.2"); | |
| props.setProperty("mail.imap.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); | |
| Properties props = new Properties(); | |
| props.setProperty("mail.store.protocol", "imaps"); | |
| props.setProperty("mail.imaps.host", HOST); | |
| props.setProperty("mail.imaps.port", PORT); | |
| props.setProperty("mail.imaps.auth", "true"); | |
| props.setProperty("mail.imaps.starttls.enable", "true"); | |
| props.setProperty("mail.imaps.connectiontimeout", "10000"); | |
| props.setProperty("mail.imaps.timeout", "10000"); | |
| props.setProperty("mail.imap.ssl.protocols", "TLSv1.2"); | |
| props.setProperty("mail.imap.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@gmail_api/src/main/java/utils/GmailUtils.java` around lines 17 - 25, The
Properties setup in GmailUtils (the Properties props block) lacks IMAP timeouts
causing potential indefinite hangs; add mail.imaps.connectiontimeout and
mail.imaps.timeout entries to props (set to appropriate millisecond values, e.g.
15000 for connection timeout and 30000 for read timeout) before the code that
opens the store/connection (the code that uses props to create the IMAP session
and calls store.connect or Session.getInstance). Ensure you use the same
"mail.imaps" prefix as the other properties so the IMAP client honors the
timeouts.
| public static String extractContent(Object content) throws Exception { | ||
| if (content instanceof String) { | ||
| return (String) content; | ||
| } else if (content instanceof Multipart) { | ||
| Multipart multipart = (Multipart) content; | ||
| BodyPart bodyPart = multipart.getBodyPart(0); | ||
| Object bodyContent = bodyPart.getContent(); | ||
| if (bodyContent instanceof String) { | ||
| return (String) bodyContent; | ||
| } else if (bodyContent instanceof Multipart) { | ||
| Multipart bodyMultipart = (Multipart) bodyContent; | ||
| return (String) bodyMultipart.getBodyPart(0).getContent(); | ||
| } | ||
| } | ||
| return null; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find . -type f -name "GmailUtils.java" | head -20Repository: testsigmahq/testsigma-addons
Length of output: 1887
🌐 Web query:
Java Mail API multipart email extraction best practices MIME parts
💡 Result:
Best practices for extracting multipart email content using Jakarta Mail API (formerly JavaMail) involve recursively parsing the MimeMessage to handle nested multiparts like multipart/mixed, multipart/alternative, and multipart/related. The key is to use a recursive function that checks each Part's MIME type with isMimeType and processes text content, attachments, or nested Multiparts accordingly. Core approach from official docs and examples: 1. Call message.getContent to get the root content Object. 2. If it's a Multipart (e.g., MimeMultipart), iterate over getBodyPart(i) for i=0 to getCount-1. 3. For each BodyPart: - Check isMimeType("text/plain") or "text/html" and use getContent as String. - For attachments: check getDisposition == Part.ATTACHMENT or specific MIME types like "image/", use getInputStream or getFileName. - If isMimeType("multipart/"), recurse on (Multipart)part.getContent. 4. Prefer "text/html" over "text/plain" in multipart/alternative by checking subtype or processing last first. 5. Handle encoding issues: Set System property "mail.mime.parameters.strict" = "false" if charset parameters are malformed. Use part.getInputStream for raw bytes if getContent fails. Example recursive extraction function (adapted from JavaMail FAQ and StackOverflow high-score answers): private String getText(Part p) throws MessagingException, IOException { if (p.isMimeType("text/")) { String s = (String) p.getContent; textIsHtml = p.isMimeType("text/html"); return s; } if (p.isMimeType("multipart/alternative")) { // Prefer HTML over plain Multipart mp = (Multipart) p.getContent; String text = null; for (int i = 0; i < mp.getCount; i++) { Part bp = mp.getBodyPart(i); if (bp.isMimeType("text/plain")) { if (text == null) text = getText(bp); } else if (bp.isMimeType("text/html")) { htmlText = getText(bp); } } return (htmlText != null ? htmlText : text); } else if (p.isMimeType("multipart/")) { Multipart mp = (Multipart) p.getContent; for (int i = 0; i < mp.getCount; i++) { String s = getText(mp.getBodyPart(i)); if (s != null) return s; } } return null; } For attachments, collect in a separate pass or list: if (Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition) || part.isMimeType("application/") || part.isMimeType("image/")) { // Save using part.getFileName, part.getInputStream } Use libraries like Apache Commons Email MimeMessageParser for production to avoid reinventing recursion. Official MIME parsing properties (from Jakarta Mail docs): - mail.mime.multipart.allowempty=true (allow empty multiparts) - mail.mime.multipart.ignoremissingendboundary=false (strict parsing) Note: As of 2026, use Jakarta Mail (jakarta.mail:*), not legacy javax.mail. Always handle IOException and MessagingException.
Citations:
- 1: https://stackoverflow.com/questions/42280533/javamail-how-to-read-actual-message-content-instead-of-javax-mail-internet-m
- 2: https://javaee.github.io/javamail/docs/api/javax/mail/internet/MimeMultipart.html
- 3: https://docs.oracle.com/javaee/7/api/javax/mail/internet/MimeMultipart.html
- 4: https://javaee.github.io/javamail/docs/api/javax/mail/internet/MimeMessage.html
- 5: https://jakartaee.github.io/mail-api/docs/api/jakarta.mail/jakarta/mail/Multipart.html
- 6: https://commons.apache.org/proper/commons-email/commons-email2-jakarta/jacoco/org.apache.commons.mail2.jakarta.util/MimeMessageParser.java.html
- 7: https://jakartaee.github.io/mail-api/docs/api/jakarta.mail/jakarta/mail/internet/MimeMessage.html
- 8: https://stackoverflow.com/questions/11240368/how-to-read-text-inside-body-of-mail-using-javax-mail
- 9: https://jakarta.ee/specifications/mail/1.6/apidocs/javax/mail/internet/mimemultipart
🌐 Web query:
JavaMail how to extract text body from multipart message with attachments
💡 Result:
To extract the text body from a multipart email message with attachments using JavaMail (Jakarta Mail), check if the message content is a Multipart. Iterate through the BodyParts, preferring text parts (text/plain or text/html) while skipping attachments (those with Content-Disposition: attachment). Use this recursive method from the official JavaMail FAQ, which handles common cases like multipart/mixed (body first, then attachments) and nested multipart/alternative (plain vs HTML): private boolean textIsHtml = false; private String getText(Part p) throws MessagingException, IOException { if (p.isMimeType("text/")) { String s = (String) p.getContent; textIsHtml = p.isMimeType("text/html"); return s; } if (p.isMimeType("multipart/alternative")) { // Prefer HTML over plain text Multipart mp = (Multipart) p.getContent; String text = null; for (int i = 0; i < mp.getCount; i++) { Part bp = mp.getBodyPart(i); if (bp.isMimeType("text/plain")) { if (text == null) text = getText(bp); continue; } else if (bp.isMimeType("text/html")) { String s = getText(bp); if (s != null) return s; } else { return getText(bp); } } return text; } else if (p.isMimeType("multipart/")) { Multipart mp = (Multipart) p.getContent; for (int i = 0; i < mp.getCount; i++) { String s = getText(mp.getBodyPart(i)); if (s != null) return s; } } return null; } Call it with: String body = getText(message); This returns the primary text content, detecting if it's HTML via textIsHtml. For attachments, continue iterating and check Part.getDisposition != null && Part.ATTACHMENT.equalsIgnoreCase(Part.getDisposition). Note: Use jakarta.mail.* for versions 2.0+ (post-Java EE).
Citations:
- 1: https://www.oracle.com/technetwork/java/javamail/faq/index.html
- 2: https://javaee.github.io/javamail/FAQ
- 3: https://jakartaee.github.io/mail-api/FAQ.html
- 4: https://www.baeldung.com/java-read-text-inside-mail-body
- 5: https://stackoverflow.com/questions/11240368/how-to-read-text-inside-body-of-mail-using-javax-mail
Walk the MIME tree instead of only getBodyPart(0).
The current implementation ignores all but the first part and blindly casts without type checking. This fails on:
- Multipart emails where attachments precede the body
multipart/alternativecontaining both plain text and HTML versions- Nested multipart structures like
multipart/relatedwithinmultipart/mixed
The proposed recursive approach correctly iterates all parts and skips attachments. However, consider using isMimeType() to properly identify text parts (avoiding unsafe String casts) and handle multipart/alternative by preferring HTML over plain text.
📨 Proposed fix
public static String extractContent(Object content) throws Exception {
if (content instanceof String) {
return (String) content;
- } else if (content instanceof Multipart) {
- Multipart multipart = (Multipart) content;
- BodyPart bodyPart = multipart.getBodyPart(0);
- Object bodyContent = bodyPart.getContent();
- if (bodyContent instanceof String) {
- return (String) bodyContent;
- } else if (bodyContent instanceof Multipart) {
- Multipart bodyMultipart = (Multipart) bodyContent;
- return (String) bodyMultipart.getBodyPart(0).getContent();
+ }
+ if (content instanceof Multipart) {
+ Multipart multipart = (Multipart) content;
+ for (int i = 0; i < multipart.getCount(); i++) {
+ BodyPart bodyPart = multipart.getBodyPart(i);
+ if (Part.ATTACHMENT.equalsIgnoreCase(bodyPart.getDisposition())) {
+ continue;
+ }
+ String extracted = extractContent(bodyPart.getContent());
+ if (extracted != null && !extracted.trim().isEmpty()) {
+ return extracted;
+ }
}
}
return null;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| public static String extractContent(Object content) throws Exception { | |
| if (content instanceof String) { | |
| return (String) content; | |
| } else if (content instanceof Multipart) { | |
| Multipart multipart = (Multipart) content; | |
| BodyPart bodyPart = multipart.getBodyPart(0); | |
| Object bodyContent = bodyPart.getContent(); | |
| if (bodyContent instanceof String) { | |
| return (String) bodyContent; | |
| } else if (bodyContent instanceof Multipart) { | |
| Multipart bodyMultipart = (Multipart) bodyContent; | |
| return (String) bodyMultipart.getBodyPart(0).getContent(); | |
| } | |
| } | |
| return null; | |
| public static String extractContent(Object content) throws Exception { | |
| if (content instanceof String) { | |
| return (String) content; | |
| } | |
| if (content instanceof Multipart) { | |
| Multipart multipart = (Multipart) content; | |
| for (int i = 0; i < multipart.getCount(); i++) { | |
| BodyPart bodyPart = multipart.getBodyPart(i); | |
| if (Part.ATTACHMENT.equalsIgnoreCase(bodyPart.getDisposition())) { | |
| continue; | |
| } | |
| String extracted = extractContent(bodyPart.getContent()); | |
| if (extracted != null && !extracted.trim().isEmpty()) { | |
| return extracted; | |
| } | |
| } | |
| } | |
| return null; | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@gmail_api/src/main/java/utils/GmailUtils.java` around lines 38 - 52, The
extractContent method currently only inspects getBodyPart(0) and casts unsafely;
replace it with a recursive MIME-tree walker in GmailUtils.extractContent that
traverses Multipart and Part nodes, checks Part.isMimeType("text/html") and
Part.isMimeType("text/plain") instead of blind String casts, prefers text/html
over text/plain when both exist (handle multipart/alternative), skips
attachments by checking Part.getDisposition() and Part.getFileName(), and
returns the first suitable body text found; ensure you handle nested Multipart
by recursing into each body part and safely call getContent() only after
confirming the part's mime type or traversing further.
please review this addon and publish as PUBLIC
Addon name : Gmail_api
Addon accont: https://jarvis.testsigma.com/ui/tenants/2817/addons
Jira: https://testsigma.atlassian.net/browse/CUS-11560
fix
Summary by CodeRabbit
Release Notes v1.1.8