millionsend 0.1.0 → 0.3.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 +4 -4
- data/README.md +38 -22
- data/lib/millionsend/broadcasts.rb +2 -1
- data/lib/millionsend/contacts.rb +18 -26
- data/lib/millionsend/deliverability.rb +14 -0
- data/lib/millionsend/emails.rb +8 -0
- data/lib/millionsend/request.rb +7 -0
- data/lib/millionsend/segments.rb +12 -12
- data/lib/millionsend/util.rb +10 -0
- data/lib/millionsend/version.rb +1 -1
- data/lib/millionsend.rb +6 -3
- metadata +6 -7
- data/lib/millionsend/audiences.rb +0 -30
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3a05f5a8a6f73d20210b65a538c84b985206374628dd5298793c01d37bd9138f
|
|
4
|
+
data.tar.gz: 7fe8ff20393c98a38072d70617e0df869aefebdb14a577db320f8514d17eca05
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ec4a59041ec45a8c620b9fa2ff618971273b0dc6ba43ba75e758cec70653978e9a428249acd52c060b79ab83cdc70b5f119b019b2407b2ce802f2407444cbee9
|
|
7
|
+
data.tar.gz: 2fc47253ed0511c373c8273f84457ad90f812db1d4d6d9df8c4d58019780e34e484681239679033f9b9d0ca435cebac24c19f23f5438c26cd92c2d388bf6be85
|
data/README.md
CHANGED
|
@@ -48,12 +48,17 @@ on any non-2xx response (see [Error handling](#error-handling)).
|
|
|
48
48
|
Millionsend.api_key = "ms_123" # falls back to ENV["MILLIONSEND_API_KEY"]
|
|
49
49
|
Millionsend.base_url = "https://mail.acme.dev" # falls back to ENV["MILLIONSEND_BASE_URL"],
|
|
50
50
|
# then http://localhost:3001
|
|
51
|
+
Millionsend.allow_insecure_http = false # accept a non-loopback http:// base_url
|
|
51
52
|
```
|
|
52
53
|
|
|
53
54
|
MillionSend is self-hosted, so there is no cloud default — **set `base_url` to your
|
|
54
55
|
deployment in production.** An explicitly assigned value always wins over the environment.
|
|
56
|
+
Plain `http://` is only accepted for loopback hosts (`localhost`, `127.0.0.1`, `::1`); any
|
|
57
|
+
other `http://` URL raises `Millionsend::ApplicationError` on the first call, since the API
|
|
58
|
+
key is sent as a bearer header. Set `allow_insecure_http = true` to talk to a non-TLS
|
|
59
|
+
instance elsewhere (e.g. inside a private network).
|
|
55
60
|
Params are symbol-keyed hashes and map straight to the wire (Ruby's snake_case is already
|
|
56
|
-
the wire's snake_case: `reply_to`, `scheduled_at`, `
|
|
61
|
+
the wire's snake_case: `reply_to`, `scheduled_at`, `segment_id`).
|
|
57
62
|
|
|
58
63
|
## Resources
|
|
59
64
|
|
|
@@ -61,7 +66,8 @@ the wire's snake_case: `reply_to`, `scheduled_at`, `audience_id`).
|
|
|
61
66
|
|
|
62
67
|
```ruby
|
|
63
68
|
Millionsend::Emails.send(payload, idempotency_key: "order-42") # POST /emails
|
|
64
|
-
Millionsend::Emails.get(id) # GET /emails/:id
|
|
69
|
+
Millionsend::Emails.get(id) # GET /emails/:id (includes score: 0-10 or nil)
|
|
70
|
+
Millionsend::Emails.get_insights(id) # GET /emails/:id/insights (404 until computed)
|
|
65
71
|
Millionsend::Emails.cancel(id) # POST /emails/:id/cancel (scheduled only)
|
|
66
72
|
|
|
67
73
|
Millionsend::Batch.send([payload_a, payload_b], idempotency_key: "run-7") # up to 100
|
|
@@ -70,28 +76,25 @@ Millionsend::Batch.send([payload_a, payload_b], idempotency_key: "run-7") # up t
|
|
|
70
76
|
`to`, `cc`, `bcc` and `reply_to` accept either a string or an array. `Emails.create` is
|
|
71
77
|
an alias of `Emails.send` (as is `Batch.create`), mirroring Resend.
|
|
72
78
|
|
|
73
|
-
###
|
|
79
|
+
### Contacts
|
|
80
|
+
|
|
81
|
+
Contacts are team-global — one list per team, no audiences.
|
|
74
82
|
|
|
75
83
|
```ruby
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
Millionsend::
|
|
79
|
-
Millionsend::
|
|
80
|
-
|
|
81
|
-
Millionsend::Contacts.
|
|
82
|
-
first_name: "Ada", properties: { plan: "pro" })
|
|
83
|
-
Millionsend::Contacts.get("ada@acme.dev", audience_id: audience[:id]) # by id or email
|
|
84
|
-
Millionsend::Contacts.get(contact_id) # top-level, by id
|
|
85
|
-
Millionsend::Contacts.update(id: contact_id, unsubscribed: true, first_name: nil) # nil clears
|
|
86
|
-
Millionsend::Contacts.remove("ada@acme.dev", audience_id: audience[:id])
|
|
87
|
-
Millionsend::Contacts.list(audience_id: audience[:id], limit: 50)
|
|
84
|
+
contact = Millionsend::Contacts.create(email: "ada@acme.dev", first_name: "Ada",
|
|
85
|
+
properties: { plan: "pro" })
|
|
86
|
+
Millionsend::Contacts.get("ada@acme.dev") # by id or email
|
|
87
|
+
Millionsend::Contacts.update(id: contact[:id], unsubscribed: true, first_name: nil) # nil clears
|
|
88
|
+
Millionsend::Contacts.remove("ada@acme.dev")
|
|
89
|
+
Millionsend::Contacts.list(limit: 50)
|
|
88
90
|
|
|
89
91
|
# Topic subscriptions (granular unsubscribe) — mirrors resend's contacts.topics.update
|
|
90
92
|
Millionsend::Contacts.topics_update("ada@acme.dev", [{ id: topic_id, subscription: "opt_out" }])
|
|
91
93
|
```
|
|
92
94
|
|
|
93
95
|
Contacts are addressable by id or email; when an `update` hash carries both, the email wins.
|
|
94
|
-
|
|
96
|
+
Emails are unique per team (case-insensitive) — a duplicate `create` raises
|
|
97
|
+
`Millionsend::ValidationError`.
|
|
95
98
|
|
|
96
99
|
### Topics
|
|
97
100
|
|
|
@@ -106,7 +109,7 @@ Millionsend::Topics.remove(id)
|
|
|
106
109
|
|
|
107
110
|
```ruby
|
|
108
111
|
broadcast = Millionsend::Broadcasts.create(
|
|
109
|
-
|
|
112
|
+
segment_id: segment[:id], # optional; omit segment_id and topic_id to send to all contacts
|
|
110
113
|
from: "Acme <news@acme.dev>",
|
|
111
114
|
subject: "Launch",
|
|
112
115
|
html: "<p>Hi {{{FIRST_NAME|there}}}</p>"
|
|
@@ -121,13 +124,12 @@ Millionsend::Broadcasts.remove(broadcast[:id]) # draft only
|
|
|
121
124
|
|
|
122
125
|
### Segments (MillionSend extension)
|
|
123
126
|
|
|
124
|
-
Dynamic segments are a saved filter over
|
|
125
|
-
no Resend equivalent
|
|
127
|
+
Dynamic segments are a saved filter over the team's contacts — a MillionSend superset with
|
|
128
|
+
no Resend equivalent.
|
|
126
129
|
|
|
127
130
|
```ruby
|
|
128
131
|
segment = Millionsend::Segments.create(
|
|
129
132
|
name: "Pro plan",
|
|
130
|
-
audience_id: audience[:id],
|
|
131
133
|
filter: { match: "all", conditions: [{ field: "property:plan", op: "equals", value: "pro" }] }
|
|
132
134
|
)
|
|
133
135
|
Millionsend::Segments.get(segment[:id]) # includes a live contact_count
|
|
@@ -136,6 +138,19 @@ Millionsend::Segments.update(segment[:id], name: "Pro tier")
|
|
|
136
138
|
Millionsend::Segments.remove(segment[:id])
|
|
137
139
|
```
|
|
138
140
|
|
|
141
|
+
### Deliverability (MillionSend extension)
|
|
142
|
+
|
|
143
|
+
Per-email best-practice insights and the account-level deliverability score.
|
|
144
|
+
|
|
145
|
+
```ruby
|
|
146
|
+
insights = Millionsend::Emails.get_insights(email[:id]) # score, band, checks: [{id:, severity:, status:, penalty:, detail:}]
|
|
147
|
+
account = Millionsend::Deliverability.get # GET /deliverability — trailing-30-day account score
|
|
148
|
+
puts account[:score] # 0-10 (one decimal) or nil when there is not enough data
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Check ids and the band/severity/status values are an open set that grows across score
|
|
152
|
+
versions — treat them as strings, not a closed enum.
|
|
153
|
+
|
|
139
154
|
## Error handling
|
|
140
155
|
|
|
141
156
|
No `{ data, error }` tuple — a non-2xx response raises. The base class is `Millionsend::Error`,
|
|
@@ -174,8 +189,9 @@ Method names, nesting and payloads match. Notes:
|
|
|
174
189
|
are no `Domains` / `ApiKeys` resources here.
|
|
175
190
|
- Resend's `Contacts.topics.update` becomes `Millionsend::Contacts.topics_update` (Ruby has no
|
|
176
191
|
nested-module method on a module function).
|
|
177
|
-
-
|
|
178
|
-
|
|
192
|
+
- **No audiences** — contacts are team-global, so there is no `Audiences` resource and no
|
|
193
|
+
`audience_id` params. `Millionsend::Segments` is the dynamic-filter feature (`/segments`),
|
|
194
|
+
not Resend's audiences alias.
|
|
179
195
|
|
|
180
196
|
## License
|
|
181
197
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Millionsend
|
|
4
|
-
# Broadcasts — one email sent to a
|
|
4
|
+
# Broadcasts — one email sent to a segment, a topic's subscribers, or every
|
|
5
|
+
# contact (pass neither segment_id nor topic_id).
|
|
5
6
|
module Broadcasts
|
|
6
7
|
class << self
|
|
7
8
|
# POST /broadcasts
|
data/lib/millionsend/contacts.rb
CHANGED
|
@@ -1,59 +1,51 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Millionsend
|
|
4
|
-
# Contacts
|
|
5
|
-
#
|
|
4
|
+
# Contacts are team-global and addressable by id or by email (email wins when
|
|
5
|
+
# an update hash carries both).
|
|
6
6
|
module Contacts
|
|
7
7
|
class << self
|
|
8
|
-
# POST /
|
|
9
|
-
# addressing, not a body field, so it is stripped from the payload.
|
|
8
|
+
# POST /contacts
|
|
10
9
|
def create(params)
|
|
11
|
-
|
|
12
|
-
Millionsend::Request.new(method: :post, path: collection_path(params[:audience_id]), body: body).perform
|
|
10
|
+
Millionsend::Request.new(method: :post, path: "/contacts", body: params).perform
|
|
13
11
|
end
|
|
14
12
|
|
|
15
13
|
# GET a single contact by id or email.
|
|
16
|
-
def get(id_or_email
|
|
17
|
-
Millionsend::Request.new(method: :get, path: member_path(id_or_email
|
|
14
|
+
def get(id_or_email)
|
|
15
|
+
Millionsend::Request.new(method: :get, path: member_path(id_or_email)).perform
|
|
18
16
|
end
|
|
19
17
|
|
|
20
|
-
# PATCH a contact. Addressing keys (:
|
|
21
|
-
#
|
|
22
|
-
#
|
|
18
|
+
# PATCH a contact. Addressing keys (:id, :email) are pulled out;
|
|
19
|
+
# everything else is the body. A nil value clears a field; omit a key to
|
|
20
|
+
# leave it unchanged.
|
|
23
21
|
def update(params)
|
|
24
22
|
key = params[:email] || params[:id]
|
|
25
|
-
body = params.reject { |k, _| [:
|
|
26
|
-
Millionsend::Request.new(method: :patch, path: member_path(key
|
|
23
|
+
body = params.reject { |k, _| [:id, :email].include?(k) }
|
|
24
|
+
Millionsend::Request.new(method: :patch, path: member_path(key), body: body).perform
|
|
27
25
|
end
|
|
28
26
|
|
|
29
27
|
# DELETE a contact by id or email.
|
|
30
|
-
def remove(id_or_email
|
|
31
|
-
Millionsend::Request.new(method: :delete, path: member_path(id_or_email
|
|
28
|
+
def remove(id_or_email)
|
|
29
|
+
Millionsend::Request.new(method: :delete, path: member_path(id_or_email)).perform
|
|
32
30
|
end
|
|
33
31
|
|
|
34
|
-
# GET
|
|
32
|
+
# GET /contacts — accepts limit:/after:/before:.
|
|
35
33
|
def list(options = {})
|
|
36
34
|
Millionsend::Request.new(
|
|
37
|
-
method: :get, path:
|
|
35
|
+
method: :get, path: "/contacts", query: Millionsend::Util.list_query(options)
|
|
38
36
|
).perform
|
|
39
37
|
end
|
|
40
38
|
|
|
41
39
|
# PATCH /contacts/:id_or_email/topics with a bare array of
|
|
42
40
|
# { id:, subscription: }. Mirrors resend-ruby's contacts.topics.update.
|
|
43
41
|
def topics_update(id_or_email, topics)
|
|
44
|
-
path
|
|
45
|
-
Millionsend::Request.new(method: :patch, path: path, body: topics).perform
|
|
42
|
+
Millionsend::Request.new(method: :patch, path: "#{member_path(id_or_email)}/topics", body: topics).perform
|
|
46
43
|
end
|
|
47
44
|
|
|
48
45
|
private
|
|
49
46
|
|
|
50
|
-
def
|
|
51
|
-
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def member_path(id_or_email, audience_id)
|
|
55
|
-
key = Millionsend::Util.encode(id_or_email)
|
|
56
|
-
audience_id ? "/audiences/#{Millionsend::Util.encode(audience_id)}/contacts/#{key}" : "/contacts/#{key}"
|
|
47
|
+
def member_path(id_or_email)
|
|
48
|
+
"/contacts/#{Millionsend::Util.encode(id_or_email)}"
|
|
57
49
|
end
|
|
58
50
|
end
|
|
59
51
|
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Millionsend
|
|
4
|
+
# Account-level deliverability score over the trailing window
|
|
5
|
+
# (scores are 0-10, one decimal; null means not enough data).
|
|
6
|
+
module Deliverability
|
|
7
|
+
class << self
|
|
8
|
+
# GET /deliverability
|
|
9
|
+
def get
|
|
10
|
+
Millionsend::Request.new(method: :get, path: "/deliverability").perform
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
data/lib/millionsend/emails.rb
CHANGED
|
@@ -20,6 +20,14 @@ module Millionsend
|
|
|
20
20
|
Millionsend::Request.new(method: :get, path: "/emails/#{Millionsend::Util.encode(id)}").perform
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
+
# GET /emails/:id/insights — the pre-send best-practice report computed
|
|
24
|
+
# when the email was sent. 404 when the email is unknown or has no
|
|
25
|
+
# insights yet. Check ids and band/severity/status values are an open
|
|
26
|
+
# set that grows across score versions; they arrive as plain strings.
|
|
27
|
+
def get_insights(id)
|
|
28
|
+
Millionsend::Request.new(method: :get, path: "/emails/#{Millionsend::Util.encode(id)}/insights").perform
|
|
29
|
+
end
|
|
30
|
+
|
|
23
31
|
# POST /emails/:id/cancel — scheduled, unsent emails only.
|
|
24
32
|
def cancel(id)
|
|
25
33
|
Millionsend::Request.new(method: :post, path: "/emails/#{Millionsend::Util.encode(id)}/cancel").perform
|
data/lib/millionsend/request.rb
CHANGED
|
@@ -65,6 +65,13 @@ module Millionsend
|
|
|
65
65
|
def build_uri
|
|
66
66
|
base = Millionsend.base_url.to_s.sub(%r{/+\z}, "")
|
|
67
67
|
uri = URI.parse("#{base}#{@path}")
|
|
68
|
+
if !Millionsend.allow_insecure_http && Millionsend::Util.insecure_http?(uri)
|
|
69
|
+
raise Millionsend::ApplicationError.new(
|
|
70
|
+
"Refusing to send the API key over plain http to #{base}. " \
|
|
71
|
+
"Use https, or set Millionsend.allow_insecure_http = true.",
|
|
72
|
+
nil, "application_error"
|
|
73
|
+
)
|
|
74
|
+
end
|
|
68
75
|
query = (@query || {}).reject { |_, v| v.nil? }
|
|
69
76
|
uri.query = URI.encode_www_form(query) unless query.empty?
|
|
70
77
|
uri
|
data/lib/millionsend/segments.rb
CHANGED
|
@@ -1,35 +1,35 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Millionsend
|
|
4
|
-
# Dynamic segments — a saved filter over
|
|
5
|
-
# extension with no Resend equivalent
|
|
4
|
+
# Dynamic segments — a saved filter over the team's contacts. A MillionSend
|
|
5
|
+
# extension with no Resend equivalent.
|
|
6
6
|
module Segments
|
|
7
7
|
class << self
|
|
8
|
-
# POST /
|
|
8
|
+
# POST /segments
|
|
9
9
|
def create(params)
|
|
10
|
-
Millionsend::Request.new(method: :post, path: "/
|
|
10
|
+
Millionsend::Request.new(method: :post, path: "/segments", body: params).perform
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
# GET /
|
|
13
|
+
# GET /segments/:id — also returns a live contact_count.
|
|
14
14
|
def get(id)
|
|
15
|
-
Millionsend::Request.new(method: :get, path: "/
|
|
15
|
+
Millionsend::Request.new(method: :get, path: "/segments/#{Millionsend::Util.encode(id)}").perform
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
# GET /
|
|
18
|
+
# GET /segments — accepts limit:/after:/before:.
|
|
19
19
|
def list(options = {})
|
|
20
20
|
Millionsend::Request.new(
|
|
21
|
-
method: :get, path: "/
|
|
21
|
+
method: :get, path: "/segments", query: Millionsend::Util.list_query(options)
|
|
22
22
|
).perform
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
-
# PATCH /
|
|
25
|
+
# PATCH /segments/:id
|
|
26
26
|
def update(id, params)
|
|
27
|
-
Millionsend::Request.new(method: :patch, path: "/
|
|
27
|
+
Millionsend::Request.new(method: :patch, path: "/segments/#{Millionsend::Util.encode(id)}", body: params).perform
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
# DELETE /
|
|
30
|
+
# DELETE /segments/:id
|
|
31
31
|
def remove(id)
|
|
32
|
-
Millionsend::Request.new(method: :delete, path: "/
|
|
32
|
+
Millionsend::Request.new(method: :delete, path: "/segments/#{Millionsend::Util.encode(id)}").perform
|
|
33
33
|
end
|
|
34
34
|
end
|
|
35
35
|
end
|
data/lib/millionsend/util.rb
CHANGED
|
@@ -16,6 +16,16 @@ module Millionsend
|
|
|
16
16
|
URI.encode_www_form_component(value.to_s).gsub("+", "%20")
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
+
LOOPBACK_HOSTS = %w[localhost 127.0.0.1 ::1].freeze
|
|
20
|
+
|
|
21
|
+
# True for an http:// URI whose host is not loopback.
|
|
22
|
+
def insecure_http?(uri)
|
|
23
|
+
return false unless uri.scheme == "http"
|
|
24
|
+
|
|
25
|
+
host = uri.host.to_s.downcase
|
|
26
|
+
!LOOPBACK_HOSTS.include?(host) && !host.start_with?("127.")
|
|
27
|
+
end
|
|
28
|
+
|
|
19
29
|
# The keyset pagination params every list endpoint accepts. nil values are
|
|
20
30
|
# dropped when the query string is built.
|
|
21
31
|
def list_query(options)
|
data/lib/millionsend/version.rb
CHANGED
data/lib/millionsend.rb
CHANGED
|
@@ -6,11 +6,11 @@ require "millionsend/error"
|
|
|
6
6
|
require "millionsend/request"
|
|
7
7
|
require "millionsend/emails"
|
|
8
8
|
require "millionsend/batch"
|
|
9
|
-
require "millionsend/audiences"
|
|
10
9
|
require "millionsend/contacts"
|
|
11
10
|
require "millionsend/topics"
|
|
12
11
|
require "millionsend/broadcasts"
|
|
13
12
|
require "millionsend/segments"
|
|
13
|
+
require "millionsend/deliverability"
|
|
14
14
|
|
|
15
15
|
# Ruby client for the MillionSend HTTP API. Configure once, then call the
|
|
16
16
|
# resource modules:
|
|
@@ -22,14 +22,17 @@ require "millionsend/segments"
|
|
|
22
22
|
#
|
|
23
23
|
# api_key falls back to the MILLIONSEND_API_KEY env var; base_url to
|
|
24
24
|
# MILLIONSEND_BASE_URL and then http://localhost:3001 (MillionSend is
|
|
25
|
-
# self-hosted, so there is no cloud default).
|
|
26
|
-
#
|
|
25
|
+
# self-hosted, so there is no cloud default). Plain http is only accepted for
|
|
26
|
+
# loopback hosts unless allow_insecure_http is set, since the API key travels
|
|
27
|
+
# as a bearer header. Every call returns a symbol-keyed Hash on success and
|
|
28
|
+
# raises a Millionsend::Error on any non-2xx response.
|
|
27
29
|
module Millionsend
|
|
28
30
|
DEFAULT_BASE_URL = "http://localhost:3001"
|
|
29
31
|
USER_AGENT = "millionsend-ruby/#{VERSION}"
|
|
30
32
|
|
|
31
33
|
class << self
|
|
32
34
|
attr_writer :api_key, :base_url
|
|
35
|
+
attr_accessor :allow_insecure_http
|
|
33
36
|
|
|
34
37
|
def api_key
|
|
35
38
|
@api_key || ENV["MILLIONSEND_API_KEY"]
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: millionsend
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- MillionSend
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-08-
|
|
11
|
+
date: 2026-08-31 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rake
|
|
@@ -52,10 +52,9 @@ dependencies:
|
|
|
52
52
|
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
54
|
version: '3.19'
|
|
55
|
-
description: 'Ruby client for the MillionSend HTTP API: emails, batch,
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
a base_url.'
|
|
55
|
+
description: 'Ruby client for the MillionSend HTTP API: emails, batch, contacts, topics,
|
|
56
|
+
broadcasts, and dynamic segments. Wire-compatible with Resend and mirror-shaped
|
|
57
|
+
after resend-ruby, so migrating is mostly an import swap plus a base_url.'
|
|
59
58
|
email:
|
|
60
59
|
executables: []
|
|
61
60
|
extensions: []
|
|
@@ -64,10 +63,10 @@ files:
|
|
|
64
63
|
- LICENSE
|
|
65
64
|
- README.md
|
|
66
65
|
- lib/millionsend.rb
|
|
67
|
-
- lib/millionsend/audiences.rb
|
|
68
66
|
- lib/millionsend/batch.rb
|
|
69
67
|
- lib/millionsend/broadcasts.rb
|
|
70
68
|
- lib/millionsend/contacts.rb
|
|
69
|
+
- lib/millionsend/deliverability.rb
|
|
71
70
|
- lib/millionsend/emails.rb
|
|
72
71
|
- lib/millionsend/error.rb
|
|
73
72
|
- lib/millionsend/request.rb
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Millionsend
|
|
4
|
-
# Audiences — named contact lists (Resend-compatible).
|
|
5
|
-
module Audiences
|
|
6
|
-
class << self
|
|
7
|
-
# POST /audiences
|
|
8
|
-
def create(params)
|
|
9
|
-
Millionsend::Request.new(method: :post, path: "/audiences", body: { name: params[:name] }).perform
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
# GET /audiences/:id
|
|
13
|
-
def get(id)
|
|
14
|
-
Millionsend::Request.new(method: :get, path: "/audiences/#{Millionsend::Util.encode(id)}").perform
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
# GET /audiences — accepts limit:/after:/before:.
|
|
18
|
-
def list(options = {})
|
|
19
|
-
Millionsend::Request.new(
|
|
20
|
-
method: :get, path: "/audiences", query: Millionsend::Util.list_query(options)
|
|
21
|
-
).perform
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
# DELETE /audiences/:id
|
|
25
|
-
def remove(id)
|
|
26
|
-
Millionsend::Request.new(method: :delete, path: "/audiences/#{Millionsend::Util.encode(id)}").perform
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|