mailtrap 2.11.1 → 2.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b6606da8d73e2112b813b87000d3aaa63c5490cf2d046dedf59eb5a4f56fc619
4
- data.tar.gz: a7647dad5291d79758edd52e2b01c57e3e475d998a271ddcd5f6daf24455f59c
3
+ metadata.gz: 40fcde70d63616c345252736a68e3de8b1f0cfa7c1cf615cb0cace7e2158c752
4
+ data.tar.gz: 5e3ab5dd73034c6fc752f0d13b683e767d6f29f170c1f2aeed5fbffedc9bef1c
5
5
  SHA512:
6
- metadata.gz: e8bca46ba63dfa33175e89b2fcdaba9cce1701d904b6eee25a4808e57524b17dd7f97f483e6289c889fdb6006d35ced29c857beacdc1d2431f8c43a26d878161
7
- data.tar.gz: 7dbeaaf7198cc263e2ab8264113b0992836a2141745d96edd031f9ff33934649ab4b1cf5bf9a882016a63e243c77d129be61f8f9ab3957b8091019fdb90e2593
6
+ metadata.gz: b971a8cc52133ce0aed38ed202742fdb45e4be73256abe284e40a1d4ac94b729674cd4faea526397685f26d80fcd307669777941b29b1a28fcbd821adbf6beba
7
+ data.tar.gz: 00bc7f6c7db02b4d70f45070e250ad726b72150eb976dcf4476f72b58a44ad99d1f59a6ac89033cc5269d2a5f13987a10a8d1cd4d8d6dc0ed4d894e1134baade
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ ## [2.12.0] - 2026-07-24
2
+
3
+ ## What's Changed
4
+ * MT-22678: Add name search filter to contact lists listing by @Rabsztok in https://github.com/mailtrap/mailtrap-ruby/pull/116
5
+ * Add Inbound Email v2 API support by @mklocek in https://github.com/mailtrap/mailtrap-ruby/pull/117
6
+
7
+
8
+ **Full Changelog**: https://github.com/mailtrap/mailtrap-ruby/compare/v2.11.1...v2.12.0
9
+
1
10
  ## [2.11.1] - 2026-07-02
2
11
 
3
12
  ## What's Changed
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- mailtrap (2.11.1)
4
+ mailtrap (2.12.0)
5
5
  base64
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -187,6 +187,13 @@ Email Sandbox (Testing):
187
187
  - Sandbox Messages CRUD - [`sandbox_messages_api.rb`](examples/sandbox_messages_api.rb)
188
188
  - Sandbox Attachments API - [`sandbox_attachments_api.rb`](examples/sandbox_attachments_api.rb)
189
189
 
190
+ Inbound Email:
191
+
192
+ - Inbound Folders API – [`inbound_folders_api.rb`](examples/inbound_folders_api.rb)
193
+ - Inbound Inboxes API – [`inbound_inboxes_api.rb`](examples/inbound_inboxes_api.rb)
194
+ - Inbound Messages API (list, get, delete, reply, reply_all, forward) – [`inbound_messages_api.rb`](examples/inbound_messages_api.rb)
195
+ - Inbound Threads API – [`inbound_threads_api.rb`](examples/inbound_threads_api.rb)
196
+
190
197
  Contact management:
191
198
 
192
199
  - Contacts CRUD & Listing – [`contacts_api.rb`](examples/contacts_api.rb)
@@ -49,10 +49,14 @@ module Mailtrap
49
49
  end
50
50
 
51
51
  # Lists all contact lists for the account
52
+ # @param search [String] Filters contact lists by name (case-insensitive prefix match)
52
53
  # @return [Array<ContactList>] Array of contact list objects
53
54
  # @!macro api_errors
54
- def list
55
- base_list
55
+ def list(search: nil)
56
+ query_params = {}
57
+ query_params[:search] = search unless search.nil?
58
+
59
+ base_list(query_params)
56
60
  end
57
61
 
58
62
  private
@@ -6,6 +6,10 @@ module Mailtrap
6
6
  # @attr_reader message_id [String] Message UUID
7
7
  # @attr_reader status [String] delivered, not_delivered, enqueued, opted_out
8
8
  # @attr_reader subject [String, nil] Email subject
9
+ # @attr_reader rfc_message_id [String, nil] Value of the RFC 5322 Message-ID header
10
+ # @attr_reader in_reply_to [String, nil] Value of the RFC 5322 In-Reply-To header
11
+ # @attr_reader references [Array<String>] Values of the RFC 5322 References header
12
+ # @attr_reader thread_id [String, nil] ID of the inbound thread this message belongs to, if any
9
13
  # @attr_reader from [String] Sender address
10
14
  # @attr_reader to [String] Recipient address
11
15
  # @attr_reader sent_at [String] ISO 8601 timestamp
@@ -24,6 +28,10 @@ module Mailtrap
24
28
  :message_id,
25
29
  :status,
26
30
  :subject,
31
+ :rfc_message_id,
32
+ :in_reply_to,
33
+ :references,
34
+ :thread_id,
27
35
  :from,
28
36
  :to,
29
37
  :sent_at,
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mailtrap
4
+ # Data Transfer Object for an inbound message attachment
5
+ # @see https://docs.mailtrap.io/developers/inbound
6
+ # @attr_reader attachment_id [String] The attachment ID
7
+ # @attr_reader size [Integer, nil] The attachment size in bytes
8
+ # @attr_reader filename [String, nil] The attachment filename
9
+ # @attr_reader content_type [String, nil] The attachment MIME type
10
+ # @attr_reader content_disposition [String, nil] attachment or inline
11
+ # @attr_reader content_id [String, nil] The content ID for inline attachments
12
+ # @attr_reader download_url [String, nil] Signed URL to download the attachment (only when fetched by ID)
13
+ # @attr_reader download_url_expires_at [String, nil] When the download URL expires (only when fetched by ID)
14
+ # rubocop:disable Lint/StructNewOverride -- +size+ is an API field that shadows Struct#size
15
+ InboundAttachment = Struct.new(
16
+ :attachment_id,
17
+ :size,
18
+ :filename,
19
+ :content_type,
20
+ :content_disposition,
21
+ :content_id,
22
+ :download_url,
23
+ :download_url_expires_at,
24
+ keyword_init: true
25
+ )
26
+ # rubocop:enable Lint/StructNewOverride
27
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mailtrap
4
+ # Data Transfer Object for an inbound folder
5
+ # @see https://docs.mailtrap.io/developers/inbound
6
+ # @attr_reader id [Integer] The folder ID
7
+ # @attr_reader name [String] The folder name
8
+ InboundFolder = Struct.new(
9
+ :id,
10
+ :name,
11
+ keyword_init: true
12
+ )
13
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_api'
4
+ require_relative 'inbound_folder'
5
+
6
+ module Mailtrap
7
+ class InboundFoldersAPI
8
+ include BaseAPI
9
+
10
+ self.supported_options = %i[name]
11
+ self.response_class = InboundFolder
12
+
13
+ # Inbound is scoped to the token's account, so no account_id is required.
14
+ # @param client [Mailtrap::Client] The client instance
15
+ def initialize(client = Mailtrap::Client.new)
16
+ @client = client
17
+ end
18
+
19
+ # Lists all inbound folders in the account
20
+ # @return [Array<InboundFolder>] Array of folders
21
+ # @!macro api_errors
22
+ def list
23
+ base_list
24
+ end
25
+
26
+ # Retrieves a specific inbound folder
27
+ # @param folder_id [Integer] The folder ID
28
+ # @return [InboundFolder] Folder object
29
+ # @!macro api_errors
30
+ def get(folder_id)
31
+ base_get(folder_id)
32
+ end
33
+
34
+ # Creates a new inbound folder
35
+ # @param [Hash] options The parameters to create
36
+ # @option options [String] :name The folder name
37
+ # @return [InboundFolder] Created folder
38
+ # @!macro api_errors
39
+ # @raise [ArgumentError] If invalid options are provided
40
+ def create(options)
41
+ base_create(options)
42
+ end
43
+
44
+ # Updates an inbound folder
45
+ # @param folder_id [Integer] The folder ID
46
+ # @param [Hash] options The parameters to update
47
+ # @option options [String] :name The folder name
48
+ # @return [InboundFolder] Updated folder
49
+ # @!macro api_errors
50
+ # @raise [ArgumentError] If invalid options are provided
51
+ def update(folder_id, options)
52
+ base_update(folder_id, options)
53
+ end
54
+
55
+ # Deletes an inbound folder along with all of its inboxes
56
+ # @param folder_id [Integer] The folder ID
57
+ # @return nil
58
+ # @!macro api_errors
59
+ def delete(folder_id)
60
+ base_delete(folder_id)
61
+ end
62
+
63
+ private
64
+
65
+ def base_path
66
+ '/api/inbound/folders'
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mailtrap
4
+ # Data Transfer Object for an inbound inbox
5
+ # @see https://docs.mailtrap.io/developers/inbound
6
+ # @attr_reader id [Integer] The inbox ID
7
+ # @attr_reader name [String] The inbox name
8
+ # @attr_reader address [String] The inbox's inbound address
9
+ # @attr_reader domain_id [Integer] The sending domain the inbox is attached to
10
+ InboundInbox = Struct.new(
11
+ :id,
12
+ :name,
13
+ :address,
14
+ :domain_id,
15
+ keyword_init: true
16
+ )
17
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_api'
4
+ require_relative 'inbound_inbox'
5
+
6
+ module Mailtrap
7
+ class InboundInboxesAPI
8
+ include BaseAPI
9
+
10
+ self.response_class = InboundInbox
11
+
12
+ CREATE_OPTIONS = %i[name domain_id].freeze
13
+ UPDATE_OPTIONS = %i[name].freeze
14
+
15
+ # Inbound is scoped to the token's account, so no account_id is required.
16
+ # @param client [Mailtrap::Client] The client instance
17
+ def initialize(client = Mailtrap::Client.new)
18
+ @client = client
19
+ end
20
+
21
+ # Lists all inboxes in a folder
22
+ # @param folder_id [Integer] The folder ID
23
+ # @return [Array<InboundInbox>] Array of inboxes
24
+ # @!macro api_errors
25
+ def list(folder_id)
26
+ client.get(inboxes_path(folder_id)).map { |item| handle_response(item) }
27
+ end
28
+
29
+ # Retrieves a specific inbox
30
+ # @param folder_id [Integer] The folder ID
31
+ # @param inbox_id [Integer] The inbox ID
32
+ # @return [InboundInbox] Inbox object
33
+ # @!macro api_errors
34
+ def get(folder_id, inbox_id)
35
+ handle_response(client.get("#{inboxes_path(folder_id)}/#{inbox_id}"))
36
+ end
37
+
38
+ # Creates a new inbox in a folder
39
+ # @param folder_id [Integer] The folder ID
40
+ # @param [Hash] options The parameters to create
41
+ # @option options [String] :name The inbox name
42
+ # @option options [Integer] :domain_id Attach to a custom domain; omit for a Mailtrap-hosted inbox
43
+ # @return [InboundInbox] Created inbox
44
+ # @!macro api_errors
45
+ # @raise [ArgumentError] If invalid options are provided
46
+ def create(folder_id, options)
47
+ validate_options!(options, CREATE_OPTIONS)
48
+ handle_response(client.post(inboxes_path(folder_id), options))
49
+ end
50
+
51
+ # Updates an inbox
52
+ # @param folder_id [Integer] The folder ID
53
+ # @param inbox_id [Integer] The inbox ID
54
+ # @param [Hash] options The parameters to update
55
+ # @option options [String] :name The inbox name
56
+ # @return [InboundInbox] Updated inbox
57
+ # @!macro api_errors
58
+ # @raise [ArgumentError] If invalid options are provided
59
+ def update(folder_id, inbox_id, options)
60
+ validate_options!(options, UPDATE_OPTIONS)
61
+ handle_response(client.patch("#{inboxes_path(folder_id)}/#{inbox_id}", options))
62
+ end
63
+
64
+ # Deletes an inbox
65
+ # @param folder_id [Integer] The folder ID
66
+ # @param inbox_id [Integer] The inbox ID
67
+ # @return nil
68
+ # @!macro api_errors
69
+ def delete(folder_id, inbox_id)
70
+ client.delete("#{inboxes_path(folder_id)}/#{inbox_id}")
71
+ end
72
+
73
+ private
74
+
75
+ def inboxes_path(folder_id)
76
+ "/api/inbound/folders/#{folder_id}/inboxes"
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mailtrap
4
+ # Data Transfer Object for an inbound message (summary in list, full details when fetched by ID)
5
+ # @see https://docs.mailtrap.io/developers/inbound
6
+ # @attr_reader id [String] The Mailtrap object ID (not the RFC Message-ID header)
7
+ # @attr_reader inbox_id [Integer] The inbox the message was received in
8
+ # @attr_reader from [String, nil] Sender address
9
+ # @attr_reader to [Array<String>] Recipient addresses
10
+ # @attr_reader cc [Array<String>] Cc addresses
11
+ # @attr_reader bcc [Array<String>] Bcc addresses
12
+ # @attr_reader reply_to [String, nil] Reply-To address
13
+ # @attr_reader subject [String, nil] Email subject
14
+ # @attr_reader rfc_message_id [String, nil] Value of the RFC 5322 Message-ID header
15
+ # @attr_reader in_reply_to [String, nil] Value of the RFC 5322 In-Reply-To header
16
+ # @attr_reader references [Array<String>] Values of the RFC 5322 References header
17
+ # @attr_reader headers [Hash, nil] Raw message headers
18
+ # @attr_reader size [Integer, nil] Total message size in bytes
19
+ # @attr_reader html_size [Integer, nil] HTML body size in bytes
20
+ # @attr_reader text_size [Integer, nil] Text body size in bytes
21
+ # @attr_reader received_at [String] ISO 8601 timestamp when the message was received
22
+ # @attr_reader thread_id [String, nil] ID of the thread this message belongs to, if any
23
+ # @attr_reader attachments [Array<InboundAttachment>] The message attachments
24
+ # @attr_reader raw_message_url [String, nil] Signed URL to download raw .eml (only when fetched by ID)
25
+ # @attr_reader raw_message_expires_at [String, nil] When the raw message URL expires (only when fetched by ID)
26
+ # @attr_reader html_body [String, nil] Decoded HTML body (only when fetched by ID)
27
+ # @attr_reader text_body [String, nil] Decoded text body (only when fetched by ID)
28
+ # rubocop:disable Lint/StructNewOverride -- +size+ is an API field that shadows Struct#size
29
+ InboundMessage = Struct.new(
30
+ :id,
31
+ :inbox_id,
32
+ :from,
33
+ :to,
34
+ :cc,
35
+ :bcc,
36
+ :reply_to,
37
+ :subject,
38
+ :rfc_message_id,
39
+ :in_reply_to,
40
+ :references,
41
+ :headers,
42
+ :size,
43
+ :html_size,
44
+ :text_size,
45
+ :received_at,
46
+ :thread_id,
47
+ :attachments,
48
+ :raw_message_url,
49
+ :raw_message_expires_at,
50
+ :html_body,
51
+ :text_body,
52
+ keyword_init: true
53
+ )
54
+ # rubocop:enable Lint/StructNewOverride
55
+ end
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_api'
4
+ require_relative 'inbound_message'
5
+ require_relative 'inbound_attachment'
6
+ require_relative 'inbound_messages_list_response'
7
+ require_relative 'inbound_send_result'
8
+
9
+ module Mailtrap
10
+ class InboundMessagesAPI
11
+ include BaseAPI
12
+
13
+ self.response_class = InboundMessage
14
+
15
+ SEND_OPTIONS = %i[from to cc bcc reply_to text html category attachments headers custom_variables].freeze
16
+
17
+ # Inbound is scoped to the token's account, so no account_id is required.
18
+ # @param client [Mailtrap::Client] The client instance
19
+ def initialize(client = Mailtrap::Client.new)
20
+ @client = client
21
+ end
22
+
23
+ # Lists messages in an inbox (cursor-paginated)
24
+ # @param inbox_id [Integer] The inbox ID
25
+ # @param last_id [String, nil] Cursor from the previous response's +last_id+ for the next page
26
+ # @return [InboundMessagesListResponse] data, total_count, and last_id
27
+ # @!macro api_errors
28
+ def list(inbox_id, last_id: nil)
29
+ query_params = last_id ? { last_id: } : {}
30
+ response = client.get(messages_path(inbox_id), query_params)
31
+
32
+ InboundMessagesListResponse.new(
33
+ data: Array(response[:data]).map { |item| build_message(item) },
34
+ total_count: response[:total_count],
35
+ last_id: response[:last_id]
36
+ )
37
+ end
38
+
39
+ # Fetches a single message with its full body and attachment download URLs
40
+ # @param inbox_id [Integer] The inbox ID
41
+ # @param message_id [String] The message ID
42
+ # @return [InboundMessage] Message details
43
+ # @!macro api_errors
44
+ def get(inbox_id, message_id)
45
+ build_message(client.get("#{messages_path(inbox_id)}/#{message_id}"))
46
+ end
47
+
48
+ # Deletes a message
49
+ # @param inbox_id [Integer] The inbox ID
50
+ # @param message_id [String] The message ID
51
+ # @return nil
52
+ # @!macro api_errors
53
+ def delete(inbox_id, message_id)
54
+ client.delete("#{messages_path(inbox_id)}/#{message_id}")
55
+ end
56
+
57
+ # Replies to a message (sends to the original sender)
58
+ # @param inbox_id [Integer] The inbox ID
59
+ # @param message_id [String] The message ID
60
+ # @param [Hash] options The send parameters (see {SEND_OPTIONS})
61
+ # @return [InboundSendResult] The sent message IDs
62
+ # @!macro api_errors
63
+ # @raise [ArgumentError] If invalid options are provided
64
+ def reply(inbox_id, message_id, options)
65
+ send_action(inbox_id, message_id, 'reply', options)
66
+ end
67
+
68
+ # Replies to a message and copies the original's other recipients
69
+ # @param (see #reply)
70
+ # @return [InboundSendResult] The sent message IDs
71
+ # @!macro api_errors
72
+ # @raise [ArgumentError] If invalid options are provided
73
+ def reply_all(inbox_id, message_id, options)
74
+ send_action(inbox_id, message_id, 'reply_all', options)
75
+ end
76
+
77
+ # Forwards a message to new recipients
78
+ # @param (see #reply)
79
+ # @return [InboundSendResult] The sent message IDs
80
+ # @!macro api_errors
81
+ # @raise [ArgumentError] If invalid options are provided, or if no +to+ recipient is given
82
+ def forward(inbox_id, message_id, options)
83
+ raise ArgumentError, 'to is required for forward' if Array(options[:to]).empty?
84
+
85
+ send_action(inbox_id, message_id, 'forward', options)
86
+ end
87
+
88
+ private
89
+
90
+ def messages_path(inbox_id)
91
+ "/api/inbound/inboxes/#{inbox_id}/messages"
92
+ end
93
+
94
+ def send_action(inbox_id, message_id, action, options)
95
+ validate_options!(options, SEND_OPTIONS)
96
+ response = client.post("#{messages_path(inbox_id)}/#{message_id}/#{action}", options)
97
+
98
+ InboundSendResult.new(message_ids: response[:message_ids])
99
+ end
100
+
101
+ def build_message(hash)
102
+ attrs = hash.slice(*InboundMessage.members)
103
+ attrs[:attachments] = build_attachments(attrs[:attachments]) if attrs[:attachments]
104
+
105
+ InboundMessage.new(**attrs)
106
+ end
107
+
108
+ def build_attachments(attachments)
109
+ Array(attachments).map do |attachment|
110
+ InboundAttachment.new(**attachment.slice(*InboundAttachment.members))
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mailtrap
4
+ # Data Transfer Object for a paginated list of inbound messages
5
+ # @see https://docs.mailtrap.io/developers/inbound
6
+ # @attr_reader data [Array<InboundMessage>] The messages on this page
7
+ # @attr_reader total_count [Integer] Total number of messages in the inbox
8
+ # @attr_reader last_id [String, nil] Cursor for the next page, or nil if this is the last page
9
+ InboundMessagesListResponse = Struct.new(
10
+ :data,
11
+ :total_count,
12
+ :last_id,
13
+ keyword_init: true
14
+ )
15
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mailtrap
4
+ # Data Transfer Object for the result of a reply, reply-all, or forward.
5
+ # @see https://docs.mailtrap.io/developers/inbound
6
+ # @attr_reader message_ids [Array<String>] UUIDs of the sent messages, one per recipient
7
+ InboundSendResult = Struct.new(
8
+ :message_ids,
9
+ keyword_init: true
10
+ )
11
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mailtrap
4
+ # Data Transfer Object for an inbound thread (summary in list, with embedded messages when fetched by ID)
5
+ # @see https://docs.mailtrap.io/developers/inbound
6
+ # @attr_reader id [String] The thread ID
7
+ # @attr_reader subject [String, nil] The thread subject
8
+ # @attr_reader message_count [Integer] Number of messages in the thread
9
+ # @attr_reader size [Integer] Total size of the thread in bytes
10
+ # @attr_reader first_message_at [String] ISO 8601 timestamp of the first message
11
+ # @attr_reader last_received_at [String, nil] ISO 8601 timestamp of the last received message
12
+ # @attr_reader last_sent_at [String, nil] ISO 8601 timestamp of the last sent message
13
+ # @attr_reader last_activity_at [String] ISO 8601 timestamp of the last activity
14
+ # @attr_reader last_message_id [String, nil] ID of the most recent message
15
+ # @attr_reader senders [Array<String>] Distinct sender addresses in the thread
16
+ # @attr_reader recipients [Array<String>] Distinct recipient addresses in the thread
17
+ # @attr_reader attachments [Array<InboundAttachment>] Attachments across the thread
18
+ # @attr_reader messages [Array<InboundThreadMessage>, nil] The thread's messages (only when fetched by ID)
19
+ # rubocop:disable Lint/StructNewOverride -- +size+ is an API field that shadows Struct#size
20
+ InboundThread = Struct.new(
21
+ :id,
22
+ :subject,
23
+ :message_count,
24
+ :size,
25
+ :first_message_at,
26
+ :last_received_at,
27
+ :last_sent_at,
28
+ :last_activity_at,
29
+ :last_message_id,
30
+ :senders,
31
+ :recipients,
32
+ :attachments,
33
+ :messages,
34
+ keyword_init: true
35
+ )
36
+ # rubocop:enable Lint/StructNewOverride
37
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mailtrap
4
+ # Data Transfer Object for a message inside an inbound thread.
5
+ # Only +visibility_status+ and +direction+ are always present; +placeholder+ entries omit the rest,
6
+ # and the delivery lifecycle fields are only set on available outbound messages.
7
+ # @see https://docs.mailtrap.io/developers/inbound
8
+ # @attr_reader visibility_status [String] available or placeholder
9
+ # @attr_reader direction [String] inbound or outbound
10
+ # @attr_reader id [String, nil] The message ID
11
+ # @attr_reader message_group_id [String, nil] Groups messages sent together as one logical send
12
+ # @attr_reader subject [String, nil] Email subject
13
+ # @attr_reader rfc_message_id [String, nil] Value of the RFC 5322 Message-ID header
14
+ # @attr_reader in_reply_to [String, nil] Value of the RFC 5322 In-Reply-To header
15
+ # @attr_reader references [Array<String>, nil] Values of the RFC 5322 References header
16
+ # @attr_reader from [String, nil] Sender address
17
+ # @attr_reader to [Array<String>, nil] Recipient addresses
18
+ # @attr_reader cc [Array<String>, nil] Cc addresses
19
+ # @attr_reader bcc [Array<String>, nil] Bcc addresses
20
+ # @attr_reader reply_to [String, nil] Reply-To address
21
+ # @attr_reader created_at [String, nil] ISO 8601 timestamp
22
+ # @attr_reader email_size [Integer, nil] Message size in bytes
23
+ # @attr_reader text_body [String, nil] Decoded text body
24
+ # @attr_reader html_body [String, nil] Decoded HTML body
25
+ # @attr_reader attachments [Array<InboundAttachment>, nil] The message attachments
26
+ # @attr_reader delivery_status [String, nil] Delivery status (outbound messages only)
27
+ # @attr_reader delivered_at [String, nil] Delivery timestamp (outbound messages only)
28
+ # @attr_reader bounced_at [String, nil] Bounce timestamp (outbound messages only)
29
+ InboundThreadMessage = Struct.new(
30
+ :visibility_status,
31
+ :direction,
32
+ :id,
33
+ :message_group_id,
34
+ :subject,
35
+ :rfc_message_id,
36
+ :in_reply_to,
37
+ :references,
38
+ :from,
39
+ :to,
40
+ :cc,
41
+ :bcc,
42
+ :reply_to,
43
+ :created_at,
44
+ :email_size,
45
+ :text_body,
46
+ :html_body,
47
+ :attachments,
48
+ :delivery_status,
49
+ :delivered_at,
50
+ :bounced_at,
51
+ keyword_init: true
52
+ )
53
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_api'
4
+ require_relative 'inbound_thread'
5
+ require_relative 'inbound_thread_message'
6
+ require_relative 'inbound_attachment'
7
+ require_relative 'inbound_threads_list_response'
8
+
9
+ module Mailtrap
10
+ class InboundThreadsAPI
11
+ include BaseAPI
12
+
13
+ self.response_class = InboundThread
14
+
15
+ # Inbound is scoped to the token's account, so no account_id is required.
16
+ # @param client [Mailtrap::Client] The client instance
17
+ def initialize(client = Mailtrap::Client.new)
18
+ @client = client
19
+ end
20
+
21
+ # Lists threads in an inbox (cursor-paginated)
22
+ # @param inbox_id [Integer] The inbox ID
23
+ # @param last_id [String, nil] Cursor from the previous response's +last_id+ for the next page
24
+ # @return [InboundThreadsListResponse] data, total_count, and last_id
25
+ # @!macro api_errors
26
+ def list(inbox_id, last_id: nil)
27
+ query_params = last_id ? { last_id: } : {}
28
+ response = client.get(threads_path(inbox_id), query_params)
29
+
30
+ InboundThreadsListResponse.new(
31
+ data: Array(response[:data]).map { |item| build_thread(item) },
32
+ total_count: response[:total_count],
33
+ last_id: response[:last_id]
34
+ )
35
+ end
36
+
37
+ # Fetches a single thread with its messages embedded (oldest first)
38
+ # @param inbox_id [Integer] The inbox ID
39
+ # @param thread_id [String] The thread ID
40
+ # @return [InboundThread] Thread with messages
41
+ # @!macro api_errors
42
+ def get(inbox_id, thread_id)
43
+ build_thread(client.get("#{threads_path(inbox_id)}/#{thread_id}"))
44
+ end
45
+
46
+ # Deletes a thread
47
+ # @param inbox_id [Integer] The inbox ID
48
+ # @param thread_id [String] The thread ID
49
+ # @return nil
50
+ # @!macro api_errors
51
+ def delete(inbox_id, thread_id)
52
+ client.delete("#{threads_path(inbox_id)}/#{thread_id}")
53
+ end
54
+
55
+ private
56
+
57
+ def threads_path(inbox_id)
58
+ "/api/inbound/inboxes/#{inbox_id}/threads"
59
+ end
60
+
61
+ def build_thread(hash)
62
+ attrs = hash.slice(*InboundThread.members)
63
+ attrs[:attachments] = build_attachments(attrs[:attachments]) if attrs[:attachments]
64
+ attrs[:messages] = build_messages(attrs[:messages]) if attrs[:messages]
65
+
66
+ InboundThread.new(**attrs)
67
+ end
68
+
69
+ def build_messages(messages)
70
+ Array(messages).map do |message|
71
+ attrs = message.slice(*InboundThreadMessage.members)
72
+ attrs[:attachments] = build_attachments(attrs[:attachments]) if attrs[:attachments]
73
+
74
+ InboundThreadMessage.new(**attrs)
75
+ end
76
+ end
77
+
78
+ def build_attachments(attachments)
79
+ Array(attachments).map do |attachment|
80
+ InboundAttachment.new(**attachment.slice(*InboundAttachment.members))
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mailtrap
4
+ # Data Transfer Object for a paginated list of inbound threads
5
+ # @see https://docs.mailtrap.io/developers/inbound
6
+ # @attr_reader data [Array<InboundThread>] The threads on this page
7
+ # @attr_reader total_count [Integer] Total number of threads in the inbox
8
+ # @attr_reader last_id [String, nil] Cursor for the next page, or nil if this is the last page
9
+ InboundThreadsListResponse = Struct.new(
10
+ :data,
11
+ :total_count,
12
+ :last_id,
13
+ keyword_init: true
14
+ )
15
+ end
@@ -17,6 +17,8 @@ module Mailtrap
17
17
  # @attr_reader health_alerts_enabled [Boolean] Whether health alerts are enabled
18
18
  # @attr_reader critical_alerts_enabled [Boolean] Whether critical alerts are enabled
19
19
  # @attr_reader alert_recipient_email [String, nil] The email address for alert recipients
20
+ # @attr_reader inbound_enabled [Boolean] Whether inbound email is enabled for this domain
21
+ # @attr_reader inbound_verified [Boolean] Whether the domain's inbound MX records are verified
20
22
  # @attr_reader permissions [Hash] The permissions for the sending domain
21
23
  #
22
24
  SendingDomain = Struct.new(
@@ -34,6 +36,8 @@ module Mailtrap
34
36
  :health_alerts_enabled,
35
37
  :critical_alerts_enabled,
36
38
  :alert_recipient_email,
39
+ :inbound_enabled,
40
+ :inbound_verified,
37
41
  :permissions,
38
42
  :created_at,
39
43
  :updated_at,
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mailtrap
4
- VERSION = '2.11.1'
4
+ VERSION = '2.12.0'
5
5
  end
data/lib/mailtrap.rb CHANGED
@@ -28,6 +28,10 @@ require_relative 'mailtrap/sandbox_attachments_api'
28
28
  require_relative 'mailtrap/stats_api'
29
29
  require_relative 'mailtrap/webhooks_api'
30
30
  require_relative 'mailtrap/webhooks'
31
+ require_relative 'mailtrap/inbound_folders_api'
32
+ require_relative 'mailtrap/inbound_inboxes_api'
33
+ require_relative 'mailtrap/inbound_messages_api'
34
+ require_relative 'mailtrap/inbound_threads_api'
31
35
 
32
36
  module Mailtrap
33
37
  # @!macro api_errors
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mailtrap
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.11.1
4
+ version: 2.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Railsware Products Studio LLC
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-07-02 00:00:00.000000000 Z
11
+ date: 2026-07-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: base64
@@ -80,6 +80,19 @@ files:
80
80
  - lib/mailtrap/email_template.rb
81
81
  - lib/mailtrap/email_templates_api.rb
82
82
  - lib/mailtrap/errors.rb
83
+ - lib/mailtrap/inbound_attachment.rb
84
+ - lib/mailtrap/inbound_folder.rb
85
+ - lib/mailtrap/inbound_folders_api.rb
86
+ - lib/mailtrap/inbound_inbox.rb
87
+ - lib/mailtrap/inbound_inboxes_api.rb
88
+ - lib/mailtrap/inbound_message.rb
89
+ - lib/mailtrap/inbound_messages_api.rb
90
+ - lib/mailtrap/inbound_messages_list_response.rb
91
+ - lib/mailtrap/inbound_send_result.rb
92
+ - lib/mailtrap/inbound_thread.rb
93
+ - lib/mailtrap/inbound_thread_message.rb
94
+ - lib/mailtrap/inbound_threads_api.rb
95
+ - lib/mailtrap/inbound_threads_list_response.rb
83
96
  - lib/mailtrap/inbox.rb
84
97
  - lib/mailtrap/inboxes_api.rb
85
98
  - lib/mailtrap/mail.rb