sendmux-sending 1.2.0 → 1.4.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: 6dbfe224c407947d8b0b69e3c8ac663c5d2e6af75b820ef775971f40fb659545
4
- data.tar.gz: d73c320e4b15a22d56b28a82e96076780c5b77009e185f0a4e7fcc517785ea40
3
+ metadata.gz: 195959762d9b4fe1a794ad4b40bde49927733d5bf6bbbe751ff7975a74a3be4b
4
+ data.tar.gz: 0b4e725dd8a434917954bd0d0bddc0232e58f7596c6e3fada3ff404f98a017d0
5
5
  SHA512:
6
- metadata.gz: 20b08ea90472135d92dcf0e346790489cd219c2f64c8004b0dbc3881cc01746eb8b0b98862bb27e9bd55999fd771098116f69dda0373916bce80e9979780e65c
7
- data.tar.gz: a05947636992ca4e2b71d35cc73219a008c53000d83eb4a954bda632bbd3ccbc6e6924c2810ef510eb5b7506c8762d257bf6c631da7e8aa21c6681ce0bdf45fb
6
+ metadata.gz: d14fc7657e5a681d1624acf5fa069f04d795435c6f6422662d0e4e25f2a2598d7dfe049c35deda0262ab0fca4e1f15a6610fe06bc737d7090aa8d657c5bbd377
7
+ data.tar.gz: 0d415c60df2619d31805dbc5b9aebe0580feaa47b12d6ae9e3e81826e3f5044054fb46423489f2f18f39473207cbf2c89556eb3ec7a66651c4893b231f577c02
data/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.4.0](https://github.com/Sendmux/sendmux-sdk/compare/ruby-sending/v1.3.0...ruby-sending/v1.4.0) (2026-09-10)
4
+
5
+
6
+ ### Features
7
+
8
+ * add REST OAuth clients and CLI token lifecycle ([cc4a3aa](https://github.com/Sendmux/sendmux-sdk/commit/cc4a3aa6110378641418a94455ed5b9a986e65ff))
9
+
10
+ ## [1.3.0](https://github.com/Sendmux/sendmux-sdk/compare/ruby-sending/v1.2.0...ruby-sending/v1.3.0) (2026-09-08)
11
+
12
+
13
+ ### Features
14
+
15
+ * add connection checks across SDKs, CLI and MCP ([77f449e](https://github.com/Sendmux/sendmux-sdk/commit/77f449e2c8cba49bc8bc84c49c35baa61120866a))
16
+ * **sdk:** add connection checks across clients, CLI and MCP ([3e02c67](https://github.com/Sendmux/sendmux-sdk/commit/3e02c67dcab45e37dad7abbdd4c4e1bd0b1fbbe6))
17
+
3
18
  ## [1.2.0](https://github.com/Sendmux/sendmux-sdk/compare/ruby-sending/v1.1.0...ruby-sending/v1.2.0) (2026-07-08)
4
19
 
5
20
 
data/README.md CHANGED
@@ -18,6 +18,8 @@ Ruby SDK package for the Sendmux Sending API.
18
18
  - Ruby 3.1 or newer.
19
19
  - A send-capable `smx_mbx_` key or owner-approved Sending-resource `smx_agent_` token.
20
20
 
21
+ For OAuth, use a REST access token with the scopes and mailbox access required by the operation. See [OAuth for REST APIs](https://sendmux.ai/docs/developer-tools/oauth).
22
+
21
23
  ## Installation
22
24
 
23
25
  ```sh
@@ -30,9 +32,21 @@ Or add it to your Gemfile:
30
32
  gem "sendmux-sending", "~> 1.0"
31
33
  ```
32
34
 
35
+ ## OAuth access tokens
36
+
37
+ Pass either `api_key:` or `access_token:`. `access_token:` accepts a bare token string or a callable; the callable is evaluated once per authenticated request. Your application owns token storage, expiry checks and refresh coordination.
38
+
39
+ ```ruby
40
+ require "sendmux/sending"
41
+
42
+ client = Sendmux::Sending::Client.new(
43
+ access_token: -> { ENV.fetch("SENDMUX_ACCESS_TOKEN") }
44
+ )
45
+ ```
46
+
33
47
  ## Usage
34
48
 
35
- Create a sending client with a send-capable key before calling generated operations.
49
+ Create a sending client with a send-capable key for the API-key example below.
36
50
 
37
51
  ```ruby
38
52
  require "sendmux/sending"
@@ -5,6 +5,12 @@ module Sendmux
5
5
  DEFAULT_BASE_URL = 'https://smtp.sendmux.ai/api/v1'
6
6
 
7
7
  class ApiClient < Generated::ApiClient
8
+ def update_params_for_auth!(header_params, query_params, auth_names)
9
+ return super unless config.access_token_getter && !Array(auth_names).empty?
10
+
11
+ header_params['Authorization'] = "Bearer #{config.access_token_with_refresh}"
12
+ end
13
+
8
14
  def call_api(...)
9
15
  super
10
16
  rescue Generated::ApiError => e
@@ -15,12 +21,13 @@ module Sendmux
15
21
  class Client
16
22
  attr_reader :api_client, :configuration
17
23
 
18
- def initialize(api_key:, base_url: DEFAULT_BASE_URL, retry_options: nil)
24
+ def initialize(api_key: nil, access_token: nil, base_url: DEFAULT_BASE_URL, retry_options: nil)
19
25
  @configuration = Sendmux::Core::Auth.configure_bearer(
20
26
  Generated::Configuration.new,
21
27
  api_key,
22
28
  Sendmux::Core::ApiKeySurface::SENDING,
23
- base_url: base_url
29
+ base_url: base_url,
30
+ access_token: access_token
24
31
  )
25
32
  Sendmux::Core::Retry.configure(@configuration, retry_options)
26
33
  @api_client = ApiClient.new(@configuration)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Sendmux
4
4
  module Sending
5
- VERSION = '1.2.0'
5
+ VERSION = '1.4.0'
6
6
  end
7
7
  end
@@ -172,7 +172,7 @@ module Sendmux::Sending::Generated
172
172
  return_type = opts[:debug_return_type] || 'AttachmentUploadIntentResponse'
173
173
 
174
174
  # auth_names
175
- auth_names = opts[:debug_auth_names] || ['BearerAuth']
175
+ auth_names = opts[:debug_auth_names] || ['OAuth2', 'BearerAuth']
176
176
 
177
177
  new_options = opts.merge(
178
178
  :operation => :"AttachmentsApi.sending_create_attachment_upload",
@@ -240,7 +240,7 @@ module Sendmux::Sending::Generated
240
240
  return_type = opts[:debug_return_type] || 'AttachmentUploadResponse'
241
241
 
242
242
  # auth_names
243
- auth_names = opts[:debug_auth_names] || ['BearerAuth']
243
+ auth_names = opts[:debug_auth_names] || ['OAuth2', 'BearerAuth']
244
244
 
245
245
  new_options = opts.merge(
246
246
  :operation => :"AttachmentsApi.sending_get_attachment",
@@ -348,7 +348,7 @@ module Sendmux::Sending::Generated
348
348
  return_type = opts[:debug_return_type] || 'AttachmentUploadResponse'
349
349
 
350
350
  # auth_names
351
- auth_names = opts[:debug_auth_names] || ['BearerAuth']
351
+ auth_names = opts[:debug_auth_names] || ['OAuth2', 'BearerAuth']
352
352
 
353
353
  new_options = opts.merge(
354
354
  :operation => :"AttachmentsApi.sending_upload_attachment",
@@ -75,7 +75,7 @@ module Sendmux::Sending::Generated
75
75
  return_type = opts[:debug_return_type] || 'SendSuccessResponse'
76
76
 
77
77
  # auth_names
78
- auth_names = opts[:debug_auth_names] || ['BearerAuth']
78
+ auth_names = opts[:debug_auth_names] || ['OAuth2', 'BearerAuth']
79
79
 
80
80
  new_options = opts.merge(
81
81
  :operation => :"EmailsApi.sending_send_email",
@@ -150,7 +150,7 @@ module Sendmux::Sending::Generated
150
150
  return_type = opts[:debug_return_type] || 'BatchSendSuccessResponse'
151
151
 
152
152
  # auth_names
153
- auth_names = opts[:debug_auth_names] || ['BearerAuth']
153
+ auth_names = opts[:debug_auth_names] || ['OAuth2', 'BearerAuth']
154
154
 
155
155
  new_options = opts.merge(
156
156
  :operation => :"EmailsApi.sending_send_email_batch",
@@ -19,6 +19,66 @@ module Sendmux::Sending::Generated
19
19
  def initialize(api_client = ApiClient.default)
20
20
  @api_client = api_client
21
21
  end
22
+ # Get Sending connection
23
+ # Validate this Sending credential and return its team, connection label, permissions and authorised mailboxes. Requires email.send. Credits, provider readiness and mailbox storage are not checked. No user profile or secrets are returned.
24
+ # @param [Hash] opts the optional parameters
25
+ # @option opts [String] :if_none_match Weak ETag from a previous response. When it matches the current resource, the server returns 304 Not Modified with no body.
26
+ # @return [ConnectionResponse]
27
+ def sending_get_connection(opts = {})
28
+ data, _status_code, _headers = sending_get_connection_with_http_info(opts)
29
+ data
30
+ end
31
+
32
+ # Get Sending connection
33
+ # Validate this Sending credential and return its team, connection label, permissions and authorised mailboxes. Requires email.send. Credits, provider readiness and mailbox storage are not checked. No user profile or secrets are returned.
34
+ # @param [Hash] opts the optional parameters
35
+ # @option opts [String] :if_none_match Weak ETag from a previous response. When it matches the current resource, the server returns 304 Not Modified with no body.
36
+ # @return [Array<(ConnectionResponse, Integer, Hash)>] ConnectionResponse data, response status code and response headers
37
+ def sending_get_connection_with_http_info(opts = {})
38
+ if @api_client.config.debugging
39
+ @api_client.config.logger.debug 'Calling API: MetaApi.sending_get_connection ...'
40
+ end
41
+ # resource path
42
+ local_var_path = '/me'
43
+
44
+ # query parameters
45
+ query_params = opts[:query_params] || {}
46
+
47
+ # header parameters
48
+ header_params = opts[:header_params] || {}
49
+ # HTTP header 'Accept' (if needed)
50
+ header_params['Accept'] = @api_client.select_header_accept(['application/json']) unless header_params['Accept']
51
+ header_params[:'If-None-Match'] = opts[:'if_none_match'] if !opts[:'if_none_match'].nil?
52
+
53
+ # form parameters
54
+ form_params = opts[:form_params] || {}
55
+
56
+ # http body (model)
57
+ post_body = opts[:debug_body]
58
+
59
+ # return_type
60
+ return_type = opts[:debug_return_type] || 'ConnectionResponse'
61
+
62
+ # auth_names
63
+ auth_names = opts[:debug_auth_names] || ['OAuth2', 'BearerAuth']
64
+
65
+ new_options = opts.merge(
66
+ :operation => :"MetaApi.sending_get_connection",
67
+ :header_params => header_params,
68
+ :query_params => query_params,
69
+ :form_params => form_params,
70
+ :body => post_body,
71
+ :auth_names => auth_names,
72
+ :return_type => return_type
73
+ )
74
+
75
+ data, status_code, headers = @api_client.call_api(:GET, local_var_path, new_options)
76
+ if @api_client.config.debugging
77
+ @api_client.config.logger.debug "API called: MetaApi#sending_get_connection\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"
78
+ end
79
+ return data, status_code, headers
80
+ end
81
+
22
82
  # OpenAPI 3.1 specification
23
83
  # Auto-generated OpenAPI 3.1 spec for the Sendmux Sending API. Public endpoint (no authentication). Emits a weak ETag; clients may send `If-None-Match` to receive 304 Not Modified.
24
84
  # @param [Hash] opts the optional parameters
@@ -255,6 +255,13 @@ module Sendmux::Sending::Generated
255
255
  key: 'Authorization',
256
256
  value: "Bearer #{access_token_with_refresh}"
257
257
  },
258
+ 'OAuth2' =>
259
+ {
260
+ type: 'oauth2',
261
+ in: 'header',
262
+ key: 'Authorization',
263
+ value: "Bearer #{access_token_with_refresh}"
264
+ },
258
265
  }
259
266
  end
260
267
 
@@ -0,0 +1,273 @@
1
+ =begin
2
+ #Sendmux Sending API
3
+
4
+ #Send emails programmatically via the Sendmux email infrastructure. Every response carries an `X-Request-Id` header; errors include a `retryable` flag. 429 and 503 responses include `Retry-After`. Mutating endpoints accept an `Idempotency-Key` header for safe retries.
5
+
6
+ The version of the OpenAPI document: 1.0.0
7
+
8
+ Generated by: https://openapi-generator.tech
9
+ Generator version: 7.22.0
10
+
11
+ =end
12
+
13
+ require 'date'
14
+ require 'time'
15
+
16
+ module Sendmux::Sending::Generated
17
+ class Connection < ApiModelBase
18
+ attr_accessor :credential
19
+
20
+ # Display label for this connection.
21
+ attr_accessor :label
22
+
23
+ attr_accessor :mailboxes
24
+
25
+ attr_accessor :permissions
26
+
27
+ attr_accessor :team
28
+
29
+ # Attribute mapping from ruby-style variable name to JSON key.
30
+ def self.attribute_map
31
+ {
32
+ :'credential' => :'credential',
33
+ :'label' => :'label',
34
+ :'mailboxes' => :'mailboxes',
35
+ :'permissions' => :'permissions',
36
+ :'team' => :'team'
37
+ }
38
+ end
39
+
40
+ # Returns attribute mapping this model knows about
41
+ def self.acceptable_attribute_map
42
+ attribute_map
43
+ end
44
+
45
+ # Returns all the JSON keys this model knows about
46
+ def self.acceptable_attributes
47
+ acceptable_attribute_map.values
48
+ end
49
+
50
+ # Attribute type mapping.
51
+ def self.openapi_types
52
+ {
53
+ :'credential' => :'ConnectionCredential',
54
+ :'label' => :'String',
55
+ :'mailboxes' => :'Array<ConnectionMailboxesInner>',
56
+ :'permissions' => :'Array<String>',
57
+ :'team' => :'ConnectionTeam'
58
+ }
59
+ end
60
+
61
+ # List of attributes with nullable: true
62
+ def self.openapi_nullable
63
+ Set.new([
64
+ ])
65
+ end
66
+
67
+ # Initializes the object
68
+ # @param [Hash] attributes Model attributes in the form of hash
69
+ def initialize(attributes = {})
70
+ if (!attributes.is_a?(Hash))
71
+ fail ArgumentError, "The input argument (attributes) must be a hash in `Sendmux::Sending::Generated::Connection` initialize method"
72
+ end
73
+
74
+ # check to see if the attribute exists and convert string to symbol for hash key
75
+ acceptable_attribute_map = self.class.acceptable_attribute_map
76
+ attributes = attributes.each_with_object({}) { |(k, v), h|
77
+ if (!acceptable_attribute_map.key?(k.to_sym))
78
+ fail ArgumentError, "`#{k}` is not a valid attribute in `Sendmux::Sending::Generated::Connection`. Please check the name to make sure it's valid. List of attributes: " + acceptable_attribute_map.keys.inspect
79
+ end
80
+ h[k.to_sym] = v
81
+ }
82
+
83
+ if attributes.key?(:'credential')
84
+ self.credential = attributes[:'credential']
85
+ else
86
+ self.credential = nil
87
+ end
88
+
89
+ if attributes.key?(:'label')
90
+ self.label = attributes[:'label']
91
+ else
92
+ self.label = nil
93
+ end
94
+
95
+ if attributes.key?(:'mailboxes')
96
+ if (value = attributes[:'mailboxes']).is_a?(Array)
97
+ self.mailboxes = value
98
+ end
99
+ else
100
+ self.mailboxes = nil
101
+ end
102
+
103
+ if attributes.key?(:'permissions')
104
+ if (value = attributes[:'permissions']).is_a?(Array)
105
+ self.permissions = value
106
+ end
107
+ else
108
+ self.permissions = nil
109
+ end
110
+
111
+ if attributes.key?(:'team')
112
+ self.team = attributes[:'team']
113
+ else
114
+ self.team = nil
115
+ end
116
+ end
117
+
118
+ # Show invalid properties with the reasons. Usually used together with valid?
119
+ # @return Array for valid properties with the reasons
120
+ def list_invalid_properties
121
+ warn '[DEPRECATED] the `list_invalid_properties` method is obsolete'
122
+ invalid_properties = Array.new
123
+ if @credential.nil?
124
+ invalid_properties.push('invalid value for "credential", credential cannot be nil.')
125
+ end
126
+
127
+ if @label.nil?
128
+ invalid_properties.push('invalid value for "label", label cannot be nil.')
129
+ end
130
+
131
+ if @mailboxes.nil?
132
+ invalid_properties.push('invalid value for "mailboxes", mailboxes cannot be nil.')
133
+ end
134
+
135
+ if @permissions.nil?
136
+ invalid_properties.push('invalid value for "permissions", permissions cannot be nil.')
137
+ end
138
+
139
+ if @team.nil?
140
+ invalid_properties.push('invalid value for "team", team cannot be nil.')
141
+ end
142
+
143
+ invalid_properties
144
+ end
145
+
146
+ # Check to see if the all the properties in the model are valid
147
+ # @return true if the model is valid
148
+ def valid?
149
+ warn '[DEPRECATED] the `valid?` method is obsolete'
150
+ return false if @credential.nil?
151
+ return false if @label.nil?
152
+ return false if @mailboxes.nil?
153
+ return false if @permissions.nil?
154
+ return false if @team.nil?
155
+ true
156
+ end
157
+
158
+ # Custom attribute writer method with validation
159
+ # @param [Object] credential Value to be assigned
160
+ def credential=(credential)
161
+ if credential.nil?
162
+ fail ArgumentError, 'credential cannot be nil'
163
+ end
164
+
165
+ @credential = credential
166
+ end
167
+
168
+ # Custom attribute writer method with validation
169
+ # @param [Object] label Value to be assigned
170
+ def label=(label)
171
+ if label.nil?
172
+ fail ArgumentError, 'label cannot be nil'
173
+ end
174
+
175
+ @label = label
176
+ end
177
+
178
+ # Custom attribute writer method with validation
179
+ # @param [Object] mailboxes Value to be assigned
180
+ def mailboxes=(mailboxes)
181
+ if mailboxes.nil?
182
+ fail ArgumentError, 'mailboxes cannot be nil'
183
+ end
184
+
185
+ @mailboxes = mailboxes
186
+ end
187
+
188
+ # Custom attribute writer method with validation
189
+ # @param [Object] permissions Value to be assigned
190
+ def permissions=(permissions)
191
+ if permissions.nil?
192
+ fail ArgumentError, 'permissions cannot be nil'
193
+ end
194
+
195
+ @permissions = permissions
196
+ end
197
+
198
+ # Custom attribute writer method with validation
199
+ # @param [Object] team Value to be assigned
200
+ def team=(team)
201
+ if team.nil?
202
+ fail ArgumentError, 'team cannot be nil'
203
+ end
204
+
205
+ @team = team
206
+ end
207
+
208
+ # Checks equality by comparing each attribute.
209
+ # @param [Object] Object to be compared
210
+ def ==(o)
211
+ return true if self.equal?(o)
212
+ self.class == o.class &&
213
+ credential == o.credential &&
214
+ label == o.label &&
215
+ mailboxes == o.mailboxes &&
216
+ permissions == o.permissions &&
217
+ team == o.team
218
+ end
219
+
220
+ # @see the `==` method
221
+ # @param [Object] Object to be compared
222
+ def eql?(o)
223
+ self == o
224
+ end
225
+
226
+ # Calculates hash code according to all attributes.
227
+ # @return [Integer] Hash code
228
+ def hash
229
+ [credential, label, mailboxes, permissions, team].hash
230
+ end
231
+
232
+ # Builds the object from hash
233
+ # @param [Hash] attributes Model attributes in the form of hash
234
+ # @return [Object] Returns the model itself
235
+ def self.build_from_hash(attributes)
236
+ return nil unless attributes.is_a?(Hash)
237
+ attributes = attributes.transform_keys(&:to_sym)
238
+ transformed_hash = {}
239
+ openapi_types.each_pair do |key, type|
240
+ if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil?
241
+ transformed_hash["#{key}"] = nil
242
+ elsif type =~ /\AArray<(.*)>/i
243
+ # check to ensure the input is an array given that the attribute
244
+ # is documented as an array but the input is not
245
+ if attributes[attribute_map[key]].is_a?(Array)
246
+ transformed_hash["#{key}"] = attributes[attribute_map[key]].map { |v| _deserialize($1, v) }
247
+ end
248
+ elsif !attributes[attribute_map[key]].nil?
249
+ transformed_hash["#{key}"] = _deserialize(type, attributes[attribute_map[key]])
250
+ end
251
+ end
252
+ new(transformed_hash)
253
+ end
254
+
255
+ # Returns the object in the form of hash
256
+ # @return [Hash] Returns the object in the form of hash
257
+ def to_hash
258
+ hash = {}
259
+ self.class.attribute_map.each_pair do |attr, param|
260
+ value = self.send(attr)
261
+ if value.nil?
262
+ is_nullable = self.class.openapi_nullable.include?(attr)
263
+ next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
264
+ end
265
+
266
+ hash[param] = _to_hash(value)
267
+ end
268
+ hash
269
+ end
270
+
271
+ end
272
+
273
+ end