Skip to content

test: cover folded line-break reply-to parsing error#2

Merged
ryush00 merged 1 commit intomainfrom
codex/fix-reply-to-serialization-bug-in-mailtrap-gem-itmsm1
Mar 8, 2026
Merged

test: cover folded line-break reply-to parsing error#2
ryush00 merged 1 commit intomainfrom
codex/fix-reply-to-serialization-bug-in-mailtrap-gem-itmsm1

Conversation

@ryush00
Copy link
Member

@ryush00 ryush00 commented Mar 8, 2026

Summary

  • Added a case to the when 'reply-to' is invalid context in spec/mailtrap/mail_spec.rb where address parsing breaks due to line folding.
  • Instead of copying and pasting the screenshot string as-is, the value was generated by composing it inside the test.
    • The display name is generated in encoded-word form by Base64-encoding a UTF-8 name
    • The domain is built as a folded address (no-reply@...) by joining the exa / mple.com fragments with "\r\n "
  • Verifies that from_message raises Mailtrap::Error for that input.

Verification

  • bundle exec rspec spec/mailtrap/mail_spec.rb passed
  • bundle exec rubocop spec/mailtrap/mail_spec.rb passed

Codex Task

@gemini-code-assist
Copy link

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request refines the handling of the 'reply-to' email header within the Mailtrap integration. It ensures that 'reply-to' addresses are consistently parsed into a structured format and introduces robust error detection for invalid 'reply-to' values, particularly those that might contain folded line breaks, preventing potential parsing failures and improving the reliability of email processing.

Highlights

  • Improved Reply-To Header Parsing: The system now correctly extracts and processes the 'reply-to' header, treating it as a structured field rather than a generic header, ensuring consistent handling across various formats.
  • Enhanced Error Handling for Invalid Reply-To Formats: New tests were added to specifically catch and raise a Mailtrap::Error when 'reply-to' addresses are malformed, including those with folded line breaks, preventing potential parsing failures.
  • Refactored Reply-To Representation: The 'reply-to' information is now represented as a dedicated structured field in the processed message, rather than being part of the general headers, streamlining data access and consistency.
Changelog
  • lib/mailtrap/mail.rb
    • Added replyto to the list of special headers to be processed.
    • Included reply_to as a distinct field in the structured output of the from_message method.
  • spec/fixtures/vcr_cassettes/Mailtrap_ActionMailer_DeliveryMethod/deliver/converts_the_message_and_sends_via_API.yml
    • Updated the VCR cassette to reflect the new structured reply_to field, moving it from the headers section to a top-level attribute.
  • spec/mailtrap/mail_spec.rb
    • Modified existing tests to remove Reply-To from expected generic headers, aligning with its new structured handling.
    • Introduced new test cases to verify correct parsing of reply-to in various valid formats (with/without names, UTF-8 encoded names).
    • Added tests to confirm that all reply-to header variants (e.g., Reply-To, REPLY-TO) are stripped from generic headers after being processed into the structured reply_to field.
    • Implemented new error-handling tests for invalid reply-to formats, specifically covering cases with folded line breaks, to ensure Mailtrap::Error is raised.
Activity
  • The author confirmed that bundle exec rspec spec/mailtrap/mail_spec.rb passed.
  • The author confirmed that bundle exec rubocop spec/mailtrap/mail_spec.rb passed.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai
Copy link

coderabbitai bot commented Mar 8, 2026

📝 Walkthrough

Walkthrough

The PR adds Reply-To header support to the Mailtrap mail library by including "replyto" in the SPECIAL_HEADERS constant and extracting the first reply-to address from incoming messages to pass to the Mailtrap::Mail::Base constructor. Tests verify various Reply-To formats are correctly processed and invalid values are handled with appropriate errors.

Changes

Cohort / File(s) Summary
Core Mail Processing
lib/mailtrap/mail.rb
Added "replyto" to SPECIAL_HEADERS constant and implemented reply_to extraction from incoming message objects using prepare_addresses(message['reply-to']).first.
Mail Spec Tests
spec/mailtrap/mail_spec.rb
Removed Reply-To header expectation from initial custom headers block. Added comprehensive test cases for mapping various Reply-To formats to structured field, validating error handling for invalid Reply-To values including folded line breaks.
VCR Fixture
spec/fixtures/vcr_cassettes/Mailtrap_ActionMailer_DeliveryMethod/_deliver_/converts_the_message_and_sends_via_API.yml
Updated API payload to include new reply_to field with email object and removed Reply-To from headers block.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 A reply-to hops into the fold,
No longer lost in headers cold,
From message mail to structured dreams,
The bunny's mail now flows in streams! 📬

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description provides a summary and verification details, but lacks required template sections including Motivation, Changes list, How to test checklist, and Images/GIFs comparison. Add missing sections: a Motivation section explaining why the change is needed, a Changes section with bullet points, a How to test section with checkboxes, and the Images and GIFs comparison table if applicable.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'test: cover folded line-break reply-to parsing error' accurately describes the main change in the PR, which adds a test case for handling folded line-break reply-to parsing errors.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/fix-reply-to-serialization-bug-in-mailtrap-gem-itmsm1

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

이 PR은 reply-to 필드 지원을 추가하고 이에 대한 종합적인 테스트를 포함하고 있습니다. 특히 reply-to 주소에 접힌 줄바꿈(folded line break)이 포함된 경우의 파싱 오류에 대한 테스트 케이스를 추가하여 이메일 파싱의 견고성을 높인 점이 인상적입니다. 구현이 깔끔하고 테스트가 잘 구조화되어 있습니다. 여러 개의 reply-to 주소를 처리하는 방식에 대해 gem의 동작을 더 예측 가능하게 만들기 위한 한 가지 개선 제안이 있습니다.

to: prepare_addresses(message['to']),
cc: prepare_addresses(message['cc']),
bcc: prepare_addresses(message['bcc']),
reply_to: prepare_addresses(message['reply-to']).first,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

여러 개의 reply-to 주소가 제공되었을 때 첫 번째 주소만 자동으로 사용하는 것은 예기치 않은 동작이나 데이터 손실로 이어질 수 있습니다. mail gem은 여러 개의 Reply-To 주소를 허용하지만, Mailtrap API는 하나만 지원하는 것으로 보입니다. 이 경우, 하나보다 많은 주소가 발견되면 오류를 발생시켜 사용자에게 호환성 문제를 알리는 것이 더 견고한 방법일 것입니다.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@lib/mailtrap/mail.rb`:
- Line 20: The current code silently drops additional addresses by removing the
original Reply-To header from headers and then keeping only the first parsed
mailbox; instead, detect when the parsed mailbox list (the value used to set
replyto/reply_to) contains more than one address and raise a clear error (e.g.,
ArgumentError) indicating multi-address Reply-To is unsupported; do not strip or
mutate headers when rejecting — only accept a single mailbox and proceed,
otherwise raise before modifying headers. Use the existing identifiers replyto
(or reply_to) and headers and the mailbox-list parsing site (where .first is
currently used) to implement this guard and error message.

In
`@spec/fixtures/vcr_cassettes/Mailtrap_ActionMailer_DeliveryMethod/_deliver_/converts_the_message_and_sends_via_API.yml`:
- Line 8: Replace any real-looking email addresses inside the VCR cassette
string payload (fields "to", "cc", "bcc", and "reply_to" and any headers) with
reserved test domains such as example.com or example.invalid; specifically
update the JSON string value (the long "string": '...') so entries like
"to":[{"email":"to_1@railsware.com",...}], "cc":[...], "bcc":[...], and
"reply_to":{"email":"reply-to@railsware.com"} are changed to use non-production
domains (e.g., "to_1@example.com", "reply-to@example.invalid") and ensure any
other email-like values in that same "string" are similarly sanitized while
preserving message structure and encoding.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f5dfe073-dbbe-4181-8ad4-d0182f8239c7

📥 Commits

Reviewing files that changed from the base of the PR and between 13d18c9 and 1bf3b14.

📒 Files selected for processing (3)
  • lib/mailtrap/mail.rb
  • spec/fixtures/vcr_cassettes/Mailtrap_ActionMailer_DeliveryMethod/_deliver_/converts_the_message_and_sends_via_API.yml
  • spec/mailtrap/mail_spec.rb

category
customvariables
contenttype
replyto
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Reject multi-address Reply-To headers instead of truncating them.

Line 199 parses a valid Reply-To mailbox-list and then keeps only .first, while Line 20 ensures the original header is stripped from headers. That silently drops every address after the first. If the API only supports a single reply_to, please raise here rather than changing reply semantics.

Possible guard
-          reply_to: prepare_addresses(message['reply-to']).first,
+          reply_to: prepare_reply_to(message['reply-to']),
+      def prepare_reply_to(header)
+        addresses = prepare_addresses(header)
+        return nil if addresses.empty?
+
+        if addresses.length > 1
+          raise Mailtrap::Error, ["failed to parse 'Reply-To': multiple addresses are not supported"]
+        end
+
+        addresses.first
+      end

Also applies to: 199-199

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/mailtrap/mail.rb` at line 20, The current code silently drops additional
addresses by removing the original Reply-To header from headers and then keeping
only the first parsed mailbox; instead, detect when the parsed mailbox list (the
value used to set replyto/reply_to) contains more than one address and raise a
clear error (e.g., ArgumentError) indicating multi-address Reply-To is
unsupported; do not strip or mutate headers when rejecting — only accept a
single mailbox and proceed, otherwise raise before modifying headers. Use the
existing identifiers replyto (or reply_to) and headers and the mailbox-list
parsing site (where .first is currently used) to implement this guard and error
message.

body:
encoding: UTF-8
string: '{"from":{"email":"mailtrap@mailtrap.io","name":"Mailtrap Test"},"to":[{"email":"to_1@railsware.com","name":"To 1"},{"email":"to_2@railsware.com"}],"cc":[{"email":"cc_1@railsware.com"},{"email":"cc_2@railsware.com","name":"Cc 2"}],"bcc":[{"email":"bcc_1@railsware.com"},{"email":"bcc_2@railsware.com"}],"subject":"You are awesome!","text":"Some text","html":"<div>HTML part</div>","attachments":[{"content":"VGhpcyBpcyBhIHRleHQgZmlsZQo=","type":"text/plain","filename":"file.txt","disposition":"attachment","content_id":"txt_content_id@test.mail"},{"content":"iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABmJLR0QA/wD/AP+gvaeTAAABiElEQVRIid3VSW5UMRCA4U8d0gIx7AjhAghBTgFICAkxRFHukDDDIRiuwI7xPNAMISQRV4CABFmkWbie2nrt9muaFZTkxavhr7Jfucz/Ln2s4hU28B0/sBO6VczPCl/GNoYd6wsuZ3ELWKuBe3iSAQa4g7M4jEM4jRt4g5+4lMEHEbc+KUED/xVOvY5iThXgg/gek+UMfq4CbstU8L7RmU/c3qxwUkc0TnN/CT9Ycn4djrenhB/H24j5iMXQX8TTUsCncD6T6daUtzyp8hNSV30uJfgWAUfje70AqMFF7FC6kGOy20rQPoKTBd1ii3EsbF9LCUpH1K62q1uWwr5RSvAyjHdb+rzqSZU38iB8npWMTZu+M96mzU5qfT6H98FYKTn0sRUONwv2hQqcNK+G2FSZsNeNRsX5CqwtF7CHfVzpcn6cJbmlfqsPSJXvRczDaarpZUmaf3JP6pAjsZZw3+jM9/FIffKOyTXpRnY9OJu4+ifgXOaljnghtedurA94HraZn8x/Q34DYaON8Fk9Z1IAAAAASUVORK5CYII=","type":"image/png","filename":"file.png","disposition":"inline","content_id":"png_content_id@test.mail"}],"headers":{"Reply-To":"reply-to@railsware.com","X-Special-Domain-Specific-Header":"SecretValue","One-more-custom-header":"CustomValue"},"category":"Module Test"}'
string: '{"from":{"email":"mailtrap@mailtrap.io","name":"Mailtrap Test"},"to":[{"email":"to_1@railsware.com","name":"To 1"},{"email":"to_2@railsware.com"}],"reply_to":{"email":"reply-to@railsware.com"},"cc":[{"email":"cc_1@railsware.com"},{"email":"cc_2@railsware.com","name":"Cc 2"}],"bcc":[{"email":"bcc_1@railsware.com"},{"email":"bcc_2@railsware.com"}],"subject":"You are awesome!","text":"Some text","html":"<div>HTML part</div>","attachments":[{"content":"VGhpcyBpcyBhIHRleHQgZmlsZQo=","type":"text/plain","filename":"file.txt","disposition":"attachment","content_id":"txt_content_id@test.mail"},{"content":"iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABmJLR0QA/wD/AP+gvaeTAAABiElEQVRIid3VSW5UMRCA4U8d0gIx7AjhAghBTgFICAkxRFHukDDDIRiuwI7xPNAMISQRV4CABFmkWbie2nrt9muaFZTkxavhr7Jfucz/Ln2s4hU28B0/sBO6VczPCl/GNoYd6wsuZ3ELWKuBe3iSAQa4g7M4jEM4jRt4g5+4lMEHEbc+KUED/xVOvY5iThXgg/gek+UMfq4CbstU8L7RmU/c3qxwUkc0TnN/CT9Ycn4djrenhB/H24j5iMXQX8TTUsCncD6T6daUtzyp8hNSV30uJfgWAUfje70AqMFF7FC6kGOy20rQPoKTBd1ii3EsbF9LCUpH1K62q1uWwr5RSvAyjHdb+rzqSZU38iB8npWMTZu+M96mzU5qfT6H98FYKTn0sRUONwv2hQqcNK+G2FSZsNeNRsX5CqwtF7CHfVzpcn6cJbmlfqsPSJXvRczDaarpZUmaf3JP6pAjsZZw3+jM9/FIffKOyTXpRnY9OJu4+ifgXOaljnghtedurA94HraZn8x/Q34DYaON8Fk9Z1IAAAAASUVORK5CYII=","type":"image/png","filename":"file.png","disposition":"inline","content_id":"png_content_id@test.mail"}],"headers":{"X-Special-Domain-Specific-Header":"SecretValue","One-more-custom-header":"CustomValue"},"category":"Module Test"}'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Scrub live-looking email addresses from the cassette.

The recorded payload now commits to, cc, bcc, and reply_to addresses under railsware.com. Even if these are synthetic mailboxes, keeping a real company domain in VCR fixtures is unnecessary exposure; please replace them with reserved test domains like example.com or example.invalid.

As per coding guidelines, spec/fixtures/vcr_cassettes/**/*.yml: Act as a data privacy officer. Carefully read all the vcr cassettes with recorded HTTP interactions and try to identify sensitive data that could potentially be recorded.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@spec/fixtures/vcr_cassettes/Mailtrap_ActionMailer_DeliveryMethod/_deliver_/converts_the_message_and_sends_via_API.yml`
at line 8, Replace any real-looking email addresses inside the VCR cassette
string payload (fields "to", "cc", "bcc", and "reply_to" and any headers) with
reserved test domains such as example.com or example.invalid; specifically
update the JSON string value (the long "string": '...') so entries like
"to":[{"email":"to_1@railsware.com",...}], "cc":[...], "bcc":[...], and
"reply_to":{"email":"reply-to@railsware.com"} are changed to use non-production
domains (e.g., "to_1@example.com", "reply-to@example.invalid") and ensure any
other email-like values in that same "string" are similarly sanitized while
preserving message structure and encoding.

@ryush00 ryush00 merged commit 7ff1068 into main Mar 8, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant