mailkick 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|