mailkick 2.0.0 → 3.0.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 +11 -1
- data/LICENSE.txt +1 -1
- data/README.md +17 -11
- data/app/controllers/mailkick/subscriptions_controller.rb +20 -2
- data/app/views/mailkick/subscriptions/show.html.erb +16 -10
- data/config/routes.rb +2 -1
- data/lib/mailkick/engine.rb +2 -1
- data/lib/mailkick/version.rb +1 -1
- data/lib/mailkick.rb +3 -2
- metadata +5 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 53b4cfd8b344ad6273e734bad7531baaab340b50777e2e0590f2780b8ba72e96
|
|
4
|
+
data.tar.gz: 99d9c057e6fba352bc509368d49e4abda33fc6abd996ffef199866943e8625bf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 31c98f092a8fcf4f2deef3b6c2a1d385e1b7cc13df3d05ddaa35b9cd460c9d9fca966972abc59ba5cf20d3ff2442410ad809d109af1ddbb9c178ee14bb934701
|
|
7
|
+
data.tar.gz: 3b6b152bd2154d13fb88f5fe38d67297a4909c3b7f95b8401f7065020501f59eff2bad0642cd38be980f07df8b26506376c669d87c580886b765b521b59419bd
|
data/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
|
+
## 3.0.0 (2026-08-08)
|
|
2
|
+
|
|
3
|
+
See the [upgrade notes](https://github.com/ankane/mailkick?tab=readme-ov-file#30)
|
|
4
|
+
|
|
5
|
+
- Added `confirm_unsubscribe` option
|
|
6
|
+
- Enabled `headers` by default
|
|
7
|
+
- Improved CSP support
|
|
8
|
+
- Fixed change to key generator hash digest class
|
|
9
|
+
- Dropped support for Ruby < 3.3 and Rails < 7.2
|
|
10
|
+
|
|
1
11
|
## 2.0.0 (2025-06-23)
|
|
2
12
|
|
|
3
|
-
See the [upgrade notes](https://github.com/ankane/mailkick
|
|
13
|
+
See the [upgrade notes](https://github.com/ankane/mailkick/blob/v2.0.0/README.md#20)
|
|
4
14
|
|
|
5
15
|
- Added `prefix` option to `has_subscriptions`
|
|
6
16
|
- Switched to suppressions API for Postmark and changed default stream to `broadcast`
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
|
@@ -5,7 +5,7 @@ Email subscriptions for Rails
|
|
|
5
5
|
- Add one-click unsubscribe links and headers to your emails
|
|
6
6
|
- Fetch bounces and spam reports from your email service
|
|
7
7
|
|
|
8
|
-
**Mailkick
|
|
8
|
+
**Mailkick 3.0 was recently released** - see [how to upgrade](#upgrading)
|
|
9
9
|
|
|
10
10
|
:postbox: Check out [Ahoy Email](https://github.com/ankane/ahoy_email) for analytics
|
|
11
11
|
|
|
@@ -83,16 +83,20 @@ rails generate mailkick:views
|
|
|
83
83
|
|
|
84
84
|
which copies the view into `app/views/mailkick`.
|
|
85
85
|
|
|
86
|
+
To add a confirmation step to prevent issues with scanners, create `config/initializers/mailkick.rb` with:
|
|
87
|
+
|
|
88
|
+
```ruby
|
|
89
|
+
Mailkick.confirm_unsubscribe = true
|
|
90
|
+
```
|
|
91
|
+
|
|
86
92
|
## Unsubscribe Headers
|
|
87
93
|
|
|
88
|
-
|
|
94
|
+
One-click unsubscribe headers ([RFC 8058](https://datatracker.ietf.org/doc/html/rfc8058)) are automatically added to emails that call `mailkick_unsubscribe_url`. To disable, create `config/initializers/mailkick.rb` with:
|
|
89
95
|
|
|
90
96
|
```ruby
|
|
91
|
-
Mailkick.headers =
|
|
97
|
+
Mailkick.headers = false
|
|
92
98
|
```
|
|
93
99
|
|
|
94
|
-
Headers will automatically be added to emails that call `mailkick_unsubscribe_url`.
|
|
95
|
-
|
|
96
100
|
## Bounces and Spam Reports
|
|
97
101
|
|
|
98
102
|
Fetch bounces, spam reports, and unsubscribes from your email service. Create `config/initializers/mailkick.rb` with a method to handle opt outs.
|
|
@@ -196,7 +200,7 @@ For more control over services, set them by hand.
|
|
|
196
200
|
|
|
197
201
|
```ruby
|
|
198
202
|
Mailkick.services = [
|
|
199
|
-
Mailkick::Service::
|
|
203
|
+
Mailkick::Service::SendGrid.new(api_key: "API_KEY"),
|
|
200
204
|
Mailkick::Service::Mailchimp.new(api_key: "API_KEY", list_id: "LIST_ID")
|
|
201
205
|
]
|
|
202
206
|
```
|
|
@@ -219,18 +223,20 @@ end
|
|
|
219
223
|
|
|
220
224
|
## Upgrading
|
|
221
225
|
|
|
222
|
-
###
|
|
226
|
+
### 3.0
|
|
227
|
+
|
|
228
|
+
Versions 1.1.0-2.0.0 cause applications to use SHA1 for the key generator hash digest class if `Mailkick.secret_token` is not manually set (due to [this behavior in Rails](https://github.com/rails/rails/issues/56736)).
|
|
223
229
|
|
|
224
|
-
|
|
230
|
+
To avoid breakage when upgrading, add to `config/application.rb`:
|
|
225
231
|
|
|
226
232
|
```ruby
|
|
227
|
-
|
|
233
|
+
config.active_support.key_generator_hash_digest_class = OpenSSL::Digest::SHA1
|
|
228
234
|
```
|
|
229
235
|
|
|
230
|
-
|
|
236
|
+
Also, one-click unsubscribe headers are enabled by default. To disable, create an initializer with:
|
|
231
237
|
|
|
232
238
|
```ruby
|
|
233
|
-
Mailkick.
|
|
239
|
+
Mailkick.headers = false
|
|
234
240
|
```
|
|
235
241
|
|
|
236
242
|
## History
|
|
@@ -9,12 +9,16 @@ module Mailkick
|
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def unsubscribe
|
|
12
|
-
|
|
12
|
+
defer = Mailkick.confirm_unsubscribe && request.get? && !params[:confirmed]
|
|
13
|
+
|
|
14
|
+
subscription.delete_all unless defer
|
|
13
15
|
|
|
14
16
|
if request.post? && params["List-Unsubscribe"] == "One-Click"
|
|
15
17
|
# must not redirect according to RFC 8058
|
|
16
18
|
# could render show action instead
|
|
17
19
|
render plain: "Unsubscribe successful"
|
|
20
|
+
elsif defer
|
|
21
|
+
render :show
|
|
18
22
|
else
|
|
19
23
|
redirect_to subscription_path(params[:id])
|
|
20
24
|
end
|
|
@@ -52,14 +56,28 @@ module Mailkick
|
|
|
52
56
|
end
|
|
53
57
|
helper_method :opted_out?
|
|
54
58
|
|
|
59
|
+
def unsubscribing?
|
|
60
|
+
action_name == "unsubscribe"
|
|
61
|
+
end
|
|
62
|
+
helper_method :unsubscribing?
|
|
63
|
+
|
|
55
64
|
def subscribe_url
|
|
56
65
|
subscribe_subscription_path(params[:id])
|
|
57
66
|
end
|
|
58
67
|
helper_method :subscribe_url
|
|
59
68
|
|
|
69
|
+
# custom views created before 3.0 will use GET instead of POST
|
|
70
|
+
# add confirmed parameter to ensure unsubscribed
|
|
60
71
|
def unsubscribe_url
|
|
61
|
-
unsubscribe_subscription_path(params[:id])
|
|
72
|
+
unsubscribe_subscription_path(params[:id], {confirmed: true})
|
|
62
73
|
end
|
|
63
74
|
helper_method :unsubscribe_url
|
|
75
|
+
|
|
76
|
+
def style_nonce
|
|
77
|
+
if request.content_security_policy_nonce_directives&.include?("style-src")
|
|
78
|
+
content_security_policy_nonce
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
helper_method :style_nonce
|
|
64
82
|
end
|
|
65
83
|
end
|
|
@@ -3,33 +3,39 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<title>Subscriptions</title>
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
<%= content_tag :style, nonce: style_nonce do %>
|
|
7
7
|
body {
|
|
8
8
|
padding: 20px;
|
|
9
|
-
font-family: "Helvetica Neue", Arial, Helvetica, sans-serif;
|
|
9
|
+
font-family: system-ui, "Helvetica Neue", Arial, Helvetica, sans-serif;
|
|
10
10
|
font-size: 14px;
|
|
11
11
|
line-height: 1.4;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
a {
|
|
15
|
-
color: blue;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
14
|
.container {
|
|
19
15
|
max-width: 500px;
|
|
20
16
|
margin-left: auto;
|
|
21
17
|
margin-right: auto;
|
|
22
18
|
}
|
|
23
|
-
|
|
19
|
+
|
|
20
|
+
button {
|
|
21
|
+
cursor: pointer;
|
|
22
|
+
font: inherit;
|
|
23
|
+
padding: 5px 10px;
|
|
24
|
+
}
|
|
25
|
+
<% end %>
|
|
24
26
|
</head>
|
|
25
27
|
<body>
|
|
26
28
|
<div class="container">
|
|
27
29
|
<% if !subscribed? %>
|
|
28
30
|
<p>You are unsubscribed.</p>
|
|
29
|
-
<p><%=
|
|
31
|
+
<p><%= button_to "Resubscribe", subscribe_url %></p>
|
|
30
32
|
<% else %>
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
<% if unsubscribing? %>
|
|
34
|
+
<p>Click the button below to confirm.</p>
|
|
35
|
+
<% else %>
|
|
36
|
+
<p>You are subscribed.</p>
|
|
37
|
+
<% end %>
|
|
38
|
+
<p><%= button_to "Unsubscribe", unsubscribe_url %></p>
|
|
33
39
|
<% end %>
|
|
34
40
|
</div>
|
|
35
41
|
</body>
|
data/config/routes.rb
CHANGED
|
@@ -7,6 +7,7 @@ end
|
|
|
7
7
|
Mailkick::Engine.routes.draw do
|
|
8
8
|
resources :subscriptions, only: [:show] do
|
|
9
9
|
match :unsubscribe, on: :member, via: [:get, :post]
|
|
10
|
-
|
|
10
|
+
# support GET for custom views created before 3.0
|
|
11
|
+
match :subscribe, on: :member, via: [:get, :post]
|
|
11
12
|
end
|
|
12
13
|
end
|
data/lib/mailkick/engine.rb
CHANGED
|
@@ -5,7 +5,8 @@ module Mailkick
|
|
|
5
5
|
initializer "mailkick" do |app|
|
|
6
6
|
Mailkick.discover_services unless Mailkick.services.any?
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
# avoid app.key_generator due to https://github.com/ankane/ahoy_email/pull/168
|
|
9
|
+
Mailkick.secret_token ||= ActiveSupport::KeyGenerator.new(app.secret_key_base, iterations: 1000, hash_digest_class: OpenSSL::Digest::SHA1).generate_key("mailkick")
|
|
9
10
|
end
|
|
10
11
|
end
|
|
11
12
|
end
|
data/lib/mailkick/version.rb
CHANGED
data/lib/mailkick.rb
CHANGED
|
@@ -21,13 +21,14 @@ require_relative "mailkick/version"
|
|
|
21
21
|
require_relative "mailkick/engine" if defined?(Rails)
|
|
22
22
|
|
|
23
23
|
module Mailkick
|
|
24
|
-
mattr_accessor :services, :mount, :process_opt_outs_method, :headers
|
|
24
|
+
mattr_accessor :services, :mount, :process_opt_outs_method, :headers, :confirm_unsubscribe
|
|
25
25
|
mattr_reader :secret_token
|
|
26
26
|
mattr_writer :message_verifier
|
|
27
27
|
self.services = []
|
|
28
28
|
self.mount = true
|
|
29
29
|
self.process_opt_outs_method = ->(_) { raise "process_opt_outs_method not defined" }
|
|
30
|
-
self.headers =
|
|
30
|
+
self.headers = true
|
|
31
|
+
self.confirm_unsubscribe = false
|
|
31
32
|
|
|
32
33
|
def self.fetch_opt_outs
|
|
33
34
|
services.each(&:fetch_opt_outs)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mailkick
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 3.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrew Kane
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: '7.
|
|
18
|
+
version: '7.2'
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - ">="
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: '7.
|
|
25
|
+
version: '7.2'
|
|
26
26
|
email: andrew@ankane.org
|
|
27
27
|
executables: []
|
|
28
28
|
extensions: []
|
|
@@ -61,14 +61,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
61
61
|
requirements:
|
|
62
62
|
- - ">="
|
|
63
63
|
- !ruby/object:Gem::Version
|
|
64
|
-
version: '3.
|
|
64
|
+
version: '3.3'
|
|
65
65
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
66
66
|
requirements:
|
|
67
67
|
- - ">="
|
|
68
68
|
- !ruby/object:Gem::Version
|
|
69
69
|
version: '0'
|
|
70
70
|
requirements: []
|
|
71
|
-
rubygems_version:
|
|
71
|
+
rubygems_version: 4.0.16
|
|
72
72
|
specification_version: 4
|
|
73
73
|
summary: Email subscriptions for Rails
|
|
74
74
|
test_files: []
|