mailkick 0.0.2 → 0.0.3
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 +5 -0
- data/README.md +69 -9
- data/app/controllers/mailkick/subscriptions_controller.rb +18 -9
- data/app/views/mailkick/subscriptions/show.html.erb +4 -4
- data/lib/generators/mailkick/templates/install.rb +1 -0
- data/lib/mailkick/model.rb +33 -15
- data/lib/mailkick/processor.rb +6 -1
- data/lib/mailkick/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c06634c652c84b39afb65d63e54e58a57d212699
|
|
4
|
+
data.tar.gz: 30073ad89e0d42b83844a46822678058ca3b1bf2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 018f990ddd1c587e4fcb791fc99b3d6767aeeb8b2eae51aa9e00017432172688bba7bc1adfab45071c540ad626953ccc6216513f4a6e74a7383858b06faebb2f
|
|
7
|
+
data.tar.gz: 62cd53b3f3395af21bf18086cf131d91b8625a4cd71a889792e7f053a96722b337928dbd0160b495d459717003dfdf50760d1484eb821b57cb22b3adb901d08a
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
|
@@ -62,33 +62,39 @@ class User < ActiveRecord::Base
|
|
|
62
62
|
end
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
-
Get all users who have
|
|
65
|
+
Get all users who have opted out
|
|
66
66
|
|
|
67
67
|
```ruby
|
|
68
|
-
User.
|
|
68
|
+
User.opted_out
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
And those who have not (send to these people)
|
|
72
|
+
|
|
73
|
+
```ruby
|
|
74
|
+
User.not_opted_out
|
|
69
75
|
```
|
|
70
76
|
|
|
71
77
|
Check one user
|
|
72
78
|
|
|
73
79
|
```ruby
|
|
74
|
-
user.
|
|
80
|
+
user.opted_out?
|
|
75
81
|
```
|
|
76
82
|
|
|
77
83
|
Unsubscribe
|
|
78
84
|
|
|
79
85
|
```ruby
|
|
80
|
-
user.
|
|
86
|
+
user.opt_out
|
|
81
87
|
```
|
|
82
88
|
|
|
83
|
-
|
|
89
|
+
Resubscribe
|
|
84
90
|
|
|
85
91
|
```ruby
|
|
86
|
-
user.
|
|
92
|
+
user.opt_in
|
|
87
93
|
```
|
|
88
94
|
|
|
89
95
|
## Bounces and Spam Reports
|
|
90
96
|
|
|
91
|
-
|
|
97
|
+
Fetch bounces, spam reports, and unsubscribes from your email service.
|
|
92
98
|
|
|
93
99
|
```ruby
|
|
94
100
|
Mailkick.fetch_opt_outs
|
|
@@ -126,7 +132,7 @@ Will gladly accept pull requests.
|
|
|
126
132
|
|
|
127
133
|
### Advanced
|
|
128
134
|
|
|
129
|
-
For more control over
|
|
135
|
+
For more control over services, set them by hand.
|
|
130
136
|
|
|
131
137
|
```ruby
|
|
132
138
|
Mailkick.services = [
|
|
@@ -137,7 +143,61 @@ Mailkick.services = [
|
|
|
137
143
|
|
|
138
144
|
## Multiple Lists
|
|
139
145
|
|
|
140
|
-
|
|
146
|
+
You may want to split your emails into multiple categories, like sale emails and order reminders.
|
|
147
|
+
|
|
148
|
+
Set the list in the mailer.
|
|
149
|
+
|
|
150
|
+
```ruby
|
|
151
|
+
class UserMailer < ActionMailer::Base
|
|
152
|
+
|
|
153
|
+
def order_reminder(user)
|
|
154
|
+
header[:mailkick_list] = "order_reminders"
|
|
155
|
+
# ...
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
end
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Pass the `list` option to methods.
|
|
162
|
+
|
|
163
|
+
```ruby
|
|
164
|
+
# scopes
|
|
165
|
+
User.opted_out(list: "order_reminders")
|
|
166
|
+
User.not_opted_out(list: "order_reminders")
|
|
167
|
+
|
|
168
|
+
# instance methods
|
|
169
|
+
user.opted_out?(list: "order_reminders")
|
|
170
|
+
user.opt_out(list: "order_reminders")
|
|
171
|
+
user.opt_in(list: "order_reminders")
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Omitting list (`nil` list) means all lists - including future lists (think “Unsubscribe All”).
|
|
175
|
+
|
|
176
|
+
```ruby
|
|
177
|
+
# opted out of all lists?
|
|
178
|
+
user.opted_out?
|
|
179
|
+
|
|
180
|
+
# opted out of the order reminder list *or* all lists?
|
|
181
|
+
user.opted_out?(list: "order_reminders")
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Opt-In Lists
|
|
185
|
+
|
|
186
|
+
For opt-in lists, you’ll need to manage the subscribers yourself.
|
|
187
|
+
|
|
188
|
+
Mailkick stores opt-outs, which you can combine with opt-ins.
|
|
189
|
+
|
|
190
|
+
```ruby
|
|
191
|
+
# opt-ins minus opt-outs
|
|
192
|
+
User.where(send_me_sales: true).not_opted_out(list: "sales")
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Check one user
|
|
196
|
+
|
|
197
|
+
```ruby
|
|
198
|
+
# opted in and didn't opt out
|
|
199
|
+
user.send_me_sales && !user.opted_out?(list: "sales")
|
|
200
|
+
```
|
|
141
201
|
|
|
142
202
|
## Bonus
|
|
143
203
|
|
|
@@ -6,11 +6,12 @@ module Mailkick
|
|
|
6
6
|
end
|
|
7
7
|
|
|
8
8
|
def unsubscribe
|
|
9
|
-
if
|
|
9
|
+
if !opted_out?
|
|
10
10
|
Mailkick::OptOut.create! do |o|
|
|
11
11
|
o.email = @email
|
|
12
12
|
o.user = @user
|
|
13
13
|
o.reason = "unsubscribe"
|
|
14
|
+
o.list = @list
|
|
14
15
|
end
|
|
15
16
|
end
|
|
16
17
|
|
|
@@ -22,8 +23,8 @@ module Mailkick
|
|
|
22
23
|
opt_out.active = false
|
|
23
24
|
opt_out.save!
|
|
24
25
|
end
|
|
25
|
-
if @user and @user.respond_to?(:
|
|
26
|
-
@user.
|
|
26
|
+
if @user and @user.respond_to?(:opt_in)
|
|
27
|
+
@user.opt_in(@options)
|
|
27
28
|
end
|
|
28
29
|
|
|
29
30
|
redirect_to subscription_path(params[:id])
|
|
@@ -34,24 +35,32 @@ module Mailkick
|
|
|
34
35
|
def set_email
|
|
35
36
|
verifier = ActiveSupport::MessageVerifier.new(Mailkick.secret_token)
|
|
36
37
|
begin
|
|
37
|
-
@email, user_id, user_type = verifier.verify(params[:id])
|
|
38
|
+
@email, user_id, user_type, @list = verifier.verify(params[:id])
|
|
38
39
|
if user_type
|
|
39
40
|
# on the unprobabilistic chance user_type is compromised, not much damage
|
|
40
41
|
@user = user_type.constantize.find(user_id)
|
|
41
42
|
end
|
|
43
|
+
@options = {}
|
|
44
|
+
@options[:list] = @list if @list
|
|
42
45
|
rescue ActiveSupport::MessageVerifier::InvalidSignature
|
|
43
46
|
render text: "Subscription not found", status: :bad_request
|
|
44
47
|
end
|
|
45
48
|
end
|
|
46
49
|
|
|
47
|
-
def
|
|
48
|
-
|
|
49
|
-
|
|
50
|
+
def opted_out?(options = {})
|
|
51
|
+
options = @options.merge(options)
|
|
52
|
+
if @user and @user.respond_to?(:opted_out?)
|
|
53
|
+
@user.opted_out?(options)
|
|
50
54
|
else
|
|
51
|
-
Mailkick::OptOut.where(email: @email, active: true)
|
|
55
|
+
relation = Mailkick::OptOut.where(email: @email, active: true)
|
|
56
|
+
if options[:list]
|
|
57
|
+
relation.where("list IS NULL OR list = ?", options[:list])
|
|
58
|
+
else
|
|
59
|
+
relation.where("list IS NULL")
|
|
60
|
+
end.any?
|
|
52
61
|
end
|
|
53
62
|
end
|
|
54
|
-
helper_method :
|
|
63
|
+
helper_method :opted_out?
|
|
55
64
|
|
|
56
65
|
def subscribe_url(options = {})
|
|
57
66
|
subscribe_subscription_path(params[:id], options)
|
|
@@ -24,12 +24,12 @@
|
|
|
24
24
|
</head>
|
|
25
25
|
<body>
|
|
26
26
|
<div class="container">
|
|
27
|
-
<% if
|
|
28
|
-
<p>You are subscribed.</p>
|
|
29
|
-
<p><%= link_to "Unsubscribe", unsubscribe_url %></p>
|
|
30
|
-
<% else %>
|
|
27
|
+
<% if opted_out? %>
|
|
31
28
|
<p>You are unsubscribed.</p>
|
|
32
29
|
<p><%= link_to "Resubscribe", subscribe_url %></p>
|
|
30
|
+
<% else %>
|
|
31
|
+
<p>You are subscribed.</p>
|
|
32
|
+
<p><%= link_to "Unsubscribe", unsubscribe_url %></p>
|
|
33
33
|
<% end %>
|
|
34
34
|
</div>
|
|
35
35
|
</body>
|
data/lib/mailkick/model.rb
CHANGED
|
@@ -3,36 +3,54 @@ module Mailkick
|
|
|
3
3
|
|
|
4
4
|
def mailkick_user(options = {})
|
|
5
5
|
class_eval do
|
|
6
|
-
scope :
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
scope :opted_out, proc {|options = {}|
|
|
7
|
+
binds = [self.class.name, true]
|
|
8
|
+
if options[:list]
|
|
9
|
+
query = "(list IS NULL OR list = ?)"
|
|
10
|
+
binds << options[:list]
|
|
11
|
+
else
|
|
12
|
+
query = "list IS NULL"
|
|
13
|
+
end
|
|
14
|
+
where("#{options[:not] ? "NOT " : ""}EXISTS(SELECT * FROM mailkick_opt_outs WHERE (#{table_name}.email = mailkick_opt_outs.email OR (#{table_name}.id = mailkick_opt_outs.user_id AND mailkick_opt_outs.user_type = ?)) AND active = ? AND #{query})", *binds)
|
|
15
|
+
}
|
|
16
|
+
scope :not_opted_out, proc {|options = {}|
|
|
17
|
+
opted_out(options.merge(not: true))
|
|
18
|
+
}
|
|
11
19
|
|
|
12
|
-
def
|
|
13
|
-
|
|
20
|
+
def opt_outs(options = {})
|
|
21
|
+
relation = Mailkick::OptOut.where("email = ? OR (user_id = ? AND user_type = ?)", email, id, self.class.name)
|
|
22
|
+
if options[:list]
|
|
23
|
+
relation.where("list IS NULL OR list = ?", options[:list])
|
|
24
|
+
else
|
|
25
|
+
relation.where(list: nil)
|
|
26
|
+
end
|
|
14
27
|
end
|
|
15
28
|
|
|
16
|
-
def
|
|
17
|
-
opt_outs.where(active: true).
|
|
18
|
-
opt_out.active = false
|
|
19
|
-
opt_out.save!
|
|
20
|
-
end
|
|
21
|
-
true
|
|
29
|
+
def opted_out?(options = {})
|
|
30
|
+
opt_outs(options).where(active: true).any?
|
|
22
31
|
end
|
|
23
32
|
|
|
24
|
-
def
|
|
25
|
-
if
|
|
33
|
+
def opt_out(options = {})
|
|
34
|
+
if !opted_out?(options)
|
|
26
35
|
OptOut.create! do |o|
|
|
27
36
|
o.email = email
|
|
28
37
|
o.user = self
|
|
29
38
|
o.reason = "unsubscribe"
|
|
39
|
+
o.list = options[:list]
|
|
30
40
|
o.save!
|
|
31
41
|
end
|
|
32
42
|
end
|
|
33
43
|
true
|
|
34
44
|
end
|
|
35
45
|
|
|
46
|
+
def opt_in(options = {})
|
|
47
|
+
opt_outs(options).where(active: true).each do |opt_out|
|
|
48
|
+
opt_out.active = false
|
|
49
|
+
opt_out.save!
|
|
50
|
+
end
|
|
51
|
+
true
|
|
52
|
+
end
|
|
53
|
+
|
|
36
54
|
end
|
|
37
55
|
end
|
|
38
56
|
|
data/lib/mailkick/processor.rb
CHANGED
|
@@ -9,9 +9,14 @@ module Mailkick
|
|
|
9
9
|
def process
|
|
10
10
|
email = message.to.first
|
|
11
11
|
user = Mailkick.user_method.call(email) if Mailkick.user_method
|
|
12
|
+
list = message[:mailkick_list].try(:value)
|
|
13
|
+
if list
|
|
14
|
+
# remove header
|
|
15
|
+
message[:mailkick_list] = nil
|
|
16
|
+
end
|
|
12
17
|
|
|
13
18
|
verifier = ActiveSupport::MessageVerifier.new(Mailkick.secret_token)
|
|
14
|
-
token = verifier.generate([email, user.try(:id), user.try(:class).try(:name)])
|
|
19
|
+
token = verifier.generate([email, user.try(:id), user.try(:class).try(:name), list])
|
|
15
20
|
|
|
16
21
|
parts = message.parts.any? ? message.parts : [message]
|
|
17
22
|
parts.each do |part|
|
data/lib/mailkick/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mailkick
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrew Kane
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2014-05-
|
|
11
|
+
date: 2014-05-05 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|