supersendtx 0.8.2
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 +7 -0
- data/.gitignore +4 -0
- data/Gemfile +9 -0
- data/README.md +24 -0
- data/lib/supersendtx/client.rb +21 -0
- data/lib/supersendtx/error.rb +38 -0
- data/lib/supersendtx/http.rb +51 -0
- data/lib/supersendtx/resources.rb +199 -0
- data/lib/supersendtx/version.rb +5 -0
- data/lib/supersendtx.rb +10 -0
- data/supersendtx.gemspec +31 -0
- metadata +57 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: eca4d44a3a130a37fb7055f295cd6f37ed780c145189a1ce40d4318f7fd5d309
|
|
4
|
+
data.tar.gz: 5a4728dd67281d5323c284c32e21ef03943f602987428c2c76452fee6c80e904
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 303ae619a3dc9bc631c2938acf710bf25d63639c2612a96fe1229e6e3d3e5d40ef0a9a24d0a4c8ed837963f41814e6012e1f7eef8c160c0c1494adce1f6d4e7e
|
|
7
|
+
data.tar.gz: dda61e8e034f98c653c0ca8adb4f75de2226065a6f9126d416487e3f5d20c48f7d94bfd10bea34229dff32f054c5402673d0326cbb8d9bf2e2378a1397a5a51c
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# SuperSend TX Ruby SDK
|
|
2
|
+
|
|
3
|
+
Official Ruby client for the [SuperSend TX](https://supersendtx.com) transactional email API.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
gem install supersendtx
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
require "supersendtx"
|
|
11
|
+
|
|
12
|
+
tx = SuperSendTX::Client.new("stx_your_key_here")
|
|
13
|
+
|
|
14
|
+
result = tx.emails.send(
|
|
15
|
+
from: "you@yourdomain.com",
|
|
16
|
+
to: "user@example.com",
|
|
17
|
+
subject: "Hello",
|
|
18
|
+
html: "<p>It works.</p>"
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
puts result["id"], result["status"]
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Docs: https://docs.supersendtx.com/sdks/ruby
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SuperSendTX
|
|
4
|
+
class Client
|
|
5
|
+
attr_reader :emails, :domains, :webhooks, :templates, :suppressions
|
|
6
|
+
|
|
7
|
+
def initialize(api_key, base_url: HttpClient::DEFAULT_API_BASE_URL, transport: nil)
|
|
8
|
+
http = HttpClient.new(api_key, base_url: base_url, transport: transport)
|
|
9
|
+
@emails = EmailsResource.new(http)
|
|
10
|
+
@domains = DomainsResource.new(http)
|
|
11
|
+
@webhooks = WebhooksResource.new(http)
|
|
12
|
+
@templates = TemplatesResource.new(http)
|
|
13
|
+
@suppressions = SuppressionsResource.new(http)
|
|
14
|
+
@http = http
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def request(method, path, body: nil, headers: {})
|
|
18
|
+
@http.request(method, path, body: body, headers: headers)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "net/http"
|
|
5
|
+
require "uri"
|
|
6
|
+
|
|
7
|
+
module SuperSendTX
|
|
8
|
+
class Error < StandardError
|
|
9
|
+
attr_reader :status, :details, :error_code, :upgrade_url
|
|
10
|
+
|
|
11
|
+
def initialize(message, status:, details: nil, error_code: nil, upgrade_url: nil)
|
|
12
|
+
super(message)
|
|
13
|
+
@status = status
|
|
14
|
+
@details = details
|
|
15
|
+
@error_code = error_code
|
|
16
|
+
@upgrade_url = upgrade_url
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.from_response(status, body)
|
|
20
|
+
err = body.is_a?(Hash) ? body["error"] : nil
|
|
21
|
+
|
|
22
|
+
case err
|
|
23
|
+
when String
|
|
24
|
+
new(err, status: status)
|
|
25
|
+
when Hash
|
|
26
|
+
new(
|
|
27
|
+
err["message"] || "Request failed with status #{status}",
|
|
28
|
+
status: status,
|
|
29
|
+
details: err["details"],
|
|
30
|
+
error_code: err["code"]&.to_s,
|
|
31
|
+
upgrade_url: err["upgrade_url"]&.to_s
|
|
32
|
+
)
|
|
33
|
+
else
|
|
34
|
+
new("Request failed with status #{status}", status: status)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "net/http"
|
|
5
|
+
require "uri"
|
|
6
|
+
|
|
7
|
+
module SuperSendTX
|
|
8
|
+
class HttpClient
|
|
9
|
+
DEFAULT_API_BASE_URL = "https://api.supersendtx.com"
|
|
10
|
+
|
|
11
|
+
def initialize(api_key, base_url: DEFAULT_API_BASE_URL, transport: nil)
|
|
12
|
+
raise ArgumentError, "SuperSend TX API key must start with stx_" unless api_key.start_with?("stx_")
|
|
13
|
+
|
|
14
|
+
@api_key = api_key
|
|
15
|
+
@base_url = base_url.chomp("/")
|
|
16
|
+
@transport = transport
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def request(method, path, body: nil, headers: {})
|
|
20
|
+
request_headers = {
|
|
21
|
+
"Authorization" => "Bearer #{@api_key}",
|
|
22
|
+
"Content-Type" => "application/json"
|
|
23
|
+
}.merge(headers)
|
|
24
|
+
|
|
25
|
+
return @transport.call(method, path, body, request_headers) if @transport
|
|
26
|
+
|
|
27
|
+
uri = URI.parse("#{@base_url}#{path}")
|
|
28
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
29
|
+
http.use_ssl = uri.scheme == "https"
|
|
30
|
+
|
|
31
|
+
request_class = Net::HTTP.const_get(method.capitalize)
|
|
32
|
+
request = request_class.new(uri.request_uri)
|
|
33
|
+
request_headers.each { |key, value| request[key] = value }
|
|
34
|
+
request.body = JSON.generate(body) if body
|
|
35
|
+
|
|
36
|
+
response = http.request(request)
|
|
37
|
+
parsed = response.body.to_s.empty? ? {} : JSON.parse(response.body)
|
|
38
|
+
|
|
39
|
+
raise Error.from_response(response.code.to_i, parsed) if response.code.to_i >= 400
|
|
40
|
+
|
|
41
|
+
parsed
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def query(params)
|
|
45
|
+
filtered = params.compact
|
|
46
|
+
return "" if filtered.empty?
|
|
47
|
+
|
|
48
|
+
"?#{URI.encode_www_form(filtered)}"
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SuperSendTX
|
|
4
|
+
class EmailsResource
|
|
5
|
+
def initialize(http)
|
|
6
|
+
@http = http
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def list(limit: nil, cursor: nil)
|
|
10
|
+
@http.request("GET", "/emails#{@http.query({ "limit" => limit, "cursor" => cursor })}")
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def get(email_id)
|
|
14
|
+
@http.request("GET", "/emails/#{URI.encode_www_form_component(email_id)}")
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def send(from: nil, to: nil, **params)
|
|
18
|
+
params["from"] = from if from
|
|
19
|
+
params["to"] = to if to
|
|
20
|
+
body = serialize_send_params(params)
|
|
21
|
+
headers = {}
|
|
22
|
+
idempotency_key = params["idempotency_key"] || params["idempotencyKey"]
|
|
23
|
+
headers["Idempotency-Key"] = idempotency_key.to_s if idempotency_key
|
|
24
|
+
|
|
25
|
+
@http.request("POST", "/emails", body: body, headers: headers)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def batch(emails)
|
|
29
|
+
serialized = emails.map { |email| serialize_send_params(email) }
|
|
30
|
+
@http.request("POST", "/emails/batch", body: { "emails" => serialized })
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def cancel(email_id)
|
|
34
|
+
@http.request("PATCH", "/emails/#{URI.encode_www_form_component(email_id)}", body: { "cancel" => true })
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def resend(email_id)
|
|
38
|
+
@http.request("POST", "/emails/#{URI.encode_www_form_component(email_id)}/resend")
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def test_webhook(**params)
|
|
42
|
+
@http.request("POST", "/emails/test", body: params)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def insights(window: "30d")
|
|
46
|
+
@http.request("GET", "/deliverability#{@http.query({ "window" => window })}")
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
def serialize_send_params(params)
|
|
52
|
+
body = {
|
|
53
|
+
"from" => params["from"] || params[:from],
|
|
54
|
+
"to" => params["to"] || params[:to]
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
%w[subject html text reply_to replyTo cc bcc tags headers tag template].each do |key|
|
|
58
|
+
value = params[key] || params[key.to_sym]
|
|
59
|
+
next if value.nil?
|
|
60
|
+
|
|
61
|
+
mapped = key == "replyTo" ? "reply_to" : key
|
|
62
|
+
body[mapped] = value
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
body["html"] = params["htmlBody"] || params[:htmlBody] if params["htmlBody"] || params[:htmlBody]
|
|
66
|
+
body["text"] = params["textBody"] || params[:textBody] if params["textBody"] || params[:textBody]
|
|
67
|
+
body["scheduled_at"] = params["scheduled_at"] || params[:scheduled_at] if params["scheduled_at"] || params[:scheduled_at]
|
|
68
|
+
body["scheduled_at"] ||= params["scheduledAt"] || params[:scheduledAt]
|
|
69
|
+
body["unsubscribe"] = params["unsubscribe"] || params[:unsubscribe] if params.key?("unsubscribe") || params.key?(:unsubscribe)
|
|
70
|
+
|
|
71
|
+
body
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
class DomainsResource
|
|
76
|
+
def initialize(http)
|
|
77
|
+
@http = http
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def list(limit: nil, cursor: nil, inbound_enabled: nil)
|
|
81
|
+
@http.request(
|
|
82
|
+
"GET",
|
|
83
|
+
"/domains#{@http.query({ "limit" => limit, "cursor" => cursor, "inbound_enabled" => inbound_enabled })}"
|
|
84
|
+
)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def get(id_or_name)
|
|
88
|
+
@http.request("GET", "/domains/#{URI.encode_www_form_component(id_or_name)}")
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def create(name, inbound_enabled: nil)
|
|
92
|
+
body = { "name" => name }
|
|
93
|
+
body["inbound_enabled"] = inbound_enabled unless inbound_enabled.nil?
|
|
94
|
+
@http.request("POST", "/domains", body: body)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def verify(id_or_name)
|
|
98
|
+
@http.request("POST", "/domains/#{URI.encode_www_form_component(id_or_name)}", body: { "action" => "verify" })
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def apply(id_or_name, provider: "cloudflare", credentials: nil)
|
|
102
|
+
body = { "action" => "apply", "provider" => provider }
|
|
103
|
+
body["credentials"] = credentials if credentials
|
|
104
|
+
@http.request("POST", "/domains/#{URI.encode_www_form_component(id_or_name)}", body: body)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def update(id_or_name, **params)
|
|
108
|
+
@http.request("PATCH", "/domains/#{URI.encode_www_form_component(id_or_name)}", body: params)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def delete(id_or_name)
|
|
112
|
+
@http.request("DELETE", "/domains/#{URI.encode_www_form_component(id_or_name)}")
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
class WebhooksResource
|
|
117
|
+
def initialize(http)
|
|
118
|
+
@http = http
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def list(limit: nil, cursor: nil)
|
|
122
|
+
@http.request("GET", "/webhooks#{@http.query({ "limit" => limit, "cursor" => cursor })}")
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def get(webhook_id)
|
|
126
|
+
@http.request("GET", "/webhooks/#{URI.encode_www_form_component(webhook_id)}")
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def create(**params)
|
|
130
|
+
@http.request("POST", "/webhooks", body: params)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def update(webhook_id, **params)
|
|
134
|
+
@http.request("PATCH", "/webhooks/#{URI.encode_www_form_component(webhook_id)}", body: params)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def delete(webhook_id)
|
|
138
|
+
@http.request("DELETE", "/webhooks/#{URI.encode_www_form_component(webhook_id)}")
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
class TemplatesResource
|
|
143
|
+
def initialize(http)
|
|
144
|
+
@http = http
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def list(limit: nil, cursor: nil, status: nil)
|
|
148
|
+
@http.request(
|
|
149
|
+
"GET",
|
|
150
|
+
"/templates#{@http.query({ "limit" => limit, "cursor" => cursor, "status" => status })}"
|
|
151
|
+
)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def get(id_or_alias)
|
|
155
|
+
@http.request("GET", "/templates/#{URI.encode_www_form_component(id_or_alias)}")
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def create(**params)
|
|
159
|
+
@http.request("POST", "/templates", body: params)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def update(id_or_alias, **params)
|
|
163
|
+
@http.request("PATCH", "/templates/#{URI.encode_www_form_component(id_or_alias)}", body: params)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def delete(id_or_alias)
|
|
167
|
+
@http.request("DELETE", "/templates/#{URI.encode_www_form_component(id_or_alias)}")
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def publish(id_or_alias)
|
|
171
|
+
@http.request("POST", "/templates/#{URI.encode_www_form_component(id_or_alias)}", body: { "action" => "publish" })
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
class SuppressionsResource
|
|
176
|
+
def initialize(http)
|
|
177
|
+
@http = http
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def list(limit: nil, cursor: nil, email: nil)
|
|
181
|
+
@http.request(
|
|
182
|
+
"GET",
|
|
183
|
+
"/suppressions#{@http.query({ "limit" => limit, "cursor" => cursor, "email" => email })}"
|
|
184
|
+
)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def create(**params)
|
|
188
|
+
@http.request("POST", "/suppressions", body: params)
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def remove(id_or_email)
|
|
192
|
+
if id_or_email.include?("@")
|
|
193
|
+
return @http.request("DELETE", "/suppressions#{@http.query({ "email" => id_or_email })}")
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
@http.request("DELETE", "/suppressions/#{URI.encode_www_form_component(id_or_email)}")
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
end
|
data/lib/supersendtx.rb
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "supersendtx/version"
|
|
4
|
+
require_relative "supersendtx/error"
|
|
5
|
+
require_relative "supersendtx/http"
|
|
6
|
+
require_relative "supersendtx/resources"
|
|
7
|
+
require_relative "supersendtx/client"
|
|
8
|
+
|
|
9
|
+
module SuperSendTX
|
|
10
|
+
end
|
data/supersendtx.gemspec
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "lib/supersendtx/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = "supersendtx"
|
|
7
|
+
spec.version = SuperSendTX::VERSION
|
|
8
|
+
spec.authors = ["SuperSend TX"]
|
|
9
|
+
spec.email = ["support@supersendtx.com"]
|
|
10
|
+
|
|
11
|
+
spec.summary = "SuperSend TX transactional email API client for Ruby"
|
|
12
|
+
spec.description = "Official Ruby client for the SuperSend TX REST API."
|
|
13
|
+
spec.homepage = "https://supersendtx.com"
|
|
14
|
+
spec.license = "MIT"
|
|
15
|
+
spec.required_ruby_version = ">= 3.1.0"
|
|
16
|
+
|
|
17
|
+
spec.metadata = {
|
|
18
|
+
"homepage_uri" => spec.homepage,
|
|
19
|
+
"source_code_uri" => "https://github.com/Super-Send/supersendtx-sdks/tree/main/ruby",
|
|
20
|
+
"documentation_uri" => "https://docs.supersendtx.com/sdks/ruby",
|
|
21
|
+
"rubygems_mfa_required" => "true"
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
spec.files = Dir.chdir(__dir__) do
|
|
25
|
+
`git ls-files -z`.split("\x0").reject { |f| f.start_with?("spec/") }
|
|
26
|
+
rescue StandardError
|
|
27
|
+
Dir.glob("{lib}/**/*", base: __dir__) + ["README.md", "supersendtx.gemspec"]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
spec.require_paths = ["lib"]
|
|
31
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: supersendtx
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.8.2
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- SuperSend TX
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-07-29 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: Official Ruby client for the SuperSend TX REST API.
|
|
14
|
+
email:
|
|
15
|
+
- support@supersendtx.com
|
|
16
|
+
executables: []
|
|
17
|
+
extensions: []
|
|
18
|
+
extra_rdoc_files: []
|
|
19
|
+
files:
|
|
20
|
+
- ".gitignore"
|
|
21
|
+
- Gemfile
|
|
22
|
+
- README.md
|
|
23
|
+
- lib/supersendtx.rb
|
|
24
|
+
- lib/supersendtx/client.rb
|
|
25
|
+
- lib/supersendtx/error.rb
|
|
26
|
+
- lib/supersendtx/http.rb
|
|
27
|
+
- lib/supersendtx/resources.rb
|
|
28
|
+
- lib/supersendtx/version.rb
|
|
29
|
+
- supersendtx.gemspec
|
|
30
|
+
homepage: https://supersendtx.com
|
|
31
|
+
licenses:
|
|
32
|
+
- MIT
|
|
33
|
+
metadata:
|
|
34
|
+
homepage_uri: https://supersendtx.com
|
|
35
|
+
source_code_uri: https://github.com/Super-Send/supersendtx-sdks/tree/main/ruby
|
|
36
|
+
documentation_uri: https://docs.supersendtx.com/sdks/ruby
|
|
37
|
+
rubygems_mfa_required: 'true'
|
|
38
|
+
post_install_message:
|
|
39
|
+
rdoc_options: []
|
|
40
|
+
require_paths:
|
|
41
|
+
- lib
|
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: 3.1.0
|
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
48
|
+
requirements:
|
|
49
|
+
- - ">="
|
|
50
|
+
- !ruby/object:Gem::Version
|
|
51
|
+
version: '0'
|
|
52
|
+
requirements: []
|
|
53
|
+
rubygems_version: 3.5.22
|
|
54
|
+
signing_key:
|
|
55
|
+
specification_version: 4
|
|
56
|
+
summary: SuperSend TX transactional email API client for Ruby
|
|
57
|
+
test_files: []
|