mailkick 0.4.3 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5a3e1a782d63a1ad223871a87aab2875c73c1a7860f614801184d005113d4d82
4
- data.tar.gz: 802fdb1f89e3ca6c25761bb61fd085b1936336ea5fd6bc6a020a1b79a21859c0
3
+ metadata.gz: 2ff139814252a1c4ec153cc81f311dd5d8c1745a4970aaab8cb2164df4d4692d
4
+ data.tar.gz: 1e4700dc2dbb96dcb09c4c79c00a837de387c8712db72c3bc13150ea94355da2
5
5
  SHA512:
6
- metadata.gz: e93ee8b3bcf05fa1536141e2f9ef639e30efd236eb9d280bb88bc7e234f6a6aa9a246eb91bd6aee188c74226e11cf0cdcb67e636ffafeb76f525f89096ec5eda
7
- data.tar.gz: 23441f577b0f294a46f47e61cc66c994a319d1e3d89ff310bd26d997c5b6bdbd2270318fda74de96e588f7da58691c63d3c188853be382a41a3608803034435d
6
+ metadata.gz: f28ec4a1bb1fa022ad4bd9a250a45650562db467a7c6d14f0150e5f9c8137cd766376a605c0304092ff7036d2efca22ae95e3d61e5693d40f616205b54aedb72
7
+ data.tar.gz: 5eb0a1544b00da879c77c2919501c2b21f6c4916e7bc1b710ad271c33ba6cd9cd6607d5d8c06f64380ce825f11187ff841deb21c58cd9ee4a8af3536ff3f594b
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 1.0.0 (2021-06-03)
2
+
3
+ - Switched from opt-outs to subscriptions
4
+
1
5
  ## 0.4.3 (2020-11-01)
2
6
 
3
7
  - Added support for AWS SES
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2014-2019 Andrew Kane
1
+ Copyright (c) 2014-2021 Andrew Kane
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -1,14 +1,15 @@
1
1
  # Mailkick
2
2
 
3
- Email unsubscribes for Rails
3
+ Email subscriptions for Rails
4
4
 
5
5
  - Add one-click unsubscribe links to your emails
6
6
  - Fetch bounces and spam reports from your email service
7
- - Gracefully handles email address changes
7
+
8
+ **Mailkick 1.0 was recently released** - see [how to upgrade](#upgrading)
8
9
 
9
10
  :postbox: Check out [Ahoy Email](https://github.com/ankane/ahoy_email) for analytics
10
11
 
11
- [![Build Status](https://travis-ci.org/ankane/mailkick.svg?branch=master)](https://travis-ci.org/ankane/mailkick)
12
+ [![Build Status](https://github.com/ankane/mailkick/workflows/build/badge.svg?branch=master)](https://github.com/ankane/mailkick/actions)
12
13
 
13
14
  ## Installation
14
15
 
@@ -18,72 +19,91 @@ Add this line to your application’s Gemfile:
18
19
  gem 'mailkick'
19
20
  ```
20
21
 
21
- And run the generator. This creates a model to store opt-outs.
22
+ And run the generator. This creates a table to store subscriptions.
22
23
 
23
24
  ```sh
25
+ bundle install
24
26
  rails generate mailkick:install
25
27
  rails db:migrate
26
28
  ```
27
29
 
28
- ## How It Works
30
+ ## Getting Started
29
31
 
30
- Add an unsubscribe link to your emails.
32
+ Add `has_subscriptions` to your user model:
31
33
 
32
- #### Text
33
-
34
- ```erb
35
- Unsubscribe: <%= mailkick_unsubscribe_url %>
34
+ ```ruby
35
+ class User < ApplicationRecord
36
+ has_subscriptions
37
+ end
36
38
  ```
37
39
 
38
- #### HTML
40
+ Subscribe to a list
39
41
 
40
- ```erb
41
- <%= link_to "Unsubscribe", mailkick_unsubscribe_url %>
42
+ ```ruby
43
+ user.subscribe("sales")
42
44
  ```
43
45
 
44
- When a user unsubscribes, he or she is taken to a mobile-friendly page and given the option to resubscribe.
45
-
46
- To customize the view, run:
46
+ Unsubscribe from a list
47
47
 
48
- ```sh
49
- rails generate mailkick:views
48
+ ```ruby
49
+ user.unsubscribe("sales")
50
50
  ```
51
51
 
52
- which copies the view into `app/views/mailkick`.
53
-
54
- ## Sending Emails
52
+ Check if subscribed
55
53
 
56
- Before sending marketing emails, make sure the user has not opted out.
54
+ ```ruby
55
+ user.subscribed?("sales")
56
+ ```
57
57
 
58
- Add the following method to models with email addresses.
58
+ Get subscribers for a list (use this for sending emails)
59
59
 
60
60
  ```ruby
61
- class User < ApplicationRecord
62
- mailkick_user
63
- end
61
+ User.subscribed("sales")
64
62
  ```
65
63
 
66
- Get all users who have opted out
64
+ ## Unsubscribe Links
67
65
 
68
- ```ruby
69
- User.opted_out
66
+ Add an unsubscribe link to your emails. For HTML emails, use:
67
+
68
+ ```erb
69
+ <%= link_to "Unsubscribe", mailkick_unsubscribe_url(@user, "sales") %>
70
70
  ```
71
71
 
72
- And those who have not - send to these people
72
+ For text emails, use:
73
73
 
74
- ```ruby
75
- User.not_opted_out
74
+ ```erb
75
+ Unsubscribe: <%= mailkick_unsubscribe_url(@user, "sales") %>
76
76
  ```
77
77
 
78
- Check one user
78
+ When a user unsubscribes, they are taken to a mobile-friendly page and given the option to resubscribe. To customize the view, run:
79
79
 
80
- ```ruby
81
- user.opted_out?
80
+ ```sh
81
+ rails generate mailkick:views
82
82
  ```
83
83
 
84
+ which copies the view into `app/views/mailkick`.
85
+
84
86
  ## Bounces and Spam Reports
85
87
 
86
- Fetch bounces, spam reports, and unsubscribes from your email service.
88
+ Fetch bounces, spam reports, and unsubscribes from your email service. Create `config/initializers/mailkick.rb` with a method to handle opt outs.
89
+
90
+ ```ruby
91
+ Mailkick.process_opt_outs_method = lambda do |opt_outs|
92
+ emails = opt_outs.map { |v| v[:email] }
93
+ subscribers = User.includes(:mailkick_subscriptions).where(email: emails).index_by(&:email)
94
+
95
+ opt_outs.each do |opt_out|
96
+ subscriber = subscribers[opt_out[:email]]
97
+ next unless subscriber
98
+
99
+ subscriber.mailkick_subscriptions.each do |subscription|
100
+ subscription.destroy if subscription.updated_at < opt_out[:time]
101
+ end
102
+ end
103
+ end
104
+ ```
105
+
106
+ And run:
87
107
 
88
108
  ```ruby
89
109
  Mailkick.fetch_opt_outs
@@ -110,6 +130,8 @@ gem 'aws-sdk-sesv2'
110
130
 
111
131
  And [configure your AWS credentials](https://github.com/aws/aws-sdk-ruby#configuration). Requires `ses:ListSuppressedDestinations` permission.
112
132
 
133
+ If you started using Amazon SES [before November 25, 2019](https://docs.aws.amazon.com/ses/latest/DeveloperGuide/sending-email-suppression-list.html#sending-email-suppression-list-considerations), you have to manually [enable account-level suppression list feature](https://docs.aws.amazon.com/ses/latest/APIReference-V2/API_PutAccountSuppressionAttributes.html).
134
+
113
135
  #### Mailchimp
114
136
 
115
137
  Add the gem
@@ -171,76 +193,74 @@ Mailkick.services = [
171
193
  ]
172
194
  ```
173
195
 
174
- ## Multiple Lists
175
-
176
- You may want to split your emails into multiple categories, like sale emails and order reminders. Set the list in the url:
177
-
178
- ```ruby
179
- mailkick_unsubscribe_url(list: "order_reminders")
180
- ```
196
+ ## Reference
181
197
 
182
- Pass the `list` option to methods.
198
+ Access the subscription model directly
183
199
 
184
200
  ```ruby
185
- User.opted_out(list: "order_reminders")
186
- User.not_opted_out(list: "order_reminders")
187
- user.opted_out?(list: "order_reminders")
201
+ Mailkick::Subscription.all
188
202
  ```
189
203
 
190
- ### Opt-In Lists
204
+ ## Upgrading
191
205
 
192
- For opt-in lists, you’ll need to manage the subscribers yourself.
206
+ ### 1.0
193
207
 
194
- Check opt-ins against the opt-outs
208
+ Mailkick 1.0 stores subscriptions instead of opt-outs. To migrate:
195
209
 
196
- ```ruby
197
- User.where(send_me_sales: true).not_opted_out(list: "sales")
198
- ```
199
-
200
- Check one user
210
+ 1. Add a table to store subscriptions
201
211
 
202
- ```ruby
203
- user.send_me_sales && !user.opted_out?(list: "sales")
212
+ ```sh
213
+ rails generate mailkick:install
214
+ rails db:migrate
204
215
  ```
205
216
 
206
- ## Bonus
207
-
208
- More great gems for email
209
-
210
- - [Roadie](https://github.com/Mange/roadie) - inline CSS
211
- - [Letter Opener](https://github.com/ryanb/letter_opener) - preview email in development
212
-
213
- ## Reference
214
-
215
- Change how the user is determined
217
+ 2. Change the following methods in your code:
216
218
 
217
- ```ruby
218
- Mailkick.user_method = ->(email) { User.find_by(email: email) }
219
- ```
219
+ - `mailkick_user` to `has_subscriptions`
220
+ - `User.not_opted_out` to `User.subscribed(list)`
221
+ - `opt_in` to `subscribe(list)`
222
+ - `opt_out` to `unsubscribe(list)`
220
223
 
221
- Use a different email field
224
+ 3. Add a user and list to `mailkick_unsubscribe_url`
222
225
 
223
226
  ```ruby
224
- mailkick_user email_key: :email_address
227
+ mailkick_unsubscribe_url(user, list)
225
228
  ```
226
229
 
227
- Unsubscribe
230
+ 4. Migrate data for each of your lists
228
231
 
229
232
  ```ruby
230
- user.opt_out
233
+ opted_out_emails = Mailkick::Legacy.opted_out_emails(list: nil)
234
+ opted_out_users = Mailkick::Legacy.opted_out_users(list: nil)
235
+
236
+ User.find_in_batches do |users|
237
+ users.reject! { |u| opted_out_emails.include?(u.email) }
238
+ users.reject! { |u| opted_out_users.include?(u) }
239
+
240
+ now = Time.now
241
+ records =
242
+ users.map do |user|
243
+ {
244
+ subscriber_type: user.class.name,
245
+ subscriber_id: user.id,
246
+ list: "sales",
247
+ created_at: now,
248
+ updated_at: now
249
+ }
250
+ end
251
+
252
+ # use create! for Active Record < 6
253
+ Mailkick::Subscription.insert_all!(records)
254
+ end
231
255
  ```
232
256
 
233
- Resubscribe
257
+ 5. Drop the `mailkick_opt_outs` table
234
258
 
235
259
  ```ruby
236
- user.opt_in
260
+ drop_table :mailkick_opt_outs
237
261
  ```
238
262
 
239
- Access the opt-out model directly
240
-
241
- ```ruby
242
- Mailkick::OptOut.all
243
- ```
263
+ Also, if you use `Mailkick.fetch_opt_outs`, [add a method](#bounces-and-spam-reports) to handle opt outs.
244
264
 
245
265
  ## History
246
266
 
@@ -2,40 +2,50 @@ module Mailkick
2
2
  class SubscriptionsController < ActionController::Base
3
3
  protect_from_forgery with: :exception
4
4
 
5
- before_action :set_email
5
+ before_action :set_subscription
6
6
 
7
7
  def show
8
8
  end
9
9
 
10
10
  def unsubscribe
11
- Mailkick.opt_out(@options)
11
+ subscription.delete_all
12
+
13
+ Mailkick::Legacy.opt_out(legacy_options) if Mailkick::Legacy.opt_outs?
14
+
12
15
  redirect_to subscription_path(params[:id])
13
16
  end
14
17
 
15
18
  def subscribe
16
- Mailkick.opt_in(@options)
19
+ subscription.first_or_create!
20
+
21
+ Mailkick::Legacy.opt_in(legacy_options) if Mailkick::Legacy.opt_outs?
22
+
17
23
  redirect_to subscription_path(params[:id])
18
24
  end
19
25
 
20
26
  protected
21
27
 
22
- def set_email
23
- @email, user_id, user_type, @list = Mailkick.message_verifier.verify(params[:id])
24
- if user_type
25
- # on the unprobabilistic chance user_type is compromised, not much damage
26
- @user = user_type.constantize.find(user_id)
27
- end
28
- @options = {
29
- email: @email,
30
- user: @user,
31
- list: @list
32
- }
28
+ def set_subscription
29
+ @email, @subscriber_id, @subscriber_type, @list = Mailkick.message_verifier.verify(params[:id])
33
30
  rescue ActiveSupport::MessageVerifier::InvalidSignature
34
31
  render plain: "Subscription not found", status: :bad_request
35
32
  end
36
33
 
34
+ def subscription
35
+ Mailkick::Subscription.where(
36
+ subscriber_id: @subscriber_id,
37
+ subscriber_type: @subscriber_type,
38
+ list: @list
39
+ )
40
+ end
41
+
42
+ def subscribed?
43
+ subscription.exists?
44
+ end
45
+ helper_method :subscribed?
46
+
37
47
  def opted_out?
38
- Mailkick.opted_out?(@options)
48
+ !subscribed?
39
49
  end
40
50
  helper_method :opted_out?
41
51
 
@@ -48,5 +58,17 @@ module Mailkick
48
58
  unsubscribe_subscription_path(params[:id])
49
59
  end
50
60
  helper_method :unsubscribe_url
61
+
62
+ def legacy_options
63
+ if @subscriber_type
64
+ # on the unprobabilistic chance subscriber_type is compromised, not much damage
65
+ user = @subscriber_type.constantize.find(@subscriber_id)
66
+ end
67
+ {
68
+ email: @email,
69
+ user: user,
70
+ list: @list
71
+ }
72
+ end
51
73
  end
52
74
  end
@@ -0,0 +1,9 @@
1
+ module Mailkick
2
+ class Subscription < ActiveRecord::Base
3
+ self.table_name = "mailkick_subscriptions"
4
+
5
+ belongs_to :subscriber, polymorphic: true
6
+
7
+ validates :list, presence: true
8
+ end
9
+ end
@@ -24,7 +24,7 @@
24
24
  </head>
25
25
  <body>
26
26
  <div class="container">
27
- <% if opted_out? %>
27
+ <% if !subscribed? %>
28
28
  <p>You are unsubscribed.</p>
29
29
  <p><%= link_to "Resubscribe", subscribe_url %></p>
30
30
  <% else %>
@@ -7,7 +7,7 @@ module Mailkick
7
7
  source_root File.join(__dir__, "templates")
8
8
 
9
9
  def copy_migration
10
- migration_template "install.rb", "db/migrate/install_mailkick.rb", migration_version: migration_version
10
+ migration_template "install.rb", "db/migrate/create_mailkick_subscriptions.rb", migration_version: migration_version
11
11
  end
12
12
 
13
13
  def migration_version
@@ -1,14 +1,11 @@
1
1
  class <%= migration_class_name %> < ActiveRecord::Migration<%= migration_version %>
2
2
  def change
3
- create_table :mailkick_opt_outs do |t|
4
- t.string :email
5
- t.references :user, polymorphic: true
6
- t.boolean :active, null: false, default: true
7
- t.string :reason
3
+ create_table :mailkick_subscriptions do |t|
4
+ t.references :subscriber, polymorphic: true, index: false
8
5
  t.string :list
9
6
  t.timestamps
10
7
  end
11
8
 
12
- add_index :mailkick_opt_outs, :email
9
+ add_index :mailkick_subscriptions, [:subscriber_type, :subscriber_id, :list], unique: true, name: "index_mailkick_subscriptions_on_subscriber_and_list"
13
10
  end
14
11
  end
data/lib/mailkick.rb CHANGED
@@ -5,6 +5,7 @@ require "active_support"
5
5
  require "set"
6
6
 
7
7
  # modules
8
+ require "mailkick/legacy"
8
9
  require "mailkick/model"
9
10
  require "mailkick/service"
10
11
  require "mailkick/service/aws_ses"
@@ -21,10 +22,10 @@ require "mailkick/version"
21
22
  require "mailkick/engine" if defined?(Rails)
22
23
 
23
24
  module Mailkick
24
- mattr_accessor :services, :user_method, :secret_token, :mount
25
+ mattr_accessor :services, :secret_token, :mount, :process_opt_outs_method
25
26
  self.services = []
26
- self.user_method = ->(email) { User.where(email: email).first rescue nil }
27
27
  self.mount = true
28
+ self.process_opt_outs_method = -> { raise "process_opt_outs_method not defined" }
28
29
 
29
30
  def self.fetch_opt_outs
30
31
  services.each(&:fetch_opt_outs)
@@ -36,77 +37,15 @@ module Mailkick
36
37
  end
37
38
  end
38
39
 
39
- def self.opted_out?(options)
40
- opt_outs(options).any?
41
- end
42
-
43
- def self.opt_out(options)
44
- unless opted_out?(options)
45
- time = options[:time] || Time.now
46
- Mailkick::OptOut.create! do |o|
47
- o.email = options[:email]
48
- o.user = options[:user]
49
- o.reason = options[:reason] || "unsubscribe"
50
- o.list = options[:list]
51
- o.created_at = time
52
- o.updated_at = time
53
- end
54
- end
55
- true
56
- end
57
-
58
- def self.opt_in(options)
59
- opt_outs(options).each do |opt_out|
60
- opt_out.active = false
61
- opt_out.save!
62
- end
63
- true
64
- end
65
-
66
- def self.opt_outs(options = {})
67
- relation = Mailkick::OptOut.where(active: true)
68
-
69
- contact_relation = Mailkick::OptOut.none
70
- if (email = options[:email])
71
- contact_relation = contact_relation.or(Mailkick::OptOut.where(email: email))
72
- end
73
- if (user = options[:user])
74
- contact_relation = contact_relation.or(
75
- Mailkick::OptOut.where("user_id = ? AND user_type = ?", user.id, user.class.name)
76
- )
77
- end
78
- relation = relation.merge(contact_relation) if email || user
79
-
80
- relation =
81
- if options[:list]
82
- relation.where("list IS NULL OR list = ?", options[:list])
83
- else
84
- relation.where("list IS NULL")
85
- end
86
-
87
- relation
88
- end
89
-
90
- # TODO use keyword arguments
91
- def self.opted_out_emails(options = {})
92
- Set.new(opt_outs(options).where.not(email: nil).distinct.pluck(:email))
93
- end
94
-
95
- # TODO use keyword arguments
96
- # does not take into account emails
97
- def self.opted_out_users(options = {})
98
- Set.new(opt_outs(options).where.not(user_id: nil).map(&:user))
99
- end
100
-
101
40
  def self.message_verifier
102
41
  @message_verifier ||= ActiveSupport::MessageVerifier.new(Mailkick.secret_token)
103
42
  end
104
43
 
105
- def self.generate_token(email, user: nil, list: nil)
106
- raise ArgumentError, "Missing email" unless email
44
+ def self.generate_token(subscriber, list)
45
+ raise ArgumentError, "Missing subscriber" unless subscriber
46
+ raise ArgumentError, "Missing list" unless list.present?
107
47
 
108
- user ||= Mailkick.user_method.call(email) if Mailkick.user_method
109
- message_verifier.generate([email, user.try(:id), user.try(:class).try(:name), list])
48
+ message_verifier.generate([nil, subscriber.id, subscriber.class.name, list])
110
49
  end
111
50
  end
112
51
 
@@ -0,0 +1,70 @@
1
+ module Mailkick
2
+ module Legacy
3
+ # checks for table as long as it exists
4
+ def self.opt_outs?
5
+ unless defined?(@opt_outs) && @opt_outs == false
6
+ @opt_outs = ActiveRecord::Base.connection.table_exists?("mailkick_opt_outs")
7
+ end
8
+ @opt_outs
9
+ end
10
+
11
+ def self.opted_out?(options)
12
+ opt_outs(options).any?
13
+ end
14
+
15
+ def self.opt_out(options)
16
+ unless opted_out?(options)
17
+ time = options[:time] || Time.now
18
+ Mailkick::OptOut.create! do |o|
19
+ o.email = options[:email]
20
+ o.user = options[:user]
21
+ o.reason = options[:reason] || "unsubscribe"
22
+ o.list = options[:list]
23
+ o.created_at = time
24
+ o.updated_at = time
25
+ end
26
+ end
27
+ true
28
+ end
29
+
30
+ def self.opt_in(options)
31
+ opt_outs(options).each do |opt_out|
32
+ opt_out.active = false
33
+ opt_out.save!
34
+ end
35
+ true
36
+ end
37
+
38
+ def self.opt_outs(options = {})
39
+ relation = Mailkick::OptOut.where(active: true)
40
+
41
+ contact_relation = Mailkick::OptOut.none
42
+ if (email = options[:email])
43
+ contact_relation = contact_relation.or(Mailkick::OptOut.where(email: email))
44
+ end
45
+ if (user = options[:user])
46
+ contact_relation = contact_relation.or(
47
+ Mailkick::OptOut.where("user_id = ? AND user_type = ?", user.id, user.class.name)
48
+ )
49
+ end
50
+ relation = relation.merge(contact_relation) if email || user
51
+
52
+ relation =
53
+ if options[:list]
54
+ relation.where("list IS NULL OR list = ?", options[:list])
55
+ else
56
+ relation.where("list IS NULL")
57
+ end
58
+
59
+ relation
60
+ end
61
+
62
+ def self.opted_out_emails(options = {})
63
+ Set.new(opt_outs(options).where.not(email: nil).distinct.pluck(:email))
64
+ end
65
+
66
+ def self.opted_out_users(options = {})
67
+ Set.new(opt_outs(options).where.not(user_id: nil).map(&:user))
68
+ end
69
+ end
70
+ end
@@ -1,33 +1,22 @@
1
1
  module Mailkick
2
2
  module Model
3
- def mailkick_user(opts = {})
4
- email_key = opts[:email_key] || :email
3
+ def has_subscriptions
5
4
  class_eval do
6
- scope :opted_out, lambda { |options = {}|
7
- binds = [name, true]
8
- if options[:list]
9
- query = "(mailkick_opt_outs.list IS NULL OR mailkick_opt_outs.list = ?)"
10
- binds << options[:list]
11
- else
12
- query = "mailkick_opt_outs.list IS NULL"
13
- end
14
- where("#{options[:not] ? 'NOT ' : ''}EXISTS(SELECT * FROM mailkick_opt_outs WHERE (#{table_name}.#{email_key} = mailkick_opt_outs.email OR (#{table_name}.#{primary_key} = mailkick_opt_outs.user_id AND mailkick_opt_outs.user_type = ?)) AND mailkick_opt_outs.active = ? AND #{query})", *binds)
15
- }
5
+ has_many :mailkick_subscriptions, class_name: "Mailkick::Subscription", as: :subscriber
6
+ scope :subscribed, -> (list) { joins(:mailkick_subscriptions).where(mailkick_subscriptions: {list: list}) }
16
7
 
17
- scope :not_opted_out, lambda { |options = {}|
18
- opted_out(options.merge(not: true))
19
- }
20
-
21
- define_method :opted_out? do |options = {}|
22
- Mailkick.opted_out?({email: send(email_key), user: self}.merge(options))
8
+ def subscribe(list)
9
+ mailkick_subscriptions.where(list: list).first_or_create!
10
+ nil
23
11
  end
24
12
 
25
- define_method :opt_out do |options = {}|
26
- Mailkick.opt_out({email: send(email_key), user: self}.merge(options))
13
+ def unsubscribe(list)
14
+ mailkick_subscriptions.where(list: list).delete_all
15
+ nil
27
16
  end
28
17
 
29
- define_method :opt_in do |options = {}|
30
- Mailkick.opt_in({email: send(email_key), user: self}.merge(options))
18
+ def subscribed?(list)
19
+ mailkick_subscriptions.where(list: list).exists?
31
20
  end
32
21
  end
33
22
  end
@@ -1,22 +1,7 @@
1
1
  module Mailkick
2
2
  class Service
3
3
  def fetch_opt_outs
4
- opt_outs.each do |api_data|
5
- email = api_data[:email]
6
- time = api_data[:time]
7
-
8
- opt_out = Mailkick::OptOut.where(email: email).order("updated_at desc").first
9
- if !opt_out || (time > opt_out.updated_at && !opt_out.active)
10
- Mailkick.opt_out(
11
- email: email,
12
- user: Mailkick.user_method ? Mailkick.user_method.call(email) : nil,
13
- reason: api_data[:reason],
14
- time: time
15
- )
16
- end
17
- end
18
-
19
- true
4
+ Mailkick.process_opt_outs_method.call(opt_outs)
20
5
  end
21
6
  end
22
7
  end
@@ -1,15 +1,8 @@
1
1
  module Mailkick
2
2
  module UrlHelper
3
- def mailkick_unsubscribe_url(email: nil, user: nil, list: nil, **options)
4
- email ||= controller.try(:message).try(:to).try(:first)
5
-
6
- Mailkick::Engine.routes.url_helpers.url_for(
7
- (ActionMailer::Base.default_url_options || {}).merge(options).merge(
8
- controller: "mailkick/subscriptions",
9
- action: "unsubscribe",
10
- id: Mailkick.generate_token(email, user: user, list: list)
11
- )
12
- )
3
+ def mailkick_unsubscribe_url(subscriber, list, **options)
4
+ token = Mailkick.generate_token(subscriber, list)
5
+ mailkick.unsubscribe_subscription_url(token, **options)
13
6
  end
14
7
  end
15
8
  end
@@ -1,3 +1,3 @@
1
1
  module Mailkick
2
- VERSION = "0.4.3"
2
+ VERSION = "1.0.0"
3
3
  end
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.4.3
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-11-01 00:00:00.000000000 Z
11
+ date: 2021-06-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -16,170 +16,16 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '5'
19
+ version: '5.2'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '5'
27
- - !ruby/object:Gem::Dependency
28
- name: bundler
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
- - !ruby/object:Gem::Dependency
42
- name: gibbon
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '2'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '2'
55
- - !ruby/object:Gem::Dependency
56
- name: mailgun-ruby
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: mandrill-api
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: minitest
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
- - !ruby/object:Gem::Dependency
98
- name: rake
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
- - !ruby/object:Gem::Dependency
112
- name: sendgrid_toolkit
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - ">="
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - ">="
123
- - !ruby/object:Gem::Version
124
- version: '0'
125
- - !ruby/object:Gem::Dependency
126
- name: postmark
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - ">="
130
- - !ruby/object:Gem::Version
131
- version: '0'
132
- type: :development
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - ">="
137
- - !ruby/object:Gem::Version
138
- version: '0'
139
- - !ruby/object:Gem::Dependency
140
- name: combustion
141
- requirement: !ruby/object:Gem::Requirement
142
- requirements:
143
- - - ">="
144
- - !ruby/object:Gem::Version
145
- version: '0'
146
- type: :development
147
- prerelease: false
148
- version_requirements: !ruby/object:Gem::Requirement
149
- requirements:
150
- - - ">="
151
- - !ruby/object:Gem::Version
152
- version: '0'
153
- - !ruby/object:Gem::Dependency
154
- name: rails
155
- requirement: !ruby/object:Gem::Requirement
156
- requirements:
157
- - - ">="
158
- - !ruby/object:Gem::Version
159
- version: '0'
160
- type: :development
161
- prerelease: false
162
- version_requirements: !ruby/object:Gem::Requirement
163
- requirements:
164
- - - ">="
165
- - !ruby/object:Gem::Version
166
- version: '0'
167
- - !ruby/object:Gem::Dependency
168
- name: sqlite3
169
- requirement: !ruby/object:Gem::Requirement
170
- requirements:
171
- - - ">="
172
- - !ruby/object:Gem::Version
173
- version: '0'
174
- type: :development
175
- prerelease: false
176
- version_requirements: !ruby/object:Gem::Requirement
177
- requirements:
178
- - - ">="
179
- - !ruby/object:Gem::Version
180
- version: '0'
26
+ version: '5.2'
181
27
  description:
182
- email: andrew@chartkick.com
28
+ email: andrew@ankane.org
183
29
  executables: []
184
30
  extensions: []
185
31
  extra_rdoc_files: []
@@ -189,6 +35,7 @@ files:
189
35
  - README.md
190
36
  - app/controllers/mailkick/subscriptions_controller.rb
191
37
  - app/models/mailkick/opt_out.rb
38
+ - app/models/mailkick/subscription.rb
192
39
  - app/views/mailkick/subscriptions/show.html.erb
193
40
  - config/routes.rb
194
41
  - lib/generators/mailkick/install_generator.rb
@@ -196,6 +43,7 @@ files:
196
43
  - lib/generators/mailkick/views_generator.rb
197
44
  - lib/mailkick.rb
198
45
  - lib/mailkick/engine.rb
46
+ - lib/mailkick/legacy.rb
199
47
  - lib/mailkick/model.rb
200
48
  - lib/mailkick/service.rb
201
49
  - lib/mailkick/service/aws_ses.rb
@@ -219,15 +67,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
219
67
  requirements:
220
68
  - - ">="
221
69
  - !ruby/object:Gem::Version
222
- version: '2.4'
70
+ version: '2.6'
223
71
  required_rubygems_version: !ruby/object:Gem::Requirement
224
72
  requirements:
225
73
  - - ">="
226
74
  - !ruby/object:Gem::Version
227
75
  version: '0'
228
76
  requirements: []
229
- rubygems_version: 3.1.4
77
+ rubygems_version: 3.2.3
230
78
  signing_key:
231
79
  specification_version: 4
232
- summary: Email unsubscribes for Rails
80
+ summary: Email subscriptions for Rails
233
81
  test_files: []