Add Inbound Email v2 API support#117
Conversation
EmailLogMessage gains rfc_message_id, in_reply_to, references, and thread_id. SendingDomain gains inbound_enabled and inbound_verified. Specs and VCR cassettes for both endpoints updated to cover the new fields. Cassette bodies were hand-edited rather than re-recorded, to avoid churning live resources and to keep the curated email-log fixture stable.
Struct DTOs for folders, inboxes, messages (with typed attachments), threads (with typed thread messages), the paginated list responses, and the reply/forward send result. Matches the OpenAPI spec.
InboundFoldersAPI (CRUD), InboundInboxesAPI (folder-scoped CRUD), InboundMessagesAPI (list/get/delete + reply/reply_all/forward) and InboundThreadsAPI (list/get/delete), wired into lib/mailtrap.rb. Inbound is token-scoped, so these override initialize to take just a client (no account_id). Nested attachments and thread messages are built into typed structs, mirroring EmailLogsAPI's event handling.
Offline DTO specs for all inbound structs, and VCR-based API specs for folders, inboxes, messages and threads (happy paths plus ArgumentError and Mailtrap::Error cases). Cassettes to be recorded against the live API.
Cassettes recorded against the live API for folders, inboxes, messages and threads, with the spec let IDs pointed at real recorded resources. Response bodies anonymised: the sending domain is replaced with example.com and the live inbox addresses with non-real slugs; the public inbound-mailtrap.io domain and resource IDs are kept, consistent with the existing cassettes.
Per-resource example scripts for inbound folders, inboxes, messages (incl. reply/reply_all/forward) and threads, linked from a new Inbound Email section in the README.
📝 WalkthroughWalkthroughAdded inbound email support to the Ruby client through folder, inbox, message, and thread APIs. The change includes typed DTOs, CRUD and messaging operations, cursor pagination, attachment mapping, examples, compatibility fields, VCR fixtures, and RSpec coverage. ChangesInbound email functionality
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant InboundThreadsAPI
participant MailtrapAPI
Client->>InboundThreadsAPI: list or get inbox threads
InboundThreadsAPI->>MailtrapAPI: GET threads endpoint with optional last_id
MailtrapAPI-->>InboundThreadsAPI: thread payload with nested messages
InboundThreadsAPI-->>Client: InboundThreadsListResponse or InboundThread
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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: 5
🧹 Nitpick comments (1)
spec/mailtrap/inbound_thread_message_spec.rb (1)
16-25: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winExpand DTO tests to cover the complete public contracts.
spec/mailtrap/inbound_thread_message_spec.rb#L16-L25: assert RFC/threading headers, addresses, bodies, attachments, andbounced_at.spec/mailtrap/inbound_thread_spec.rb#L20-L32: assertlast_received_at,last_sent_at, andlast_message_id.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@spec/mailtrap/inbound_thread_message_spec.rb` around lines 16 - 25, Expand the DTO expectations in spec/mailtrap/inbound_thread_message_spec.rb lines 16-25 to cover RFC/threading headers, addresses, bodies, attachments, and bounced_at in addition to the existing attributes. Also update spec/mailtrap/inbound_thread_spec.rb lines 20-32 to assert last_received_at, last_sent_at, and last_message_id, using the fixture values established by each DTO.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@examples/inbound_messages_api.rb`:
- Around line 14-15: Update the message retrieval flow around messages.get to
check whether page.data contains a first message before accessing its id; handle
an empty inbox gracefully and only perform the remaining message operations when
a message is available.
In `@examples/inbound_threads_api.rb`:
- Around line 14-19: Guard the example calls to threads.get and threads.delete
by checking that page.data contains a first thread before dereferencing
page.data.first.id. Preserve the existing get/delete behavior when the page is
non-empty, and skip both operations for an empty page.
In
`@spec/fixtures/vcr_cassettes/Mailtrap_InboundInboxesAPI/_list/maps_response_data_to_InboundInbox_objects.yml`:
- Line 71: Replace the recorded `@inbound-mailtrap.io` addresses with reserved
synthetic/local addresses in both fixture entries:
spec/fixtures/vcr_cassettes/Mailtrap_InboundInboxesAPI/_list/maps_response_data_to_InboundInbox_objects.yml:71
and
spec/fixtures/vcr_cassettes/Mailtrap_InboundInboxesAPI/_update/maps_response_data_to_an_InboundInbox_object.yml:71.
Keep the fixture response structure and inbox fields unchanged.
In
`@spec/fixtures/vcr_cassettes/Mailtrap_InboundMessagesAPI/_get/maps_response_data_to_an_InboundMessage_with_attachments.yml`:
- Around line 73-80: Sanitize the cassette response data by replacing the S3
presigned raw_message_url and raw_message_expires_at with deterministic redacted
values, and replace opaque unsubscribe and open-tracking URLs in html_body and
text_body with fixed placeholders. Remove the exposed credentials, signatures,
tokens, and PII from repository history, and invalidate the existing capture if
it remains usable.
In
`@spec/fixtures/vcr_cassettes/Mailtrap_InboundThreadsAPI/_get/maps_response_data_to_an_InboundThread_with_messages.yml`:
- Around line 72-79: Across the three listed fixture files and their indicated
ranges, address the repeated tickets-1a2b3c4d@inbound-mailtrap.io identity:
either document and test that it is intentional shared test setup, or replace it
consistently in every affected VCR JSON body with a reserved synthetic mailbox
address, preserving the fixture data structure and references.
---
Nitpick comments:
In `@spec/mailtrap/inbound_thread_message_spec.rb`:
- Around line 16-25: Expand the DTO expectations in
spec/mailtrap/inbound_thread_message_spec.rb lines 16-25 to cover RFC/threading
headers, addresses, bodies, attachments, and bounced_at in addition to the
existing attributes. Also update spec/mailtrap/inbound_thread_spec.rb lines
20-32 to assert last_received_at, last_sent_at, and last_message_id, using the
fixture values established by each DTO.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 4ab09e27-0db0-4c1a-bd3e-24e1faa00513
📒 Files selected for processing (68)
README.mdexamples/inbound_folders_api.rbexamples/inbound_inboxes_api.rbexamples/inbound_messages_api.rbexamples/inbound_threads_api.rblib/mailtrap.rblib/mailtrap/email_log_message.rblib/mailtrap/inbound_attachment.rblib/mailtrap/inbound_folder.rblib/mailtrap/inbound_folders_api.rblib/mailtrap/inbound_inbox.rblib/mailtrap/inbound_inboxes_api.rblib/mailtrap/inbound_message.rblib/mailtrap/inbound_messages_api.rblib/mailtrap/inbound_messages_list_response.rblib/mailtrap/inbound_send_result.rblib/mailtrap/inbound_thread.rblib/mailtrap/inbound_thread_message.rblib/mailtrap/inbound_threads_api.rblib/mailtrap/inbound_threads_list_response.rblib/mailtrap/sending_domain.rbspec/fixtures/vcr_cassettes/Mailtrap_EmailLogsAPI/_get/maps_response_data_to_EmailLogMessage_with_events_and_raw_message_url.ymlspec/fixtures/vcr_cassettes/Mailtrap_EmailLogsAPI/_list/maps_response_data_to_EmailLogsListResponse_with_messages.ymlspec/fixtures/vcr_cassettes/Mailtrap_InboundFoldersAPI/_create/maps_response_data_to_an_InboundFolder_object.ymlspec/fixtures/vcr_cassettes/Mailtrap_InboundFoldersAPI/_delete/returns_nil.ymlspec/fixtures/vcr_cassettes/Mailtrap_InboundFoldersAPI/_delete/when_the_folder_does_not_exist/raises_an_error.ymlspec/fixtures/vcr_cassettes/Mailtrap_InboundFoldersAPI/_get/maps_response_data_to_an_InboundFolder_object.ymlspec/fixtures/vcr_cassettes/Mailtrap_InboundFoldersAPI/_get/when_the_folder_does_not_exist/raises_an_error.ymlspec/fixtures/vcr_cassettes/Mailtrap_InboundFoldersAPI/_list/maps_response_data_to_InboundFolder_objects.ymlspec/fixtures/vcr_cassettes/Mailtrap_InboundFoldersAPI/_update/maps_response_data_to_an_InboundFolder_object.ymlspec/fixtures/vcr_cassettes/Mailtrap_InboundInboxesAPI/_create/maps_response_data_to_an_InboundInbox_object.ymlspec/fixtures/vcr_cassettes/Mailtrap_InboundInboxesAPI/_delete/returns_nil.ymlspec/fixtures/vcr_cassettes/Mailtrap_InboundInboxesAPI/_delete/when_the_inbox_does_not_exist/raises_an_error.ymlspec/fixtures/vcr_cassettes/Mailtrap_InboundInboxesAPI/_get/maps_response_data_to_an_InboundInbox_object.ymlspec/fixtures/vcr_cassettes/Mailtrap_InboundInboxesAPI/_get/when_the_inbox_does_not_exist/raises_an_error.ymlspec/fixtures/vcr_cassettes/Mailtrap_InboundInboxesAPI/_list/maps_response_data_to_InboundInbox_objects.ymlspec/fixtures/vcr_cassettes/Mailtrap_InboundInboxesAPI/_update/maps_response_data_to_an_InboundInbox_object.ymlspec/fixtures/vcr_cassettes/Mailtrap_InboundMessagesAPI/_delete/returns_nil.ymlspec/fixtures/vcr_cassettes/Mailtrap_InboundMessagesAPI/_forward/maps_response_data_to_an_InboundSendResult.ymlspec/fixtures/vcr_cassettes/Mailtrap_InboundMessagesAPI/_get/maps_response_data_to_an_InboundMessage_with_attachments.ymlspec/fixtures/vcr_cassettes/Mailtrap_InboundMessagesAPI/_get/when_the_message_does_not_exist/raises_an_error.ymlspec/fixtures/vcr_cassettes/Mailtrap_InboundMessagesAPI/_list/maps_response_data_to_an_InboundMessagesListResponse.ymlspec/fixtures/vcr_cassettes/Mailtrap_InboundMessagesAPI/_list/with_pagination_cursor/passes_last_id_and_returns_a_page.ymlspec/fixtures/vcr_cassettes/Mailtrap_InboundMessagesAPI/_reply/maps_response_data_to_an_InboundSendResult.ymlspec/fixtures/vcr_cassettes/Mailtrap_InboundMessagesAPI/_reply_all/maps_response_data_to_an_InboundSendResult.ymlspec/fixtures/vcr_cassettes/Mailtrap_InboundThreadsAPI/_delete/returns_nil.ymlspec/fixtures/vcr_cassettes/Mailtrap_InboundThreadsAPI/_delete/when_the_thread_does_not_exist/raises_an_error.ymlspec/fixtures/vcr_cassettes/Mailtrap_InboundThreadsAPI/_get/maps_response_data_to_an_InboundThread_with_messages.ymlspec/fixtures/vcr_cassettes/Mailtrap_InboundThreadsAPI/_get/when_the_thread_does_not_exist/raises_an_error.ymlspec/fixtures/vcr_cassettes/Mailtrap_InboundThreadsAPI/_list/maps_response_data_to_an_InboundThreadsListResponse.ymlspec/fixtures/vcr_cassettes/Mailtrap_InboundThreadsAPI/_list/with_pagination_cursor/passes_last_id_and_returns_a_page.ymlspec/fixtures/vcr_cassettes/Mailtrap_SendingDomainsAPI/_create/maps_response_data_to_sending_domain_object.ymlspec/fixtures/vcr_cassettes/Mailtrap_SendingDomainsAPI/_get/maps_response_data_to_SendingDomain_object.ymlspec/mailtrap/email_logs_api_spec.rbspec/mailtrap/inbound_attachment_spec.rbspec/mailtrap/inbound_folder_spec.rbspec/mailtrap/inbound_folders_api_spec.rbspec/mailtrap/inbound_inbox_spec.rbspec/mailtrap/inbound_inboxes_api_spec.rbspec/mailtrap/inbound_message_spec.rbspec/mailtrap/inbound_messages_api_spec.rbspec/mailtrap/inbound_messages_list_response_spec.rbspec/mailtrap/inbound_send_result_spec.rbspec/mailtrap/inbound_thread_message_spec.rbspec/mailtrap/inbound_thread_spec.rbspec/mailtrap/inbound_threads_api_spec.rbspec/mailtrap/inbound_threads_list_response_spec.rbspec/mailtrap/sending_domains_api_spec.rb
| test 2026-07-24T05:58:20Z","headers":{"mime-version":"1.0","return-path":""},"size":4210,"html_size":968,"text_size":351,"received_at":"2026-07-24T05:58:21.528Z","rfc_message_id":"<ace7a270-8724-11f1-0040-f14113a7558c@example.com>","in_reply_to":null,"references":[],"thread_id":"1871574677878845504","attachments":[],"raw_message_url":"https://mailsend-us-inbound-mail-bodies.s3.amazonaws.com/raw/c3b/292/1871574677877796928/raw.eml?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIAWYSURJ3UHLCG6JQ7%2F20260724%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260724T060123Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEDUaCXVzLWVhc3QtMSJHMEUCIH9u%2BHOb4l%2B1ZFnNCLWzphITJt6I3taUKyf8nSVY4V8JAiEA4es2wKLun0kAbwWXIMleOdvbevn%2Bwzq%2FMent%2F02hcvUqggQI%2Fv%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FARAAGgw0NjUxMDc1MDQ4NzIiDBxJ01lkJNHlF%2Fn7airWA7vGXuAMz2QikJKrPvdt1cA%2F%2FvhrbmmZOqDUhsUc0mw9aFKe6ZwtnsxKbZABqlNIPX7DZsxvsXzyzu2icMGAHw%2F%2FHZPdtsy7zOd7F8jyU%2BVdvTU2TNVzpm%2FReJZQ3XZaZAwhBjWgxgPQS0Mf5VErdnZFb4M73V5mHOQR8qUmLByf2YKllmnDBd0l6rP6TLxJB2sUnqZBW0kjP%2Fw1H65sfiXtJgkL%2FiYtDLKoGHLrcACiGwSWWd1WEEQWNRUCHfVD5pTGPFxDhbpU9NWPBCrXEm7lhNCjQjw8GL6a7ZYJHFOxwLRm3OSSTsLg%2FMTH69oq3mEO8JPwk3hJEBWeTTtgSCpWhVz1stj2UHQeVbr0EQpOgyrPaZ%2BVybOL1zFsVXSRCNAstDi6II3BkOCPxWw6D89DLF3XPyLh6BQrwC%2BsNd6%2BpRqbsJD3MpFZaWzasTGvRho09r9FJx2HMinqjch3uQyYkIkjQ938q9c41OYrccqrvLpSGKjSFdbLKP8syMeZJzTA%2Bxh9Wmz0aBcl0BvQgFj%2BjFSQrZpCRirxzMHcpQi%2Bumc8bE4CW%2BHTI%2BqXNkIEO%2FpuIOEkLbZ8UO0FgKUnqbEtJOPTo9Hv13jhbuUW%2BokD4DMbUHVuMLjdi9MGOqUBJzvmV5%2FoGML5LYyb6ldBzYoIpt8aFoDBxxREfwePzvEbgOXaiBcQN372D6lkL1ocvWa3%2FEWyVOmu%2FpQ%2FAwcjkvOO7R9BMiMcmw%2Bn0ko7sRbi9Nd4UbUM7CtcvR5qGfUYw2kOleqhnKO2sMwqhCG3jawnBKjBCB4rqwxZa01ZuaUeggq%2FGTYqDFsAnBubAXNafUT%2FceS%2FlNQAWoV7s8B20hLtc%2BXR&X-Amz-SignedHeaders=host&X-Amz-Signature=37287b9020f3a3357197d518c874b2b0c9aa5b713e16b07e69d79f14ae43d78b","raw_message_expires_at":"2026-07-24T07:01:23.851Z","html_body":"<p>Hello | ||
| from the inbound test script.</p><table style=\"font-family:Helvetica,Arial,sans-serif;font-size:12px;color:#000;width:95%;margin:32px | ||
| auto 24px;border:none;border-top:1px solid #eee;\" cellspacing=\"20\" cellpadding=\"0\">\r\n <tr>\r\n <td | ||
| style=\"text-align:center;\">\r\n <a href=\"https://u3078320257.t.mailtrap.net/out/ntgNV6MS9IBzPmwVhf1_fKExno65VCmBSrdL4c5tlwH2CO9coPgYNBN3KERVdgaihvzBmS2k7E.ssfokaA1DxvdSzEJPRFJP9xyyzICbmf_vKcZxqeWCQRagJajz6iQpPCXv0W3YnCdg_mk2PeeTm_r1Oe5cT.Z3UKIou.V5wsdHbfhVJSfyZhXESOk_p5m4wUqrpFt9Hfj5fLrwi83tgWm0--k5ABeX5qcndWqpZZ--Oi0cYr28qmLNe0MqbS9i1A~~\" | ||
| style=\"font-weight:700;color:#000;\">Unsubscribe</a>\r\n </td>\r\n </tr>\r\n</table>\r\n<img | ||
| src=\"https://u3078320257.t.mailtrap.net/op/guTBjLEJorUAGJTKi1xOZn.ysPnvx93fOcnqfV5aLlTKKRtTF7Ov9ztc2x2u3BenuHpj1T46PSZP2d.rWDx3w4DuuQfp7Cr4s8joXgsu1BJVBCwhjkfu5h7tlQ5P1zjvu3BxQxSgQmNsniixpsb5mBW4nio.ZHZ4KvdMeAY~--aR0KP0qsZhMhvURM--6Xp0ANaGi1jyE3lCeKyi7w~~.gif\" | ||
| width=\"1\" height=\"1\" alt=\"\" />","text_body":"Hello from the inbound | ||
| test script.\r\n\r\nUnsubscribe: https://u3078320257.t.mailtrap.net/out/ntgNV6MS9IBzPmwVhf1_fKExno65VCmBSrdL4c5tlwH2CO9coPgYNBN3KERVdgaihvzBmS2k7E.ssfokaA1DxvdSzEJPRFJP9xyyzICbmf_vKcZxqeWCQRagJajz6iQpPCXv0W3YnCdg_mk2PeeTm_r1Oe5cT.Z3UKIou.V5wsdHbfhVJSfyZhXESOk_p5m4wUqrpFt9Hfj5fLrwi83tgWm0--k5ABeX5qcndWqpZZ--Oi0cYr28qmLNe0MqbS9i1A~~"}' |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Redact the signed URL and tracking tokens before committing this cassette.
The response records an S3 presigned URL containing X-Amz-Credential, X-Amz-Security-Token, and X-Amz-Signature, plus opaque unsubscribe/open-tracking URLs in the HTML and text bodies. Replace these with deterministic redacted values and scrub the exposed material from repository history; invalidate the capture if it is still usable. As per path instructions, VCR cassettes must not retain recorded PII or credentials.
🧰 Tools
🪛 Checkov (3.3.8)
[high] 73-74: AWS Access Key
(CKV_SECRET_2)
[high] 73-74: IBM Cloud IAM Key
(CKV_SECRET_7)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@spec/fixtures/vcr_cassettes/Mailtrap_InboundMessagesAPI/_get/maps_response_data_to_an_InboundMessage_with_attachments.yml`
around lines 73 - 80, Sanitize the cassette response data by replacing the S3
presigned raw_message_url and raw_message_expires_at with deterministic redacted
values, and replace opaque unsubscribe and open-tracking URLs in html_body and
text_body with fixed placeholders. Remove the exposed credentials, signatures,
tokens, and PII from repository history, and invalidate the existing capture if
it remains usable.
Sources: Path instructions, Linters/SAST tools
| string: '{"id":"1871574677878845504","subject":"Inbound test 2026-07-24T05:58:20Z","message_count":2,"size":936,"first_message_at":"2026-07-24T05:58:21.528Z","last_received_at":"2026-07-24T05:58:21.528Z","last_sent_at":"2026-07-24T06:01:47.114Z","last_activity_at":"2026-07-24T06:01:47.114Z","last_message_id":"1871574893450792960","senders":["tickets-1a2b3c4d@inbound-mailtrap.io"],"recipients":["Inbound | ||
| Tester <sender@example.com>"],"attachments":[],"messages":[{"visibility_status":"available","direction":"outbound","id":"23594a30-8725-11f1-0000-f1b5e753a178","message_group_id":null,"subject":"Re: | ||
| Inbound test 2026-07-24T05:58:20Z","rfc_message_id":"<23594a30-8725-11f1-0000-f1b5e753a178@inbound-mailtrap.io>","in_reply_to":"<ace7a270-8724-11f1-0040-f14113a7558c@example.com>","references":["<ace7a270-8724-11f1-0040-f14113a7558c@example.com>"],"from":"tickets-1a2b3c4d@inbound-mailtrap.io","to":["Inbound | ||
| Tester <sender@example.com>"],"cc":[],"bcc":[],"reply_to":"","created_at":"2026-07-24T06:01:40.178Z","email_size":470,"text_body":"Thanks | ||
| for reaching out.","html_body":null,"attachments":[],"delivery_status":"enqueued","delivered_at":null,"bounced_at":null},{"visibility_status":"available","direction":"outbound","id":"277b7ca0-8725-11f1-0000-f12f7dc93be2","message_group_id":null,"subject":"Re: | ||
| Inbound test 2026-07-24T05:58:20Z","rfc_message_id":"<277b7ca0-8725-11f1-0000-f12f7dc93be2@inbound-mailtrap.io>","in_reply_to":"<ace7a270-8724-11f1-0040-f14113a7558c@example.com>","references":["<ace7a270-8724-11f1-0040-f14113a7558c@example.com>"],"from":"tickets-1a2b3c4d@inbound-mailtrap.io","to":["Inbound | ||
| Tester <sender@example.com>"],"cc":[],"bcc":[],"reply_to":"","created_at":"2026-07-24T06:01:47.114Z","email_size":466,"text_body":"Looping | ||
| everyone in.","html_body":null,"attachments":[],"delivery_status":"enqueued","delivered_at":null,"bounced_at":null}]}' |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== referenced cassette snippets =="
for f in \
spec/fixtures/vcr_cassettes/Mailtrap_InboundThreadsAPI/_get/maps_response_data_to_an_InboundThread_with_messages.yml \
spec/fixtures/vcr_cassettes/Mailtrap_InboundThreadsAPI/_list/maps_response_data_to_an_InboundThreadsListResponse.yml \
spec/fixtures/vcr_cassettes/Mailtrap_InboundThreadsAPI/_list/with_pagination_cursor/passes_last_id_and_returns_a_page.yml
do
echo "--- $f ---"
sed -n '1,120p' "$f" | nl -ba
done
echo
echo "== search for the mailbox address =="
rg -n "tickets-1a2b3c4d@inbound-mailtrap\.io|inbound-mailtrap\.io|Inbound Tester|sender@example\.com" spec config . -g '!vendor/**' -g '!node_modules/**' -g '!dist/**' -g '!build/**' || true
echo
echo "== git status and relevant files count =="
git status --short
git ls-files 'spec/fixtures/vcr_cassettes/**.yml' '**/Mailtrap*' | head -200Repository: mailtrap/mailtrap-ruby
Length of output: 361
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== referenced cassette snippets =="
for f in \
spec/fixtures/vcr_cassettes/Mailtrap_InboundThreadsAPI/_get/maps_response_data_to_an_InboundThread_with_messages.yml \
spec/fixtures/vcr_cassettes/Mailtrap_InboundThreadsAPI/_list/maps_response_data_to_an_InboundThreads ListResponse.yml \
spec/fixtures/vcr_cassettes/Mailtrap_InboundThreadsAPI/_list/with_pagination_cursor/passes_last_id_and_returns_a_page.yml
do
if [ -f "$f" ]; then
echo "--- $f ---"
sed -n '1,120p' "$f"
else
echo "MISSING: $f"
fi
done
echo
echo "== exact mailbox address occurrences =="
rg -n "tickets-1a2b3c4d@inbound-mailtrap\.io|inbound-mailtrap\.io|Inbound Tester|sender@example\.com" . || true
echo
echo "== list referenced files =="
for f in \
spec/fixtures/vcr_cassettes/Mailtrap_InboundThreadsAPI/_get/maps_response_data_to_an_InboundThread_with_messages.yml \
spec/fixtures/vcr_cassettes/Mailtrap_InboundThreadsAPI/_list/maps_response_data_to_an_InboundThreadsListResponse.yml \
spec/fixtures/vcr_cassettes/Mailtrap_InboundThreadsAPI/_list/with_pagination_cursor/passes_last_id_and_returns_a_page.yml
do
[ -f "$f" ] && echo "FOUND: $f" || echo "MISSING: $f"
doneRepository: mailtrap/mailtrap-ruby
Length of output: 16106
Redact or verify the repeated mailbox identity across the thread fixtures.
tickets-1a2b3c4d@inbound-mailtrap.io is a non-obvious, shared mailbox address recorded in the VCR JSON bodies. If this is test setup, document/test against that identity; otherwise replace it with a reserved synthetic address across the affected response bodies.
spec/fixtures/vcr_cassettes/Mailtrap_InboundThreadsAPI/_get/maps_response_data_to_an_InboundThread_with_messages.ymlspec/fixtures/vcr_cassettes/Mailtrap_InboundThreadsAPI/_list/maps_response_data_to_an_InboundThreadsListResponse.ymlspec/fixtures/vcr_cassettes/Mailtrap_InboundThreadsAPI/_list/with_pagination_cursor/passes_last_id_and_returns_a_page.yml
📍 Affects 3 files
spec/fixtures/vcr_cassettes/Mailtrap_InboundThreadsAPI/_get/maps_response_data_to_an_InboundThread_with_messages.yml#L72-L79(this comment)spec/fixtures/vcr_cassettes/Mailtrap_InboundThreadsAPI/_list/maps_response_data_to_an_InboundThreadsListResponse.yml#L71-L72spec/fixtures/vcr_cassettes/Mailtrap_InboundThreadsAPI/_list/with_pagination_cursor/passes_last_id_and_returns_a_page.yml#L71-L72
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@spec/fixtures/vcr_cassettes/Mailtrap_InboundThreadsAPI/_get/maps_response_data_to_an_InboundThread_with_messages.yml`
around lines 72 - 79, Across the three listed fixture files and their indicated
ranges, address the repeated tickets-1a2b3c4d@inbound-mailtrap.io identity:
either document and test that it is intentional shared test setup, or replace it
consistently in every affected VCR JSON body with a reserved synthetic mailbox
address, preserving the fixture data structure and references.
Source: Path instructions
| # @attr_reader download_url [String, nil] Signed URL to download the attachment (only when fetched by ID) | ||
| # @attr_reader download_url_expires_at [String, nil] When the download URL expires (only when fetched by ID) | ||
| # rubocop:disable Lint/StructNewOverride -- +size+ is an API field that shadows Struct#size | ||
| InboundAttachment = Struct.new( |
There was a problem hiding this comment.
BTW i wonder if it would make more sense to use Data
... Data doesn't even have size :)
Motivation
Add SDK support for the Inbound Email v2 API, and surface the inbound-related additions on existing endpoints. Mirrors the OpenAPI spec.
Changes
account_idrequired):InboundFoldersAPI— list, get, create, update, deleteInboundInboxesAPI(folder-scoped) — list, get, create (hosted & custom-domain), update, deleteInboundMessagesAPI(inbox-scoped) — list (cursor-paginated), get, delete,reply,reply_all,forwardInboundThreadsAPI(inbox-scoped) — list (cursor-paginated), get, deleteEmailLogMessagegainsrfc_message_id,in_reply_to,references,thread_id.SendingDomaingainsinbound_enabled,inbound_verified.Split into reviewable commits: existing-endpoint fields, DTOs, API classes, specs, cassettes, examples + README.