mailx-sdk 0.1.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 +7 -0
- data/lib/mailx/client.rb +153 -0
- data/lib/mailx/error.rb +14 -0
- data/lib/mailx.rb +2 -0
- metadata +47 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: c58bfcde392e7ef326898f019436fd782aefae0b92236adf2a9d479bbe77fd3a
|
|
4
|
+
data.tar.gz: 30f3b32add0be50f4b1f4f8f2d401f6a049d612f728dbbcea923f269f13afcea
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 6c3ff61e82a0fd646f61c2c19d1be51efdb5a04f5d168c466166c541dbf479826a150a03764af75c42977b9cb4ababe70d6c1a48f656edf2c276ce9bbd5a9f13
|
|
7
|
+
data.tar.gz: 6c8eaa67ccc907907669a260c970b213def7c1ff2623d4f1f363f97f7ed2029ef32287da773b5d9cb8feeddd22ac623a2e698938ef893beac118dc9f91f91c4c
|
data/lib/mailx/client.rb
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
require "net/http"
|
|
2
|
+
require "json"
|
|
3
|
+
require "uri"
|
|
4
|
+
|
|
5
|
+
require_relative "error"
|
|
6
|
+
|
|
7
|
+
module MailX
|
|
8
|
+
class Client
|
|
9
|
+
DEFAULT_BASE_URL = "https://api.mailx.dev"
|
|
10
|
+
|
|
11
|
+
def initialize(api_key, base_url: DEFAULT_BASE_URL, max_retries: 3, http_client: nil)
|
|
12
|
+
@api_key = api_key
|
|
13
|
+
@base_url = base_url.chomp("/")
|
|
14
|
+
@max_retries = max_retries
|
|
15
|
+
@http_client = http_client
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def send_email(body)
|
|
19
|
+
request(:post, "/v1/emails", body)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def send_batch(body)
|
|
23
|
+
request(:post, "/v1/emails/batch", body)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def get_email(id)
|
|
27
|
+
request(:get, "/v1/emails/#{id}")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def list_emails(query = "")
|
|
31
|
+
request(:get, "/v1/emails#{query}")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def list_events(query = "")
|
|
35
|
+
request(:get, "/v1/events#{query}")
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def create_domain(body); request(:post, "/v1/domains", body); end
|
|
39
|
+
def get_domain(id); request(:get, "/v1/domains/#{id}"); end
|
|
40
|
+
def list_domains; request(:get, "/v1/domains"); end
|
|
41
|
+
def delete_domain(id); request(:delete, "/v1/domains/#{id}"); end
|
|
42
|
+
def verify_dkim(domain_id); request(:post, "/v1/domains/#{domain_id}/dkim/verify"); end
|
|
43
|
+
def get_spf(domain_id); request(:get, "/v1/domains/#{domain_id}/spf"); end
|
|
44
|
+
def get_dmarc(domain_id); request(:get, "/v1/domains/#{domain_id}/dmarc"); end
|
|
45
|
+
def get_bimi(domain_id); request(:get, "/v1/domains/#{domain_id}/bimi"); end
|
|
46
|
+
def verify_bimi(domain_id); request(:post, "/v1/domains/#{domain_id}/bimi/verify"); end
|
|
47
|
+
|
|
48
|
+
def create_template(body); request(:post, "/v1/templates", body); end
|
|
49
|
+
def get_template(id); request(:get, "/v1/templates/#{id}"); end
|
|
50
|
+
def list_templates; request(:get, "/v1/templates"); end
|
|
51
|
+
def update_template(id, body); request(:patch, "/v1/templates/#{id}", body); end
|
|
52
|
+
def delete_template(id); request(:delete, "/v1/templates/#{id}"); end
|
|
53
|
+
|
|
54
|
+
def create_contact(body); request(:post, "/v1/contacts", body); end
|
|
55
|
+
def get_contact(id); request(:get, "/v1/contacts/#{id}"); end
|
|
56
|
+
def list_contacts; request(:get, "/v1/contacts"); end
|
|
57
|
+
def update_contact(id, body); request(:patch, "/v1/contacts/#{id}", body); end
|
|
58
|
+
def delete_contact(id); request(:delete, "/v1/contacts/#{id}"); end
|
|
59
|
+
|
|
60
|
+
def create_audience(body); request(:post, "/v1/audiences", body); end
|
|
61
|
+
def get_audience(id); request(:get, "/v1/audiences/#{id}"); end
|
|
62
|
+
def list_audiences; request(:get, "/v1/audiences"); end
|
|
63
|
+
def delete_audience(id); request(:delete, "/v1/audiences/#{id}"); end
|
|
64
|
+
|
|
65
|
+
def create_broadcast(body); request(:post, "/v1/broadcasts", body); end
|
|
66
|
+
def get_broadcast(id); request(:get, "/v1/broadcasts/#{id}"); end
|
|
67
|
+
def list_broadcasts; request(:get, "/v1/broadcasts"); end
|
|
68
|
+
|
|
69
|
+
def get_analytics(query = ""); request(:get, "/v1/analytics#{query}"); end
|
|
70
|
+
|
|
71
|
+
def list_suppressions; request(:get, "/v1/suppressions"); end
|
|
72
|
+
def create_suppression(body); request(:post, "/v1/suppressions", body); end
|
|
73
|
+
def delete_suppression(id); request(:delete, "/v1/suppressions/#{id}"); end
|
|
74
|
+
|
|
75
|
+
def create_webhook(body); request(:post, "/v1/webhooks", body); end
|
|
76
|
+
def get_webhook(id); request(:get, "/v1/webhooks/#{id}"); end
|
|
77
|
+
def list_webhooks; request(:get, "/v1/webhooks"); end
|
|
78
|
+
def update_webhook(id, body); request(:patch, "/v1/webhooks/#{id}", body); end
|
|
79
|
+
def delete_webhook(id); request(:delete, "/v1/webhooks/#{id}"); end
|
|
80
|
+
|
|
81
|
+
private
|
|
82
|
+
|
|
83
|
+
def request(method, path, body = nil)
|
|
84
|
+
payload = body ? JSON.generate(body) : nil
|
|
85
|
+
attempt = 0
|
|
86
|
+
last_retry_after = nil
|
|
87
|
+
|
|
88
|
+
loop do
|
|
89
|
+
sleep(backoff_seconds(attempt, last_retry_after)) if attempt > 0
|
|
90
|
+
|
|
91
|
+
uri = URI.join(@base_url, path)
|
|
92
|
+
req = build_request(method, uri, payload)
|
|
93
|
+
|
|
94
|
+
status, headers, resp_body = perform(uri, req)
|
|
95
|
+
|
|
96
|
+
if status >= 200 && status < 300
|
|
97
|
+
return resp_body.nil? || resp_body.empty? ? {} : JSON.parse(resp_body)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Every MailX error response is {"error": {type, code, message,
|
|
101
|
+
# request_id}} - see internal/api/errors.go's errorBody.
|
|
102
|
+
body = resp_body && !resp_body.empty? ? (JSON.parse(resp_body) rescue {}) : {}
|
|
103
|
+
parsed = body["error"] || {}
|
|
104
|
+
retry_after = headers["retry-after"] ? headers["retry-after"].to_i : nil
|
|
105
|
+
error = APIError.new(
|
|
106
|
+
status: status,
|
|
107
|
+
type: parsed["type"] || "",
|
|
108
|
+
code: parsed["code"] || "",
|
|
109
|
+
message: parsed["message"] || "request failed with status #{status}",
|
|
110
|
+
request_id: parsed["request_id"],
|
|
111
|
+
retry_after: retry_after
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
retryable = status == 429 || status >= 500
|
|
115
|
+
if retryable && attempt < @max_retries
|
|
116
|
+
attempt += 1
|
|
117
|
+
last_retry_after = retry_after
|
|
118
|
+
next
|
|
119
|
+
end
|
|
120
|
+
raise error
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def build_request(method, uri, payload)
|
|
125
|
+
klass = { get: Net::HTTP::Get, post: Net::HTTP::Post, put: Net::HTTP::Put,
|
|
126
|
+
patch: Net::HTTP::Patch, delete: Net::HTTP::Delete }.fetch(method)
|
|
127
|
+
req = klass.new(uri)
|
|
128
|
+
req["Authorization"] = "Bearer #{@api_key}"
|
|
129
|
+
if payload
|
|
130
|
+
req["Content-Type"] = "application/json"
|
|
131
|
+
req.body = payload
|
|
132
|
+
end
|
|
133
|
+
req
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def perform(uri, req)
|
|
137
|
+
if @http_client
|
|
138
|
+
return @http_client.call(uri, req)
|
|
139
|
+
end
|
|
140
|
+
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") do |http|
|
|
141
|
+
http.request(req)
|
|
142
|
+
end
|
|
143
|
+
[res.code.to_i, res.each_header.to_h, res.body]
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def backoff_seconds(attempt, retry_after)
|
|
147
|
+
return retry_after.to_f if retry_after && retry_after > 0
|
|
148
|
+
base_ms = [1000 * (2 ** attempt), 10000].min
|
|
149
|
+
jitter_ms = rand(250)
|
|
150
|
+
(base_ms + jitter_ms) / 1000.0
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
data/lib/mailx/error.rb
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module MailX
|
|
2
|
+
class APIError < StandardError
|
|
3
|
+
attr_reader :status, :type, :code, :request_id, :retry_after
|
|
4
|
+
|
|
5
|
+
def initialize(status:, type:, code:, message:, request_id: nil, retry_after: nil)
|
|
6
|
+
super(message)
|
|
7
|
+
@status = status
|
|
8
|
+
@type = type
|
|
9
|
+
@code = code
|
|
10
|
+
@request_id = request_id
|
|
11
|
+
@retry_after = retry_after
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
data/lib/mailx.rb
ADDED
metadata
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: mailx-sdk
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- MailX
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-09-24 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: Official Ruby client for the MailX transactional email API.
|
|
14
|
+
email:
|
|
15
|
+
executables: []
|
|
16
|
+
extensions: []
|
|
17
|
+
extra_rdoc_files: []
|
|
18
|
+
files:
|
|
19
|
+
- lib/mailx.rb
|
|
20
|
+
- lib/mailx/client.rb
|
|
21
|
+
- lib/mailx/error.rb
|
|
22
|
+
homepage: https://github.com/UseMailx/mailx-ruby
|
|
23
|
+
licenses:
|
|
24
|
+
- MIT
|
|
25
|
+
metadata:
|
|
26
|
+
source_code_uri: https://github.com/UseMailx/mailx-ruby
|
|
27
|
+
bug_tracker_uri: https://github.com/UseMailx/mailx-ruby/issues
|
|
28
|
+
post_install_message:
|
|
29
|
+
rdoc_options: []
|
|
30
|
+
require_paths:
|
|
31
|
+
- lib
|
|
32
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
33
|
+
requirements:
|
|
34
|
+
- - ">="
|
|
35
|
+
- !ruby/object:Gem::Version
|
|
36
|
+
version: '2.6'
|
|
37
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
38
|
+
requirements:
|
|
39
|
+
- - ">="
|
|
40
|
+
- !ruby/object:Gem::Version
|
|
41
|
+
version: '0'
|
|
42
|
+
requirements: []
|
|
43
|
+
rubygems_version: 3.4.19
|
|
44
|
+
signing_key:
|
|
45
|
+
specification_version: 4
|
|
46
|
+
summary: Official Ruby SDK for MailX
|
|
47
|
+
test_files: []
|