mailtea 0.4.0 → 0.5.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/CHANGELOG.md +77 -0
- data/README.md +1 -1
- data/lib/mailtea/automations.rb +8 -2
- data/lib/mailtea/posts.rb +13 -4
- data/lib/mailtea/templates.rb +34 -16
- data/lib/mailtea/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3539cea90528dd0db53f91ddaf0897c093ce83f6ec75ccac90666ba24fb6dcd9
|
|
4
|
+
data.tar.gz: e1f33edadd5e115d42f3d3294d589034d76bb29e870dbe5c952c06fc11fab42e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: abc137144ae2f95a8a881005409eeff50142404f8b9ba35043482f2780d80c4e2e887263c1953c16b79f39bbd3ec364c484e8cd95c0541978c1d3746a3878c56
|
|
7
|
+
data.tar.gz: 56f72ee40bb049f99e4d95fc58c78539fa6da22109b25d6bbf7c6af87a08fa9109e7cb33f3bd72a787e6559067f5db97f6382ab00372b9b42ae8866e1db16b14
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,83 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to the `mailtea` Ruby gem are documented here.
|
|
4
4
|
|
|
5
|
+
## 0.5.0 (2026-09-28)
|
|
6
|
+
|
|
7
|
+
- Breaking: `Posts#create` with `template_id` now HTML-escapes the `variables`
|
|
8
|
+
you pass, the same as every other send. HTML passed in a `{{key}}` value now
|
|
9
|
+
arrives as visible text, and a value you escaped yourself arrives
|
|
10
|
+
double-escaped. Put `{{{key}}}` in the template where a value is meant to be
|
|
11
|
+
raw HTML. Variables are now filled in both the `{{key}}` and Visual Email
|
|
12
|
+
Designer `{key}` forms. A declared variable you do not pass stays in the
|
|
13
|
+
post with its `fallback_value`, so the broadcast gives each recipient their
|
|
14
|
+
own value or that fallback, and undeclared tokens like
|
|
15
|
+
`{{contact.first_name}}` are left for the broadcast too. The post keeps the
|
|
16
|
+
template's published page style, is wrapped in that page, and has its
|
|
17
|
+
show-if blocks decided per recipient when it is sent. Before, only the
|
|
18
|
+
variables you passed were replaced, raw, and only in `{{key}}` form. It uses
|
|
19
|
+
the template's published version; Mailtea Studio's "Use template" starts
|
|
20
|
+
from the latest saved design instead.
|
|
21
|
+
- Changed: `Templates#update` and `Templates#restore_version` no longer move a
|
|
22
|
+
published template back to draft. The template keeps its published status,
|
|
23
|
+
and automations and the API keep sending its published version until
|
|
24
|
+
`Templates#publish` is called again. The template's `from` and `reply_to`
|
|
25
|
+
are part of the published version too, so a new sender or reply-to address
|
|
26
|
+
reaches sends only after the next publish. `Templates#unpublish` is now the
|
|
27
|
+
only way to stop a published template sending, short of deleting it, and it
|
|
28
|
+
drops the stored published version so the next publish starts from the
|
|
29
|
+
current content.
|
|
30
|
+
- Added: `has_unpublished_versions` on every returned template hash. True only
|
|
31
|
+
when the template is published and its saved content (From, Reply-To and the style profile
|
|
32
|
+
included) differs from the published version.
|
|
33
|
+
- Added: `is_published` on each template version entry: true for the one entry
|
|
34
|
+
automations and the API are sending now. `is_current` is now described as
|
|
35
|
+
what it is: the entry that matches the working copy (the saved design being
|
|
36
|
+
edited), not necessarily what is sending. `is_published` is false on every
|
|
37
|
+
entry of a draft, and on a template published before the field existed until
|
|
38
|
+
it is published again.
|
|
39
|
+
- Changed: the `unpublished` key on the update and restore replies is kept for
|
|
40
|
+
compatibility and is now always `false`. Check `has_unpublished_versions`
|
|
41
|
+
(or the reply's `message`) instead.
|
|
42
|
+
- Changed (API behavior): a template variable's `fallback_value` can no longer
|
|
43
|
+
contain `{` or `}`. Creating a template with one, or changing a fallback
|
|
44
|
+
to one on update, is a 400 ("Fallbacks can't contain { or }."). A value
|
|
45
|
+
the template already stores is accepted unchanged, so a template saved
|
|
46
|
+
before the rule keeps saving. Inline chip fallbacks such as
|
|
47
|
+
`{first_name|Mom & Pop}` now render as written instead of double-escaped.
|
|
48
|
+
- Changed (API behavior): saving an active automation is refused only when the
|
|
49
|
+
edit adds an error the live version does not already have. The 422
|
|
50
|
+
`active_graph_invalid` reply's `issues` lists just those new problems.
|
|
51
|
+
Before, any error refused the save, even one the live version already had.
|
|
52
|
+
Starting refuses every error as before, except an `unknown_step_ref` at a
|
|
53
|
+
`config.*` path or a trigger `missing_branch` that the version the
|
|
54
|
+
automation last ran on already had, so pausing and starting an unchanged
|
|
55
|
+
automation keeps working. Issues the last live version already had come back
|
|
56
|
+
with `pre_existing: true`.
|
|
57
|
+
- Added (API behavior): issue objects carry `field`, what a rule reads (the
|
|
58
|
+
rule's `field`, or the path in a `{"var": ...}` value, e.g.
|
|
59
|
+
`steps.welcome.opened`) when the issue is about one.
|
|
60
|
+
- Changed (API behavior): two issues are the same problem when their code and
|
|
61
|
+
step match, and their `field` or, when there is none, their `path`. Moving
|
|
62
|
+
a rule, by removing a rule beside it or putting it in a group, no longer
|
|
63
|
+
makes a problem the live version already had look new. An error is
|
|
64
|
+
`pre_existing` only if the live version had an error there, not a warning.
|
|
65
|
+
- Changed (API behavior): `validate_only` on an active automation answers the
|
|
66
|
+
way the save would. A trigger change is a 422 `trigger_locked_while_active`,
|
|
67
|
+
a change that adds a problem is a 422 `active_graph_invalid` listing only
|
|
68
|
+
the new problems, and otherwise issues come back with `pre_existing` marked
|
|
69
|
+
against the version live now. Before, it returned every issue unmarked.
|
|
70
|
+
- Changed (API behavior): changing the trigger (its type or key) of an active
|
|
71
|
+
automation is now refused with 422 `trigger_locked_while_active`. Pause it
|
|
72
|
+
first; draft and paused automations can still change their trigger. Before,
|
|
73
|
+
the change was accepted.
|
|
74
|
+
- Added (API behavior): new validation rules. A trigger with nothing after it
|
|
75
|
+
is a `missing_branch` error at `branches.next`. A rule or `{"var": ...}`
|
|
76
|
+
value that reads `steps.<key>.*` for a step that isn't in the automation is
|
|
77
|
+
an `unknown_step_ref` error at that `config.*` path, or a warning when the
|
|
78
|
+
`{"var": ...}` has a `default`. A rule or value that reads
|
|
79
|
+
`event.properties.*` when the automation does not start from an app event is
|
|
80
|
+
the new warning `event_field_without_event_trigger`.
|
|
81
|
+
|
|
5
82
|
## 0.4.0 (2026-09-15)
|
|
6
83
|
|
|
7
84
|
- Added: test mode. `mailtea.api_keys.create(name: "CI", mode: "test")` mints a
|
data/README.md
CHANGED
|
@@ -139,7 +139,7 @@ mailtea = Mailtea::Client.new(ENV["MAILTEA_API_KEY"], transport: recorder)
|
|
|
139
139
|
| `templates.create / list / get / update / publish / unpublish / duplicate / delete` | Manage reusable email templates |
|
|
140
140
|
| `templates.render(params)` | Render a spec to HTML without saving → `{ "html", "text" }` |
|
|
141
141
|
| `templates.versions(id, params = nil)` | List a template's design history, newest first (metadata only) |
|
|
142
|
-
| `templates.restore_version(id, version, params = nil)` | Put an older design back
|
|
142
|
+
| `templates.restore_version(id, version, params = nil)` | Put an older design back as unpublished changes; a published template keeps sending its published version until you `publish` again |
|
|
143
143
|
| `assets.upload / list / delete` | The publication's image library (raw bytes are base64-encoded for you) |
|
|
144
144
|
| `suppressions.list / add / remove` | Manage the team-wide do-not-send list |
|
|
145
145
|
| `suppressions.export` | Export the whole suppression list as CSV (raw text) |
|
data/lib/mailtea/automations.rb
CHANGED
|
@@ -59,7 +59,11 @@ module Mailtea
|
|
|
59
59
|
#
|
|
60
60
|
# <tt>validate_only: true</tt> returns an +automation_validation+ and writes
|
|
61
61
|
# nothing. A graph change that carries errors saves anyway while the
|
|
62
|
-
# automation is draft/paused/archived
|
|
62
|
+
# automation is draft/paused/archived. On an +active+ one it is a 422
|
|
63
|
+
# +active_graph_invalid+ only when it adds an error the live version does
|
|
64
|
+
# not already have; +issues+ then lists just those new problems, and older
|
|
65
|
+
# ones come back with <tt>pre_existing: true</tt>. Changing an +active+
|
|
66
|
+
# automation's trigger is a 422 +trigger_locked_while_active+. Either way:
|
|
63
67
|
# pause, save, then start again.
|
|
64
68
|
def update(id, params = nil, **fields)
|
|
65
69
|
scope, body = Util.split_publication(payload(params, fields), keep_in_body: false)
|
|
@@ -75,7 +79,9 @@ module Mailtea
|
|
|
75
79
|
|
|
76
80
|
# Start the automation so new contacts enroll. Requires +publication_id+. A
|
|
77
81
|
# graph with errors is refused with 422 +automation_invalid+ and the
|
|
78
|
-
# blocking +issues
|
|
82
|
+
# blocking +issues+, except an +unknown_step_ref+ at a <tt>config.*</tt>
|
|
83
|
+
# path or a trigger +missing_branch+ that the version it last ran on
|
|
84
|
+
# already had (<tt>pre_existing: true</tt>).
|
|
79
85
|
def activate(id, params = nil, **filters)
|
|
80
86
|
request("POST", "/v1/automations/" + escape(id) + "/activate" + query(payload(params, filters)))
|
|
81
87
|
end
|
data/lib/mailtea/posts.rb
CHANGED
|
@@ -7,10 +7,19 @@ module Mailtea
|
|
|
7
7
|
# <tt>mailtea.posts</tt>.
|
|
8
8
|
class Posts < Resource
|
|
9
9
|
# Create a newsletter post (a draft by default). Seed it from a published
|
|
10
|
-
# server template with +template_id+ + +variables+,
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
10
|
+
# server template with +template_id+ + +variables+, using the template's
|
|
11
|
+
# PUBLISHED version and not any unpublished edits saved since, or pass
|
|
12
|
+
# inline +html+. The +variables+ you pass are filled in, in both the
|
|
13
|
+
# <tt>{{key}}</tt> and Visual Email Designer <tt>{key}</tt> forms, and
|
|
14
|
+
# HTML-escaped (use <tt>{{{key}}}</tt> in the template for raw HTML).
|
|
15
|
+
# Everything else is left for the broadcast to fill per recipient: a
|
|
16
|
+
# declared variable you do not pass keeps its +fallback_value+ for
|
|
17
|
+
# recipients with no value, and undeclared tokens like
|
|
18
|
+
# <tt>{{contact.first_name}}</tt> stay as they are. The post keeps the
|
|
19
|
+
# template's published page style. +kind+ selects the post type
|
|
20
|
+
# ("newsletter" or "broadcast"). Set <tt>send: true</tt> to deliver right
|
|
21
|
+
# after creating (or with +scheduled_at+ to schedule); that requires the
|
|
22
|
+
# +issues:send+ scope.
|
|
14
23
|
#
|
|
15
24
|
# Returns <tt>{ "id" => ... }</tt>.
|
|
16
25
|
def create(params = nil, publication_id: UNSET, subject: UNSET, html: UNSET,
|
data/lib/mailtea/templates.rb
CHANGED
|
@@ -46,6 +46,13 @@ module Mailtea
|
|
|
46
46
|
# +global_css+, +category+, +preview_image_url+, +tags+, +text+, +subject+,
|
|
47
47
|
# +from+ and +reply_to+ accept +nil+ to clear them. +publication_id+ is
|
|
48
48
|
# required and goes in the query string.
|
|
49
|
+
#
|
|
50
|
+
# Editing a published template no longer unpublishes it: the change is
|
|
51
|
+
# saved as the working copy, the template keeps its published status, and
|
|
52
|
+
# the published version keeps sending until #publish is called again. The
|
|
53
|
+
# reply's +unpublished+ is kept for compatibility and is always +false+
|
|
54
|
+
# now; check +has_unpublished_versions+ on the reply instead (it also
|
|
55
|
+
# carries +message+ when that is +true+).
|
|
49
56
|
def update(id, params = nil, **fields)
|
|
50
57
|
scope, body = Util.split_publication(payload(params, fields))
|
|
51
58
|
request("PATCH", "/v1/templates/" + escape(id) + scope, body)
|
|
@@ -57,8 +64,11 @@ module Mailtea
|
|
|
57
64
|
end
|
|
58
65
|
|
|
59
66
|
# Return a published template to draft. +published_at+ is kept — it records
|
|
60
|
-
# that the template was published once, not that it still is.
|
|
61
|
-
#
|
|
67
|
+
# that the template was published once, not that it still is. This is now
|
|
68
|
+
# the only way to stop a published template sending, short of deleting it
|
|
69
|
+
# (editing or restoring it no longer does that on its own). It also drops
|
|
70
|
+
# the published version, so the next #publish starts from the current
|
|
71
|
+
# (working) content. Requires +publication_id+.
|
|
62
72
|
def unpublish(id, params = nil, **filters)
|
|
63
73
|
request("POST", "/v1/templates/" + escape(id) + "/unpublish" + query(payload(params, filters)))
|
|
64
74
|
end
|
|
@@ -66,13 +76,18 @@ module Mailtea
|
|
|
66
76
|
# List a template's design history, newest first. Requires +publication_id+;
|
|
67
77
|
# optional +limit+ (the server caps it at the retained maximum).
|
|
68
78
|
#
|
|
69
|
-
# Entries are metadata only
|
|
79
|
+
# Entries are metadata only: +version+, +origin+ ("edit", "publish" or
|
|
70
80
|
# "restore"), +restored_from_version+, +format+, +name+, +sealed+,
|
|
71
|
-
# +is_current+, +created_at+, +updated_at+ and +author+ (or
|
|
72
|
-
# design document,
|
|
73
|
-
# +is_current+ marks the
|
|
74
|
-
# not always the newest entry: a
|
|
75
|
-
# without recording a version.
|
|
81
|
+
# +is_current+, +is_published+, +created_at+, +updated_at+ and +author+ (or
|
|
82
|
+
# nil). The design document is never included, because one entry alone can
|
|
83
|
+
# carry half a megabyte of it. +is_current+ marks the entry that matches the working copy
|
|
84
|
+
# (the saved design being edited), which is not always the newest entry: a
|
|
85
|
+
# metadata-only update touches the template without recording a version.
|
|
86
|
+
# +is_published+ (a boolean) marks the entry automations and the API are
|
|
87
|
+
# sending now. They differ while a published template has unpublished
|
|
88
|
+
# changes. +is_published+ is +false+ on every entry of a draft, and on every
|
|
89
|
+
# entry of a template published before the field existed until it is
|
|
90
|
+
# published again.
|
|
76
91
|
#
|
|
77
92
|
# The reply also carries +retention+: only the newest +max_versions+ are
|
|
78
93
|
# kept, and consecutive edits by the same author within
|
|
@@ -84,10 +99,13 @@ module Mailtea
|
|
|
84
99
|
# Put an older design from #versions back onto the template. Requires
|
|
85
100
|
# +publication_id+.
|
|
86
101
|
#
|
|
87
|
-
# *Restoring
|
|
88
|
-
#
|
|
89
|
-
#
|
|
90
|
-
#
|
|
102
|
+
# *Restoring no longer unpublishes the template.* It is a content write,
|
|
103
|
+
# and lands in the working copy: a published template keeps its published
|
|
104
|
+
# status and keeps sending its published version until #publish makes the
|
|
105
|
+
# restored design live. The reply's +unpublished+ is kept for
|
|
106
|
+
# compatibility and is always +false+ now; check +has_unpublished_versions+
|
|
107
|
+
# on the returned +template+ (or the reply's +message+) to see whether the
|
|
108
|
+
# restored design is live yet.
|
|
91
109
|
#
|
|
92
110
|
# History is forward-only: the design being replaced is recorded as its own
|
|
93
111
|
# version first, then the restored design is appended as the new newest one.
|
|
@@ -96,10 +114,10 @@ module Mailtea
|
|
|
96
114
|
#
|
|
97
115
|
# Restoring the design that is already current writes nothing and returns
|
|
98
116
|
# <tt>restored: false</tt> with <tt>reason: "identical"</tt> and
|
|
99
|
-
# <tt>unpublished: false</tt
|
|
100
|
-
#
|
|
101
|
-
#
|
|
102
|
-
#
|
|
117
|
+
# <tt>unpublished: false</tt>. A version that has aged out of retention
|
|
118
|
+
# raises Mailtea::Error with +code+ "template_version_not_found". Returns
|
|
119
|
+
# +restored+, +restored_from_version+, +unpublished+, +message+ and the
|
|
120
|
+
# updated +template+.
|
|
103
121
|
def restore_version(id, version, params = nil, **filters)
|
|
104
122
|
request(
|
|
105
123
|
"POST",
|
data/lib/mailtea/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mailtea
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mailtea
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-09-
|
|
11
|
+
date: 2026-09-28 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: 'The official Ruby SDK for Mailtea: a thin, zero-dependency wrapper over
|
|
14
14
|
the Mailtea REST API, built on net/http and json.'
|