resend 1.17.0 → 1.18.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: 532989766c9ed1e426d6f81567469fdb496dbd715aeef2ad650804b332650eee
4
- data.tar.gz: 3e3701c9eb920447371bdb60bf699e37640035e33f06412a41034b775b863249
3
+ metadata.gz: 0e024af320af434631fba03fac6574a554874e1a5c43193ed082427000eeaa13
4
+ data.tar.gz: b10c3fb1b88e7fbbad8eb7d7b040942696233ef6f4695c45331c9ab8d20de261
5
5
  SHA512:
6
- metadata.gz: cb417219f3df87158356c91eb40f03e81e6ea26cfe743fe9e8e6a51002e0d3caea44d62e4596daf134728e4dbb0402f747625550955ff4a624b4c107fa2e4fcd
7
- data.tar.gz: 85a5c55eb75099201eb8d21575f5b5929ebc6e7aa4e2fb3e909a8a48618dfda3d3f33fa00fc6cd1838d89fc58aee4f82aa09d71e450ae5f49290dc0dc1a4fc82
6
+ metadata.gz: 1e31ee422985b5a4c3aaee94adde13febd8027b3b44d84e147759190ab60a50b0d1c9c2c8b61842deead2989aef65198a3855ea4911b0ab832203cb118f7ce4e
7
+ data.tar.gz: 5f18787f17121aa4653f15a932385b70258894898d9a2fb3e2660f4024aed63531505be301e2433d18baa86e8127fe41e799e66a88f5daba3e292aa4f78eb0ad
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Resend
4
+ module Inboxes
5
+ # Inbox Agent api wrapper
6
+ module Agent
7
+ class << self
8
+ # Retrieve the agent settings for an inbox
9
+ #
10
+ # An inbox without a configured agent returns empty settings: `instructions` and `tone`
11
+ # are nil and `actions` is an empty array.
12
+ #
13
+ # @param params [Hash] the parameters
14
+ # @option params [String] :inbox_id the inbox ID or the inbox email address (required)
15
+ #
16
+ # https://resend.com/docs/api-reference/inboxes/get-agent
17
+ def get(params = {})
18
+ raise ArgumentError, "inbox_id is required" if params[:inbox_id].nil?
19
+
20
+ Resend::Request.new("#{Resend::Inboxes.path(params[:inbox_id])}/agent", {}, "get").perform
21
+ end
22
+
23
+ # Update the agent settings for an inbox
24
+ #
25
+ # The agent is created when the inbox has none. Omitted fields keep their current value.
26
+ # At least one of `instructions`, `tone`, or `actions` must be provided.
27
+ #
28
+ # @param params [Hash] the parameters
29
+ # @option params [String] :inbox_id the inbox ID or the inbox email address (required)
30
+ # @option params [String, nil] :instructions instructions the agent follows when it handles
31
+ # the threads of the inbox, max 4000 characters. Send nil to clear the instructions
32
+ # @option params [String, nil] :tone the tone the agent writes in. One of `concise_professional`,
33
+ # `concise_casual`, `expanded_professional`, or `expanded_casual`. Send nil to clear the tone
34
+ # @option params [Array<String>] :actions the actions the agent can take. Replaces the whole set.
35
+ # Duplicates are removed. Send an empty array to disable all actions. One or more of
36
+ # `draft_reply`, `forward_thread`, `add_labels`, `assign_thread`, `mark_as_spam`, `archive`,
37
+ # `move_to_trash`
38
+ #
39
+ # https://resend.com/docs/api-reference/inboxes/update-agent
40
+ def update(params = {})
41
+ raise ArgumentError, "inbox_id is required" if params[:inbox_id].nil?
42
+
43
+ path = "#{Resend::Inboxes.path(params[:inbox_id])}/agent"
44
+ Resend::Request.new(path, params.except(:inbox_id), "patch").perform
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,176 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Resend
4
+ module Inboxes
5
+ # Inbox Drafts api wrapper
6
+ module Drafts
7
+ class << self
8
+ # Retrieve a list of drafts, most recently updated first
9
+ #
10
+ # Returns the unsent drafts on the inbox. The `after` and `before` cursors take a draft ID from
11
+ # the current page. A cursor that is not an unsent draft on this inbox returns a 404.
12
+ #
13
+ # @param params [Hash] the parameters
14
+ # @option params [String] :inbox_id the inbox ID or the inbox email address (required)
15
+ # @option params [Integer] :limit the maximum number of results to return
16
+ # @option params [String] :after the cursor for pagination
17
+ # @option params [String] :before the cursor for pagination
18
+ #
19
+ # https://resend.com/docs/api-reference/inboxes/list-drafts
20
+ def list(params = {})
21
+ raise ArgumentError, "inbox_id is required" if params[:inbox_id].nil?
22
+
23
+ path = Resend::PaginationHelper.build_paginated_path(drafts_path(params), params.except(:inbox_id))
24
+ Resend::Request.new(path, {}, "get").perform
25
+ end
26
+
27
+ # Create a draft
28
+ #
29
+ # Creates an unsent draft on the inbox. Omit `thread_id` and `reply_to_email_id` for a draft
30
+ # that starts a new thread. Pass both together for a reply draft in an existing thread. A reply
31
+ # draft without `to` is addressed to the sender of the email it replies to, or to its Reply-To
32
+ # when set. For an email the inbox sent, it defaults to that email's `to` recipients. Send
33
+ # `to: []` to leave it empty. At least one of `to`, `cc`, `bcc`, `subject`, `text`, `html` or
34
+ # `attachments` must be non-empty. The combined recipients of `to`, `cc` and `bcc` cannot exceed
35
+ # 50. Only one unsent reply draft can target an email, so a reply draft request for an email
36
+ # that already has one returns the ID of the existing draft. That request ignores every other
37
+ # field, except `attachments`, which replaces the attachments of the existing draft when sent.
38
+ # A reply draft created without `subject` stores an empty subject and gets no `Re:` prefix,
39
+ # so set one before you send it.
40
+ #
41
+ # @param params [Hash] the parameters
42
+ # @option params [String] :inbox_id the inbox ID or the inbox email address (required)
43
+ # @option params [String, Array<String>] :to the recipients. Each value can include a friendly
44
+ # name, for example `Ada Lovelace <ada@example.org>`
45
+ # @option params [String, Array<String>] :cc the CC recipients
46
+ # @option params [String, Array<String>] :bcc the BCC recipients
47
+ # @option params [String] :subject the subject, max 2000 characters
48
+ # @option params [String] :html the HTML body
49
+ # @option params [String] :text the plain text body
50
+ # @option params [String] :thread_id the thread ID to reply in. Must be sent with `reply_to_email_id`
51
+ # @option params [String] :reply_to_email_id the email ID to reply to. Must be sent with `thread_id`
52
+ # @option params [Array<Hash>] :attachments files to store on the draft. Each one needs `content`,
53
+ # `filename` and `content_type`. A `path` or `content_id` returns a 422. The files on a draft can
54
+ # total at most 25 MB. An empty file or a blocked file type returns a 422
55
+ # @param options [Hash] additional options for the request
56
+ # @option options [String] :idempotency_key a unique key for the request, so the draft is created
57
+ # only once. 1 to 256 characters. A retry with the same key within 24 hours replays the first
58
+ # successful (2xx) response, with the `idempotent-replayed: true` header. A failed request is
59
+ # not stored, so you can retry it with the same key. Reusing the key with a different body, or
60
+ # while the first request is still running, returns a 409
61
+ #
62
+ # @return [Hash] the draft `object` and `id`
63
+ #
64
+ # https://resend.com/docs/api-reference/inboxes/create-draft
65
+ def create(params = {}, options: {})
66
+ raise ArgumentError, "inbox_id is required" if params[:inbox_id].nil?
67
+
68
+ Resend::Request.new(drafts_path(params), params.except(:inbox_id), "post", options: options).perform
69
+ end
70
+
71
+ # Retrieve a single draft
72
+ #
73
+ # @param params [Hash] the parameters
74
+ # @option params [String] :inbox_id the inbox ID or the inbox email address (required)
75
+ # @option params [String] :draft_id the draft ID (required)
76
+ #
77
+ # https://resend.com/docs/api-reference/inboxes/get-draft
78
+ def get(params = {})
79
+ validate_draft!(params)
80
+
81
+ Resend::Request.new(draft_path(params), {}, "get").perform
82
+ end
83
+
84
+ # Update an existing draft
85
+ #
86
+ # Updates the content of an unsent draft. Omitted fields are left unchanged. Send at least one
87
+ # of `to`, `cc`, `bcc`, `subject`, `text`, `html` or `attachments`. Sending `attachments` replaces
88
+ # every attachment on the draft. A request that sets `text` or `html` replaces the whole body.
89
+ # The body part you omit from that request becomes nil. The merged draft must still contain at
90
+ # least one non-empty field, and its combined recipients cannot exceed 50. A draft that was
91
+ # already sent, or that changed during the request, returns a 409.
92
+ #
93
+ # @param params [Hash] the parameters
94
+ # @option params [String] :inbox_id the inbox ID or the inbox email address (required)
95
+ # @option params [String] :draft_id the draft ID (required)
96
+ # @option params [String, Array<String>, nil] :to the recipients. Pass nil to clear
97
+ # @option params [String, Array<String>, nil] :cc the CC recipients. Pass nil or [] to clear
98
+ # @option params [String, Array<String>, nil] :bcc the BCC recipients. Pass nil or [] to clear
99
+ # @option params [String, nil] :subject the subject, max 2000 characters. Pass nil to clear
100
+ # @option params [String, nil] :html the HTML body. Pass nil to clear
101
+ # @option params [String, nil] :text the plain text body. Pass nil to clear
102
+ # @option params [Array<Hash>] :attachments files to store on the draft, as in {create}. Sending
103
+ # the field replaces every attachment on the draft. Send [] or nil to remove them all
104
+ #
105
+ # https://resend.com/docs/api-reference/inboxes/update-draft
106
+ def update(params = {})
107
+ validate_draft!(params)
108
+
109
+ Resend::Request.new(draft_path(params), params.except(:inbox_id, :draft_id), "patch").perform
110
+ end
111
+
112
+ # Remove an existing draft
113
+ #
114
+ # Discards an unsent draft. A draft that was already sent, or that changed during the request,
115
+ # returns a 409.
116
+ #
117
+ # @param params [Hash] the parameters
118
+ # @option params [String] :inbox_id the inbox ID or the inbox email address (required)
119
+ # @option params [String] :draft_id the draft ID (required)
120
+ #
121
+ # https://resend.com/docs/api-reference/inboxes/delete-draft
122
+ def remove(params = {})
123
+ validate_draft!(params)
124
+
125
+ Resend::Request.new(draft_path(params), {}, "delete").perform
126
+ end
127
+
128
+ # Send a draft
129
+ #
130
+ # Sends the draft from the inbox address. A reply draft is sent in its thread. A draft without
131
+ # a thread starts a new thread. The draft must have at least one `to` recipient, a non-empty
132
+ # `subject`, and `html` or `text`, or the request returns a 422. A draft that was already sent
133
+ # returns a 409. The request body is optional and takes only `headers`.
134
+ #
135
+ # @param params [Hash] the parameters
136
+ # @option params [String] :inbox_id the inbox ID or the inbox email address (required)
137
+ # @option params [String] :draft_id the draft ID (required)
138
+ # @option params [Hash{String => String}] :headers custom headers to add to the email. The
139
+ # `In-Reply-To`, `References` and `Reply-To` headers are set by Resend and cannot be set here.
140
+ # Sending one of them, in any letter case, returns a 422. Header names cannot be empty, and
141
+ # names and values cannot contain line breaks or null characters, or the request returns a 422
142
+ # @param options [Hash] additional options for the request
143
+ # @option options [String] :idempotency_key a unique key for the request, so the draft is sent
144
+ # only once. 1 to 256 characters. A retry with the same key within 24 hours replays the first
145
+ # successful (2xx) response, with the `idempotent-replayed: true` header. A failed request is
146
+ # not stored, so you can retry it with the same key. Reusing the key with a different body, or
147
+ # while the first request is still running, returns a 409
148
+ #
149
+ # @return [Hash] the `id` of the sent email
150
+ #
151
+ # https://resend.com/docs/api-reference/inboxes/send-draft
152
+ def send(params = {}, options: {})
153
+ validate_draft!(params)
154
+
155
+ body = params.except(:inbox_id, :draft_id)
156
+ Resend::Request.new("#{draft_path(params)}/send", body, "post", options: options).perform
157
+ end
158
+
159
+ private
160
+
161
+ def validate_draft!(params)
162
+ raise ArgumentError, "inbox_id is required" if params[:inbox_id].nil?
163
+ raise ArgumentError, "draft_id is required" if params[:draft_id].nil?
164
+ end
165
+
166
+ def drafts_path(params)
167
+ "#{Resend::Inboxes.path(params[:inbox_id])}/drafts"
168
+ end
169
+
170
+ def draft_path(params)
171
+ "#{drafts_path(params)}/#{params[:draft_id]}"
172
+ end
173
+ end
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Resend
4
+ module Inboxes
5
+ # Inbox Labels api wrapper
6
+ #
7
+ # A label is a named, colored tag that belongs to one inbox.
8
+ module Labels
9
+ class << self
10
+ # Retrieve every label on the inbox, oldest first. The list is not paginated.
11
+ #
12
+ # @param params [Hash] the parameters
13
+ # @option params [String] :inbox_id the inbox ID or the inbox email address (required)
14
+ #
15
+ # https://resend.com/docs/api-reference/inboxes/list-labels
16
+ def list(params = {})
17
+ raise ArgumentError, "inbox_id is required" if params[:inbox_id].nil?
18
+
19
+ Resend::Request.new("#{Resend::Inboxes.path(params[:inbox_id])}/labels", {}, "get").perform
20
+ end
21
+
22
+ # Create a label on an inbox
23
+ #
24
+ # An inbox can have at most 100 labels. Label names are unique per inbox, compared without
25
+ # case. A duplicate name or a full inbox returns a 422 validation_error.
26
+ #
27
+ # @param params [Hash] the parameters
28
+ # @option params [String] :inbox_id the inbox ID or the inbox email address (required)
29
+ # @option params [String] :name the name of the label, max 64 characters (required)
30
+ # @option params [String] :color the color of the label, as a `#RRGGBB` hex color. It is stored
31
+ # in uppercase. When omitted, a random color from the dashboard palette is used
32
+ #
33
+ # @return [Hash] the created label `object` and `id`
34
+ #
35
+ # https://resend.com/docs/api-reference/inboxes/create-label
36
+ def create(params = {})
37
+ raise ArgumentError, "inbox_id is required" if params[:inbox_id].nil?
38
+
39
+ path = "#{Resend::Inboxes.path(params[:inbox_id])}/labels"
40
+ Resend::Request.new(path, params.except(:inbox_id), "post").perform
41
+ end
42
+
43
+ # Update an existing inbox label
44
+ #
45
+ # Renames or recolors a label. Omitted fields keep their current value. A new name must not
46
+ # match another label on the inbox, compared without case, or the request returns a 422
47
+ # validation_error.
48
+ #
49
+ # @param params [Hash] the parameters
50
+ # @option params [String] :inbox_id the inbox ID or the inbox email address (required)
51
+ # @option params [String] :label_id the label ID (required)
52
+ # @option params [String] :name a new name for the label, max 64 characters
53
+ # @option params [String] :color a new color for the label, as a `#RRGGBB` hex color.
54
+ # It is stored in uppercase
55
+ #
56
+ # https://resend.com/docs/api-reference/inboxes/update-label
57
+ def update(params = {})
58
+ raise ArgumentError, "inbox_id is required" if params[:inbox_id].nil?
59
+ raise ArgumentError, "label_id is required" if params[:label_id].nil?
60
+
61
+ path = "#{Resend::Inboxes.path(params[:inbox_id])}/labels/#{params[:label_id]}"
62
+ Resend::Request.new(path, params.except(:inbox_id, :label_id), "patch").perform
63
+ end
64
+
65
+ # Remove an existing inbox label
66
+ #
67
+ # Deletes the label and removes it from every thread that carries it.
68
+ #
69
+ # @param params [Hash] the parameters
70
+ # @option params [String] :inbox_id the inbox ID or the inbox email address (required)
71
+ # @option params [String] :label_id the label ID (required)
72
+ #
73
+ # https://resend.com/docs/api-reference/inboxes/delete-label
74
+ def remove(params = {})
75
+ raise ArgumentError, "inbox_id is required" if params[:inbox_id].nil?
76
+ raise ArgumentError, "label_id is required" if params[:label_id].nil?
77
+
78
+ path = "#{Resend::Inboxes.path(params[:inbox_id])}/labels/#{params[:label_id]}"
79
+ Resend::Request.new(path, {}, "delete").perform
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,163 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Resend
4
+ module Inboxes
5
+ module Threads
6
+ # Inbox Thread Emails api wrapper
7
+ module Emails
8
+ class << self
9
+ # Retrieve a list of thread emails, oldest first
10
+ #
11
+ # Pass the `id` of the last message as `after` to get the next, newer page. Pass the `id` of
12
+ # the first message as `before` to get the previous, older page. You cannot combine `after`
13
+ # and `before`. A cursor that is not a message of the thread returns a 404.
14
+ #
15
+ # @param params [Hash] the parameters
16
+ # @option params [String] :inbox_id the inbox ID or the inbox email address (required)
17
+ # @option params [String] :thread_id the thread ID (required)
18
+ # @option params [Integer] :limit the maximum number of results to return
19
+ # @option params [String] :after the cursor for pagination
20
+ # @option params [String] :before the cursor for pagination
21
+ #
22
+ # https://resend.com/docs/api-reference/inboxes/list-thread-emails
23
+ def list(params = {})
24
+ validate_thread!(params)
25
+
26
+ base_path = "#{Resend::Inboxes.path(params[:inbox_id])}/threads/#{params[:thread_id]}/emails"
27
+ path = Resend::PaginationHelper.build_paginated_path(base_path, params.except(:inbox_id, :thread_id))
28
+ Resend::Request.new(path, {}, "get").perform
29
+ end
30
+
31
+ # Retrieve a single thread email
32
+ #
33
+ # @param params [Hash] the parameters
34
+ # @option params [String] :inbox_id the inbox ID or the inbox email address (required)
35
+ # @option params [String] :thread_id the thread ID (required)
36
+ # @option params [String] :email_id the email ID, as returned in `data[].id` by {list} (required)
37
+ #
38
+ # https://resend.com/docs/api-reference/inboxes/get-thread-email
39
+ def get(params = {})
40
+ validate_email!(params)
41
+
42
+ Resend::Request.new(email_path(params), {}, "get").perform
43
+ end
44
+
45
+ # Reply to a thread email
46
+ #
47
+ # Sends a reply from the inbox address right away, with no stored draft. The `to` recipients
48
+ # come from the message you reply to. For a message the inbox received, the reply goes to its
49
+ # `Reply-To` addresses, or to its sender when it has no `Reply-To`. For a message the inbox
50
+ # sent, the reply goes to that message's `to` recipients. Set `reply_all` to also copy the
51
+ # other recipients of the message. At least one of `html` or `text` must contain more than
52
+ # whitespace.
53
+ #
54
+ # @param params [Hash] the parameters
55
+ # @option params [String] :inbox_id the inbox ID or the inbox email address (required)
56
+ # @option params [String] :thread_id the thread ID (required)
57
+ # @option params [String] :email_id the email ID of the message to reply to (required)
58
+ # @option params [String] :html the HTML body of the reply
59
+ # @option params [String] :text the plain-text body of the reply
60
+ # @option params [String] :subject the subject of the reply. When omitted, the thread subject
61
+ # is used, prefixed with `Re:` if it does not already start with it
62
+ # @option params [String, Array<String>] :cc CC recipients. Without `reply_all`, the reply
63
+ # copies only these addresses
64
+ # @option params [String, Array<String>] :bcc BCC recipients. BCC recipients of the original
65
+ # message are never copied
66
+ # @option params [Boolean] :reply_all reply to everyone on the original message. For a message the
67
+ # inbox received, the reply goes to its `Reply-To` addresses, or to its sender when it has none,
68
+ # and copies the other addresses of its `To` header and its `cc` recipients in `cc`. For a message
69
+ # the inbox sent, the reply goes to its `Reply-To` addresses when they are not the inbox address,
70
+ # otherwise to its `to` recipients, and copies its `cc` recipients. The inbox address is always
71
+ # excluded, and duplicates are removed. Defaults to false
72
+ # @option params [Array<Hash>] :attachments files to attach, as on {Resend::Emails.send}. Each one
73
+ # needs `content` or `path`. At most 25 MB of `content` in total. An empty file, a
74
+ # blocked file type, or a `path` that is not an `http` or `https` URL, or that points to
75
+ # `localhost`, returns a 422
76
+ # @option params [Hash{String => String}] :headers custom headers to add to the email. The
77
+ # `In-Reply-To`, `References` and `Reply-To` headers are set by Resend and cannot be set here.
78
+ # Sending one of them, in any letter case, returns a 422. Header names cannot be empty, and
79
+ # names and values cannot contain line breaks or null characters, or the request returns a 422
80
+ # @param options [Hash] additional options for the request
81
+ # @option options [String] :idempotency_key a unique key for the request, so the reply is sent
82
+ # only once. 1 to 256 characters. A retry with the same key within 24 hours replays the first
83
+ # successful (2xx) response, with the `idempotent-replayed: true` header. A failed request is
84
+ # not stored, so you can retry it with the same key. Reusing the key with a different body, or
85
+ # while the first request is still running, returns a 409
86
+ #
87
+ # @return [Hash] the `id` of the sent email
88
+ #
89
+ # https://resend.com/docs/api-reference/inboxes/reply-thread-email
90
+ def reply(params = {}, options: {})
91
+ validate_email!(params)
92
+
93
+ Resend::Request.new("#{email_path(params)}/reply", body(params), "post", options: options).perform
94
+ end
95
+
96
+ # Forward a thread email
97
+ #
98
+ # Forwards a message from the inbox address right away, with no stored draft. The original
99
+ # message is quoted under a forwarded-message banner, below the optional `html` or `text`
100
+ # note. The attachments of the original message are sent with the forward, together with any
101
+ # `attachments` you add. The request fails when they exceed 25 MB of `content` in total. An
102
+ # original attachment that was sent from a URL (`path`) cannot be forwarded, and the request
103
+ # returns a 422.
104
+ #
105
+ # @param params [Hash] the parameters
106
+ # @option params [String] :inbox_id the inbox ID or the inbox email address (required)
107
+ # @option params [String] :thread_id the thread ID (required)
108
+ # @option params [String] :email_id the email ID of the message to forward (required)
109
+ # @option params [String, Array<String>] :to the recipients (required). `to`, `cc` and `bcc`
110
+ # combined cannot exceed 50 recipients
111
+ # @option params [String, Array<String>] :cc CC recipients
112
+ # @option params [String, Array<String>] :bcc BCC recipients
113
+ # @option params [String] :html an HTML note sent above the quoted original
114
+ # @option params [String] :text a plain-text note sent above the quoted original
115
+ # @option params [String] :subject the subject of the forward. When omitted, the thread subject
116
+ # is used, prefixed with `Fwd:` if it does not already start with it
117
+ # @option params [Array<Hash>] :attachments files to attach, as on {Resend::Emails.send}. Each one
118
+ # needs `content` or `path`. An empty file, a blocked file type, or a `path` that is not an
119
+ # `http` or `https` URL, or that points to `localhost`, returns a 422
120
+ # @option params [Hash{String => String}] :headers custom headers to add to the email. The
121
+ # `In-Reply-To`, `References` and `Reply-To` headers are set by Resend and cannot be set here.
122
+ # Sending one of them, in any letter case, returns a 422. Header names cannot be empty, and
123
+ # names and values cannot contain line breaks or null characters, or the request returns a 422
124
+ # @param options [Hash] additional options for the request
125
+ # @option options [String] :idempotency_key a unique key for the request, so the forward is sent
126
+ # only once. 1 to 256 characters. A retry with the same key within 24 hours replays the first
127
+ # successful (2xx) response, with the `idempotent-replayed: true` header. A failed request is
128
+ # not stored, so you can retry it with the same key. Reusing the key with a different body, or
129
+ # while the first request is still running, returns a 409
130
+ #
131
+ # @return [Hash] the `id` of the sent email
132
+ #
133
+ # https://resend.com/docs/api-reference/inboxes/forward-thread-email
134
+ def forward(params = {}, options: {})
135
+ validate_email!(params)
136
+
137
+ Resend::Request.new("#{email_path(params)}/forward", body(params), "post", options: options).perform
138
+ end
139
+
140
+ private
141
+
142
+ def validate_thread!(params)
143
+ raise ArgumentError, "inbox_id is required" if params[:inbox_id].nil?
144
+ raise ArgumentError, "thread_id is required" if params[:thread_id].nil?
145
+ end
146
+
147
+ def validate_email!(params)
148
+ validate_thread!(params)
149
+ raise ArgumentError, "email_id is required" if params[:email_id].nil?
150
+ end
151
+
152
+ def email_path(params)
153
+ "#{Resend::Inboxes.path(params[:inbox_id])}/threads/#{params[:thread_id]}/emails/#{params[:email_id]}"
154
+ end
155
+
156
+ def body(params)
157
+ params.except(:inbox_id, :thread_id, :email_id)
158
+ end
159
+ end
160
+ end
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Resend
4
+ module Inboxes
5
+ module Threads
6
+ # Inbox Thread Labels api wrapper
7
+ #
8
+ # Changes which labels a thread carries. To create, rename, or delete the labels themselves,
9
+ # use {Resend::Inboxes::Labels}. Every method returns every label on the thread after the change.
10
+ module Labels
11
+ class << self
12
+ # Add labels to an inbox thread
13
+ #
14
+ # Labels already on the thread stay on it. A label ID that is not a label of the inbox returns
15
+ # a 404, and nothing changes. To replace the labels of the thread, use {set}.
16
+ #
17
+ # @param params [Hash] the parameters
18
+ # @option params [String] :inbox_id the inbox ID or the inbox email address (required)
19
+ # @option params [String] :thread_id the thread ID (required)
20
+ # @option params [Array<String>] :labels the IDs of the labels to apply to the thread. Between
21
+ # 1 and 10 IDs, each a label of the inbox (required)
22
+ #
23
+ # https://resend.com/docs/api-reference/inboxes/add-thread-labels
24
+ def add(params = {})
25
+ validate_labels!(params)
26
+
27
+ Resend::Request.new(labels_path(params), params.slice(:labels), "post").perform
28
+ end
29
+
30
+ # Set the labels of an inbox thread
31
+ #
32
+ # Replaces every label on the thread with the given labels, in one atomic change. The labels
33
+ # themselves are kept. An empty array takes every label off the thread. A label ID that is not
34
+ # a label of the inbox returns a 404, and nothing changes.
35
+ #
36
+ # @param params [Hash] the parameters
37
+ # @option params [String] :inbox_id the inbox ID or the inbox email address (required)
38
+ # @option params [String] :thread_id the thread ID (required)
39
+ # @option params [Array<String>] :labels the IDs of the labels the thread carries after the
40
+ # change. Up to 100 IDs, each a label of the inbox (required)
41
+ #
42
+ # https://resend.com/docs/api-reference/inboxes/set-thread-labels
43
+ def set(params = {})
44
+ validate_labels!(params)
45
+
46
+ Resend::Request.new(labels_path(params), params.slice(:labels), "put").perform
47
+ end
48
+
49
+ # Remove a label from an inbox thread
50
+ #
51
+ # The label itself is kept, and stays on every other thread that carries it. A label that is
52
+ # not on the thread returns the current labels. To delete the label, use
53
+ # {Resend::Inboxes::Labels.remove}.
54
+ #
55
+ # @param params [Hash] the parameters
56
+ # @option params [String] :inbox_id the inbox ID or the inbox email address (required)
57
+ # @option params [String] :thread_id the thread ID (required)
58
+ # @option params [String] :label_id the label ID (required)
59
+ #
60
+ # https://resend.com/docs/api-reference/inboxes/remove-thread-label
61
+ def remove(params = {})
62
+ validate_thread!(params)
63
+ raise ArgumentError, "label_id is required" if params[:label_id].nil?
64
+
65
+ Resend::Request.new("#{labels_path(params)}/#{params[:label_id]}", {}, "delete").perform
66
+ end
67
+
68
+ private
69
+
70
+ def validate_thread!(params)
71
+ raise ArgumentError, "inbox_id is required" if params[:inbox_id].nil?
72
+ raise ArgumentError, "thread_id is required" if params[:thread_id].nil?
73
+ end
74
+
75
+ def validate_labels!(params)
76
+ validate_thread!(params)
77
+ raise ArgumentError, "labels is required" if params[:labels].nil?
78
+ end
79
+
80
+ def labels_path(params)
81
+ "#{Resend::Inboxes.path(params[:inbox_id])}/threads/#{params[:thread_id]}/labels"
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Resend
4
+ module Inboxes
5
+ # Inbox Threads api wrapper
6
+ #
7
+ # A thread is a conversation made up of one or more emails.
8
+ module Threads
9
+ class << self
10
+ # Retrieve a list of inbox threads, most recently active first
11
+ #
12
+ # The `after` and `before` cursors take a thread ID, and only one of them can be passed.
13
+ # A cursor thread that is not in the selected folders returns a 404. To find threads by text,
14
+ # sender, recipient, attachment, or date, use {search}.
15
+ #
16
+ # @param params [Hash] the parameters
17
+ # @option params [String] :inbox_id the inbox ID or the inbox email address (required)
18
+ # @option params [Array<String>] :folders the folders to list: `inbox`, `archive`, `spam`, `sent`,
19
+ # `trash`. A thread is returned when any of its emails is in one of the folders. Defaults to
20
+ # `inbox`, or to `inbox`, `archive` and `sent` when `labels` is set. `spam` and `trash` are only
21
+ # included when you name them
22
+ # @option params [Array<String>] :labels label IDs. Returns threads with any of these labels.
23
+ # Up to 50 IDs
24
+ # @option params [Boolean] :read true returns threads where every email is read. false returns
25
+ # threads with at least one unread email
26
+ # @option params [Integer] :limit the maximum number of results to return
27
+ # @option params [String] :after the cursor for pagination
28
+ # @option params [String] :before the cursor for pagination
29
+ #
30
+ # https://resend.com/docs/api-reference/inboxes/list-threads
31
+ def list(params = {})
32
+ raise ArgumentError, "inbox_id is required" if params[:inbox_id].nil?
33
+
34
+ path = build_query_path("#{Resend::Inboxes.path(params[:inbox_id])}/threads", params.except(:inbox_id))
35
+ Resend::Request.new(path, {}, "get").perform
36
+ end
37
+
38
+ # Search the threads of an inbox
39
+ #
40
+ # Results are ordered by latest activity, newest first, and paginate like {list}. Search can be
41
+ # up to about a minute behind new emails. Different parameters combine, so a thread must match
42
+ # all of them. `folders`, `labels`, and `read` apply to the thread. `query`, `from`, `to`, `cc`,
43
+ # `bcc`, `has_attachment`, `start_date`, and `end_date` must all match the same email in the
44
+ # thread. When any of these email filters is set, the matching email must itself be in one of
45
+ # `folders`. For `sent`, that means an email the inbox sent. When more than 10,000 threads match,
46
+ # search covers the 10,000 with the newest matching email.
47
+ #
48
+ # @param params [Hash] the parameters
49
+ # @option params [String] :inbox_id the inbox ID or the inbox email address (required)
50
+ # @option params [String] :query free text to search for in the subject, body, sender,
51
+ # recipients, and attachment names. Every word must match. Wrap words in double quotes to
52
+ # match an exact phrase. Start a word or quoted phrase with `-` to exclude it.
53
+ # Max 256 characters and 32 words
54
+ # @option params [Array<String>] :from senders. Each value matches part of the sender's address
55
+ # or name, without case. Returns threads that match any of them. Up to 20 values
56
+ # @option params [Array<String>] :to recipients, matched the same way as `from`. Up to 20 values
57
+ # @option params [Array<String>] :cc CC recipients, matched the same way as `from`. Up to 20 values
58
+ # @option params [Array<String>] :bcc BCC recipients, matched the same way as `from`.
59
+ # Up to 20 values
60
+ # @option params [Boolean] :has_attachment true matches emails with an attachment. false matches
61
+ # emails without one
62
+ # @option params [String] :start_date matches emails sent on or after this date. Accepts a date
63
+ # like `2026-09-01` or an ISO 8601 timestamp, in UTC unless the timestamp has an offset
64
+ # @option params [String] :end_date matches emails sent on or before this date. Same formats as
65
+ # `start_date`. A date covers that whole day
66
+ # @option params [Array<String>] :folders the folders to search, as in {list}
67
+ # @option params [Array<String>] :labels label IDs, as in {list}
68
+ # @option params [Boolean] :read the read state, as in {list}
69
+ # @option params [Integer] :limit the maximum number of results to return
70
+ # @option params [String] :after the cursor for pagination
71
+ # @option params [String] :before the cursor for pagination
72
+ #
73
+ # https://resend.com/docs/api-reference/inboxes/search-threads
74
+ def search(params = {})
75
+ raise ArgumentError, "inbox_id is required" if params[:inbox_id].nil?
76
+
77
+ path = build_query_path("#{Resend::Inboxes.path(params[:inbox_id])}/threads/search", params.except(:inbox_id))
78
+ Resend::Request.new(path, {}, "get").perform
79
+ end
80
+
81
+ # Retrieve a single inbox thread
82
+ #
83
+ # Returns the thread summary. List the emails in the thread with {Emails.list}.
84
+ #
85
+ # @param params [Hash] the parameters
86
+ # @option params [String] :inbox_id the inbox ID or the inbox email address (required)
87
+ # @option params [String] :thread_id the thread ID (required)
88
+ #
89
+ # https://resend.com/docs/api-reference/inboxes/get-thread
90
+ def get(params = {})
91
+ raise ArgumentError, "inbox_id is required" if params[:inbox_id].nil?
92
+ raise ArgumentError, "thread_id is required" if params[:thread_id].nil?
93
+
94
+ path = "#{Resend::Inboxes.path(params[:inbox_id])}/threads/#{params[:thread_id]}"
95
+ Resend::Request.new(path, {}, "get").perform
96
+ end
97
+
98
+ # Update an existing inbox thread
99
+ #
100
+ # Marks a thread read or unread, or moves it to a folder. At least one of `read` or `folder` is
101
+ # required. To change the labels of a thread, use {Labels}. Moving a thread out of `trash` restores
102
+ # it and clears its deletion deadline. The changes apply in this order: `read`, then `folder`.
103
+ # They are not atomic.
104
+ #
105
+ # @param params [Hash] the parameters
106
+ # @option params [String] :inbox_id the inbox ID or the inbox email address (required)
107
+ # @option params [String] :thread_id the thread ID (required)
108
+ # @option params [Boolean] :read marks every email in the thread read or unread
109
+ # @option params [String] :folder moves the thread to this folder: `inbox`, `archive`, `spam`,
110
+ # or `trash`. `sent` is assigned automatically and cannot be set
111
+ #
112
+ # https://resend.com/docs/api-reference/inboxes/update-thread
113
+ def update(params = {})
114
+ raise ArgumentError, "inbox_id is required" if params[:inbox_id].nil?
115
+ raise ArgumentError, "thread_id is required" if params[:thread_id].nil?
116
+
117
+ path = "#{Resend::Inboxes.path(params[:inbox_id])}/threads/#{params[:thread_id]}"
118
+ Resend::Request.new(path, params.except(:inbox_id, :thread_id), "patch").perform
119
+ end
120
+
121
+ # Remove an existing inbox thread
122
+ #
123
+ # Moves the thread to `trash` and schedules it for deletion in 30 days. This is reversible.
124
+ # To restore the thread, update its `folder` to `inbox`, `archive`, or `spam`, which also clears
125
+ # the deletion deadline.
126
+ #
127
+ # @param params [Hash] the parameters
128
+ # @option params [String] :inbox_id the inbox ID or the inbox email address (required)
129
+ # @option params [String] :thread_id the thread ID (required)
130
+ #
131
+ # https://resend.com/docs/api-reference/inboxes/delete-thread
132
+ def remove(params = {})
133
+ raise ArgumentError, "inbox_id is required" if params[:inbox_id].nil?
134
+ raise ArgumentError, "thread_id is required" if params[:thread_id].nil?
135
+
136
+ path = "#{Resend::Inboxes.path(params[:inbox_id])}/threads/#{params[:thread_id]}"
137
+ Resend::Request.new(path, {}, "delete").perform
138
+ end
139
+
140
+ private
141
+
142
+ # The API reads list filters as one comma-separated value and rejects a repeated parameter.
143
+ def build_query_path(base_path, query)
144
+ joined = query.transform_values { |value| value.is_a?(Array) ? value.join(",") : value }
145
+ Resend::PaginationHelper.build_paginated_path(base_path, joined)
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Resend
4
+ # Inboxes api wrapper
5
+ #
6
+ # An inbox sends and receives email at an address on one of your domains.
7
+ #
8
+ # @example Create an inbox
9
+ # Resend::Inboxes.create(email_address: "support@acme.com", name: "Customer Support")
10
+ #
11
+ # @example Retrieve an inbox by ID or email address
12
+ # Resend::Inboxes.get("support@acme.com")
13
+ module Inboxes
14
+ class << self
15
+ # Create an inbox
16
+ #
17
+ # The domain must belong to the team. Without `forwarding`, the domain must have receiving
18
+ # enabled, with DKIM and SPF verified and the inbound MX record verified or pending. With
19
+ # `forwarding` set to `true`, the domain only needs DKIM and SPF verified for sending, and
20
+ # Resend generates a `receiving_address` on the team inbound domain. A team that has reached
21
+ # the inbox limit of its plan gets a 403 validation_error. A blocked account gets a 451.
22
+ #
23
+ # @param params [Hash] the inbox parameters
24
+ # @option params [String] :email_address the inbox email address on one of your domains (required)
25
+ # @option params [String] :name internal name for the inbox, max 64 characters.
26
+ # Recipients do not see it. Defaults to `email_address`
27
+ # @option params [String] :from_name the name recipients see when mail is sent from this inbox,
28
+ # max 78 characters. An empty string leaves it unset
29
+ # @option params [Boolean] :forwarding when true, Resend provisions a receiving address so you can
30
+ # receive mail without adding an MX record. Defaults to false
31
+ #
32
+ # @return [Hash] the created inbox `object` and `id`
33
+ #
34
+ # https://resend.com/docs/api-reference/inboxes/create-inbox
35
+ def create(params = {})
36
+ Resend::Request.new("inboxes", params, "post").perform
37
+ end
38
+
39
+ # Retrieve a list of inboxes, newest first
40
+ #
41
+ # The list items carry fewer fields than a single inbox. Retrieve an inbox to get all its fields.
42
+ # The `after` and `before` cursors take an inbox ID.
43
+ #
44
+ # @param params [Hash] the pagination parameters
45
+ # @option params [Integer] :limit the maximum number of results to return
46
+ # @option params [String] :after the cursor for pagination
47
+ # @option params [String] :before the cursor for pagination
48
+ #
49
+ # https://resend.com/docs/api-reference/inboxes/list-inboxes
50
+ def list(params = {})
51
+ path = Resend::PaginationHelper.build_paginated_path("inboxes", params)
52
+ Resend::Request.new(path, {}, "get").perform
53
+ end
54
+
55
+ # Retrieve a single inbox
56
+ #
57
+ # @param inbox_id [String] the inbox ID or the inbox email address, such as `support@acme.com`.
58
+ # An email address matches without case
59
+ #
60
+ # https://resend.com/docs/api-reference/inboxes/get-inbox
61
+ def get(inbox_id = "")
62
+ Resend::Request.new(path(inbox_id), {}, "get").perform
63
+ end
64
+
65
+ # Update an existing inbox
66
+ #
67
+ # At least one of `name` or `from_name` is required.
68
+ #
69
+ # @param params [Hash] the update parameters
70
+ # @option params [String] :inbox_id the inbox ID or the inbox email address (required)
71
+ # @option params [String] :name new internal name for the inbox, between 1 and 64 characters
72
+ # @option params [String] :from_name the name recipients see when mail is sent from this inbox,
73
+ # max 78 characters. An empty string removes it
74
+ #
75
+ # @return [Hash] the updated inbox `object` and `id`
76
+ #
77
+ # https://resend.com/docs/api-reference/inboxes/update-inbox
78
+ def update(params = {})
79
+ raise ArgumentError, "inbox_id is required" if params[:inbox_id].nil?
80
+
81
+ payload = params.except(:inbox_id)
82
+ Resend::Request.new(path(params[:inbox_id]), payload, "patch").perform
83
+ end
84
+
85
+ # Remove an existing inbox
86
+ #
87
+ # @param inbox_id [String] the inbox ID or the inbox email address
88
+ #
89
+ # https://resend.com/docs/api-reference/inboxes/delete-inbox
90
+ def remove(inbox_id = "")
91
+ Resend::Request.new(path(inbox_id), {}, "delete").perform
92
+ end
93
+
94
+ # The path of an inbox. The API takes the inbox ID or the inbox email address, and an address
95
+ # must be percent-encoded to fit in the path.
96
+ #
97
+ # @api private
98
+ def path(inbox_id)
99
+ "inboxes/#{ERB::Util.url_encode(inbox_id)}"
100
+ end
101
+ end
102
+ end
103
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Resend
4
- VERSION = "1.17.0"
4
+ VERSION = "1.18.0"
5
5
  end
data/lib/resend.rb CHANGED
@@ -42,6 +42,13 @@ require "resend/events"
42
42
  require "resend/suppressions"
43
43
  require "resend/suppressions/batch"
44
44
  require "resend/usage"
45
+ require "resend/inboxes"
46
+ require "resend/inboxes/agent"
47
+ require "resend/inboxes/labels"
48
+ require "resend/inboxes/threads"
49
+ require "resend/inboxes/threads/emails"
50
+ require "resend/inboxes/threads/labels"
51
+ require "resend/inboxes/drafts"
45
52
 
46
53
  # Rails
47
54
  require "resend/railtie" if defined?(Rails) && defined?(ActionMailer)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: resend
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.17.0
4
+ version: 1.18.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Derich Pacheco
@@ -68,6 +68,13 @@ files:
68
68
  - lib/resend/emails/receiving/attachments.rb
69
69
  - lib/resend/errors.rb
70
70
  - lib/resend/events.rb
71
+ - lib/resend/inboxes.rb
72
+ - lib/resend/inboxes/agent.rb
73
+ - lib/resend/inboxes/drafts.rb
74
+ - lib/resend/inboxes/labels.rb
75
+ - lib/resend/inboxes/threads.rb
76
+ - lib/resend/inboxes/threads/emails.rb
77
+ - lib/resend/inboxes/threads/labels.rb
71
78
  - lib/resend/logs.rb
72
79
  - lib/resend/mailer.rb
73
80
  - lib/resend/multipart_request.rb